Merge tag 'driver-core-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 29 Apr 2013 18:31:50 +0000 (11:31 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 29 Apr 2013 18:31:50 +0000 (11:31 -0700)
Pull driver core update from Greg Kroah-Hartman:
 "Here's the merge request for the driver core tree for 3.10-rc1

  It's pretty small, just a number of driver core and sysfs updates and
  fixes, all of which have been in linux-next for a while now.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"
Fixed conflict in kernel/rtmutex-tester.c, the locking tree had a better
fix for the same sysfs file mode problem.

* tag 'driver-core-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core:
  PM / Runtime: Idle devices asynchronously after probe|release
  driver core: handle user namespaces properly with the uid/gid devtmpfs change
  driver core: devtmpfs: fix compile failure with CONFIG_UIDGID_STRICT_TYPE_CHECKS
  devtmpfs: add base.h include
  driver core: add uid and gid to devtmpfs
  sysfs: check if one entry has been removed before freeing
  sysfs: fix crash_notes_size build warning
  sysfs: fix use after free in case of concurrent read/write and readdir
  rtmutex-tester: fix mode of sysfs files
  Documentation: Add ABI entry for crash_notes and crash_notes_size
  sysfs: Add crash_notes_size to export percpu note size
  driver core: platform_device.h: fix checkpatch errors and warnings
  driver core: platform.c: fix checkpatch errors and warnings
  driver core: warn that platform_driver_probe can not use deferred probing
  sysfs: use atomic_inc_unless_negative in sysfs_get_active
  base: core: WARN() about bogus permissions on device attributes
  device: separate all subsys mutexes

689 files changed:
Documentation/ABI/testing/sysfs-bus-mei [new file with mode: 0644]
Documentation/devicetree/bindings/arm/msm/ssbi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio.txt
Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
Documentation/devicetree/bindings/video/via,vt8500-fb.txt
Documentation/devicetree/bindings/video/wm,wm8505-fb.txt
Documentation/hwmon/adt7410
Documentation/hwmon/lm25066
Documentation/hwmon/lm95234 [new file with mode: 0644]
Documentation/hwmon/ltc2978
Documentation/hwmon/nct6775 [new file with mode: 0644]
Documentation/hwmon/sht15
Documentation/hwmon/tmp401
Documentation/hwmon/zl6100
Documentation/ia64/err_inject.txt
Documentation/kdump/kdump.txt
Documentation/kernel-parameters.txt
Documentation/misc-devices/mei/mei-client-bus.txt [new file with mode: 0644]
Documentation/pinctrl.txt
Documentation/s390/s390dbf.txt
MAINTAINERS
Makefile
arch/arm/boot/dts/msm8660-surf.dts
arch/arm/boot/dts/msm8960-cdp.dts
arch/arm/boot/dts/spear1310.dtsi
arch/arm/boot/dts/spear1340.dtsi
arch/arm/boot/dts/spear310.dtsi
arch/arm/boot/dts/spear320.dtsi
arch/arm/boot/dts/vt8500-bv07.dts
arch/arm/boot/dts/vt8500.dtsi
arch/arm/boot/dts/wm8505-ref.dts
arch/arm/boot/dts/wm8505.dtsi
arch/arm/boot/dts/wm8650-mid.dts
arch/arm/boot/dts/wm8650.dtsi
arch/arm/boot/dts/wm8850-w70v2.dts
arch/arm/boot/dts/wm8850.dtsi
arch/arm/include/asm/glue-cache.h
arch/arm/include/asm/hardware/iop3xx.h
arch/arm/include/asm/pgtable-3level.h
arch/arm/include/asm/tlbflush.h
arch/arm/kernel/hw_breakpoint.c
arch/arm/kernel/perf_event.c
arch/arm/kernel/sched_clock.c
arch/arm/kernel/setup.c
arch/arm/kernel/tcm.c
arch/arm/kvm/arm.c
arch/arm/kvm/coproc.c
arch/arm/mach-highbank/hotplug.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mm/Kconfig
arch/arm/mm/Makefile
arch/arm/mm/cache-feroceon-l2.c
arch/arm/mm/cache-v3.S [deleted file]
arch/arm/mm/cache-v4.S
arch/arm/mm/mmu.c
arch/arm/mm/proc-arm740.S
arch/arm/mm/proc-arm920.S
arch/arm/mm/proc-arm926.S
arch/arm/mm/proc-mohawk.S
arch/arm/mm/proc-sa1100.S
arch/arm/mm/proc-syms.c
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-xsc3.S
arch/arm/mm/proc-xscale.S
arch/arm/mm/tcm.h [moved from arch/arm/kernel/tcm.h with 100% similarity]
arch/arm/plat-samsung/include/plat/fb.h
arch/avr32/include/asm/io.h
arch/ia64/Kconfig
arch/ia64/include/asm/futex.h
arch/ia64/include/asm/mca.h
arch/ia64/include/asm/numa.h
arch/ia64/kernel/fsys.S
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/irq.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/mca_drv.c
arch/ia64/kvm/vtlb.c
arch/ia64/mm/ioremap.c
arch/ia64/mm/numa.c
arch/ia64/pci/pci.c
arch/ia64/sn/kernel/tiocx.c
arch/mips/include/asm/page.h
arch/mips/pci/pci.c
arch/parisc/Makefile
arch/parisc/include/asm/cacheflush.h
arch/parisc/include/asm/pgtable.h
arch/parisc/include/asm/uaccess.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/parisc_ksyms.c
arch/parisc/lib/Makefile
arch/parisc/lib/ucmpdi2.c [new file with mode: 0644]
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/process.c
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_64.c
arch/powerpc/kernel/tm.S
arch/powerpc/kvm/e500.h
arch/powerpc/kvm/e500_mmu_host.c
arch/powerpc/kvm/e500mc.c
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/hypfs/hypfs_dbfs.c
arch/s390/include/asm/bitops.h
arch/s390/include/asm/ccwdev.h
arch/s390/include/asm/cio.h
arch/s390/include/asm/compat.h
arch/s390/include/asm/elf.h
arch/s390/include/asm/io.h
arch/s390/include/asm/pci.h
arch/s390/include/asm/pci_debug.h
arch/s390/include/asm/pci_insn.h
arch/s390/include/asm/pci_io.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/ptrace.h
arch/s390/include/asm/syscall.h
arch/s390/include/asm/thread_info.h
arch/s390/include/uapi/asm/ptrace.h
arch/s390/include/uapi/asm/statfs.h
arch/s390/kernel/Makefile
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/compat_signal.c
arch/s390/kernel/dis.c
arch/s390/kernel/dumpstack.c [new file with mode: 0644]
arch/s390/kernel/entry.S
arch/s390/kernel/entry.h
arch/s390/kernel/entry64.S
arch/s390/kernel/machine_kexec.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/suspend.c
arch/s390/kernel/swsusp_asm64.S
arch/s390/kernel/traps.c
arch/s390/kvm/trace.h
arch/s390/mm/cmm.c
arch/s390/mm/fault.c
arch/s390/mm/init.c
arch/s390/mm/pageattr.c
arch/s390/mm/pgtable.c
arch/s390/net/bpf_jit_comp.c
arch/s390/pci/Makefile
arch/s390/pci/pci.c
arch/s390/pci/pci_clp.c
arch/s390/pci/pci_debug.c
arch/s390/pci/pci_dma.c
arch/s390/pci/pci_insn.c [new file with mode: 0644]
arch/s390/pci/pci_msi.c
arch/sparc/include/asm/Kbuild
arch/sparc/include/asm/cputime.h [deleted file]
arch/sparc/include/asm/emergency-restart.h [deleted file]
arch/sparc/include/asm/mutex.h [deleted file]
arch/sparc/include/asm/pgtable_64.h
arch/sparc/include/asm/serial.h [deleted file]
arch/sparc/include/asm/smp_32.h
arch/sparc/include/asm/switch_to_64.h
arch/sparc/include/asm/tlbflush_64.h
arch/sparc/include/uapi/asm/Kbuild
arch/sparc/include/uapi/asm/types.h [deleted file]
arch/sparc/kernel/smp_64.c
arch/sparc/lib/bitext.c
arch/sparc/mm/iommu.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/tlb.c
arch/sparc/mm/tsb.c
arch/sparc/mm/ultra.S
arch/x86/Kconfig
arch/x86/boot/compressed/eboot.c
arch/x86/include/asm/efi.h
arch/x86/include/uapi/asm/bootparam.h
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/microcode_core_early.c
arch/x86/kernel/setup.c
arch/x86/pci/common.c
arch/x86/pci/xen.c
arch/x86/platform/efi/efi.c
arch/x86/xen/enlighten.c
arch/x86/xen/smp.c
arch/x86/xen/spinlock.c
arch/x86/xen/time.c
block/blk-core.c
crypto/algif_hash.c
crypto/algif_skcipher.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/pci_root.c
drivers/acpi/pci_slot.c
drivers/acpi/scan.c
drivers/ata/ahci.c
drivers/ata/pata_pcmcia.c
drivers/block/rbd.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/dtl1_cs.c
drivers/char/applicom.c
drivers/char/hpet.c
drivers/char/hw_random/mxc-rnga.c
drivers/char/hw_random/tx4939-rng.c
drivers/char/tile-srom.c
drivers/dma/at_hdmac.c
drivers/eisa/eisa-bus.c
drivers/eisa/pci_eisa.c
drivers/extcon/extcon-arizona.c
drivers/extcon/extcon-max77693.c
drivers/extcon/extcon-max8997.c
drivers/firmware/Kconfig
drivers/firmware/efivars.c
drivers/gpio/gpio-pl061.c
drivers/gpio/gpio-pxa.c
drivers/gpio/gpiolib-of.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/tilcdc/Kconfig
drivers/gpu/drm/tilcdc/tilcdc_panel.c
drivers/hv/Makefile
drivers/hv/channel_mgmt.c
drivers/hv/hv.c
drivers/hv/hv_balloon.c
drivers/hv/hv_snapshot.c [new file with mode: 0644]
drivers/hv/hv_util.c
drivers/hv/ring_buffer.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/abituguru.c
drivers/hwmon/abituguru3.c
drivers/hwmon/ad7314.c
drivers/hwmon/adm1021.c
drivers/hwmon/adm1026.c
drivers/hwmon/adm1029.c
drivers/hwmon/adm9240.c
drivers/hwmon/ads7871.c
drivers/hwmon/adt7310.c [new file with mode: 0644]
drivers/hwmon/adt7410.c
drivers/hwmon/adt7411.c
drivers/hwmon/adt7x10.c [new file with mode: 0644]
drivers/hwmon/adt7x10.h [new file with mode: 0644]
drivers/hwmon/applesmc.c
drivers/hwmon/asb100.c
drivers/hwmon/asc7621.c
drivers/hwmon/coretemp.c
drivers/hwmon/da9052-hwmon.c
drivers/hwmon/da9055-hwmon.c
drivers/hwmon/dme1737.c
drivers/hwmon/f71805f.c
drivers/hwmon/fam15h_power.c
drivers/hwmon/fschmd.c
drivers/hwmon/gl518sm.c
drivers/hwmon/gpio-fan.c
drivers/hwmon/ibmaem.c
drivers/hwmon/ibmpex.c
drivers/hwmon/ina2xx.c
drivers/hwmon/it87.c
drivers/hwmon/k8temp.c
drivers/hwmon/lm78.c
drivers/hwmon/lm80.c
drivers/hwmon/lm85.c
drivers/hwmon/lm93.c
drivers/hwmon/lm95234.c [new file with mode: 0644]
drivers/hwmon/ltc4151.c
drivers/hwmon/ltc4215.c
drivers/hwmon/ltc4245.c
drivers/hwmon/ltc4261.c
drivers/hwmon/max6697.c
drivers/hwmon/mc13783-adc.c
drivers/hwmon/nct6775.c [new file with mode: 0644]
drivers/hwmon/ntc_thermistor.c
drivers/hwmon/pc87360.c
drivers/hwmon/pc87427.c
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/lm25066.c
drivers/hwmon/pmbus/ltc2978.c
drivers/hwmon/s3c-hwmon.c
drivers/hwmon/sch56xx-common.c
drivers/hwmon/sis5595.c
drivers/hwmon/thmc50.c
drivers/hwmon/tmp102.c
drivers/hwmon/tmp401.c
drivers/hwmon/tmp421.c
drivers/hwmon/via686a.c
drivers/hwmon/vt1211.c
drivers/hwmon/vt8231.c
drivers/hwmon/w83627ehf.c
drivers/hwmon/w83781d.c
drivers/hwmon/w83791d.c
drivers/hwmon/w83792d.c
drivers/hwmon/w83793.c
drivers/hwmon/w83795.c
drivers/idle/intel_idle.c
drivers/input/tablet/wacom_wac.c
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_types.h
drivers/ipack/carriers/tpci200.c
drivers/ipack/ipack.c
drivers/irqchip/irq-gic.c
drivers/isdn/hardware/avm/avm_cs.c
drivers/isdn/hisax/avma1_cs.c
drivers/isdn/hisax/elsa_cs.c
drivers/isdn/hisax/sedlbauer_cs.c
drivers/isdn/hisax/teles_cs.c
drivers/md/dm.c
drivers/md/raid5.c
drivers/media/dvb-frontends/mb86a20s.c
drivers/media/pci/cx25821/cx25821-video.c
drivers/memory/emif.c
drivers/memory/tegra30-mc.c
drivers/mfd/Kconfig
drivers/mfd/pm8921-core.c
drivers/mfd/wm5102-tables.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/apds9802als.c
drivers/misc/apds990x.c
drivers/misc/arm-charlcd.c
drivers/misc/atmel_pwm.c
drivers/misc/bh1770glc.c
drivers/misc/bh1780gli.c
drivers/misc/cs5535-mfgpt.c
drivers/misc/dummy-irq.c [new file with mode: 0644]
drivers/misc/eeprom/at25.c
drivers/misc/eeprom/eeprom_93xx46.c
drivers/misc/ep93xx_pwm.c
drivers/misc/fsa9480.c
drivers/misc/isl29003.c
drivers/misc/lattice-ecp3-config.c
drivers/misc/mei/Kconfig
drivers/misc/mei/Makefile
drivers/misc/mei/amthif.c
drivers/misc/mei/bus.c [new file with mode: 0644]
drivers/misc/mei/client.c
drivers/misc/mei/client.h
drivers/misc/mei/debugfs.c [new file with mode: 0644]
drivers/misc/mei/hbm.c
drivers/misc/mei/hbm.h
drivers/misc/mei/hw-me.c
drivers/misc/mei/hw-me.h
drivers/misc/mei/init.c
drivers/misc/mei/interrupt.c
drivers/misc/mei/main.c
drivers/misc/mei/mei_dev.h
drivers/misc/mei/nfc.c [new file with mode: 0644]
drivers/misc/mei/pci-me.c
drivers/misc/mei/wd.c
drivers/misc/tsl2550.c
drivers/mmc/host/sdricoh_cs.c
drivers/mtd/mtdchar.c
drivers/net/arcnet/com20020_cs.c
drivers/net/bonding/bond_main.c
drivers/net/can/mcp251x.c
drivers/net/can/sja1000/ems_pcmcia.c
drivers/net/can/sja1000/peak_pcmcia.c
drivers/net/can/sja1000/sja1000_of_platform.c
drivers/net/can/softing/softing_cs.c
drivers/net/ethernet/3com/3c574_cs.c
drivers/net/ethernet/3com/3c589_cs.c
drivers/net/ethernet/8390/ax88796.c
drivers/net/ethernet/8390/axnet_cs.c
drivers/net/ethernet/8390/pcnet_cs.c
drivers/net/ethernet/amd/nmclan_cs.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec.c
drivers/net/ethernet/fujitsu/fmvj18x_cs.c
drivers/net/ethernet/intel/igb/igb.h
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/marvell/Kconfig
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
drivers/net/ethernet/qlogic/qlge/qlge.h
drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c
drivers/net/ethernet/qlogic/qlge/qlge_main.c
drivers/net/ethernet/smsc/smc91c92_cs.c
drivers/net/ethernet/stmicro/stmmac/mmc_core.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/xircom/xirc2ps_cs.c
drivers/net/tun.c
drivers/net/usb/cdc_mbim.c
drivers/net/usb/qmi_wwan.c
drivers/net/wireless/airo_cs.c
drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/atmel_cs.c
drivers/net/wireless/b43/pcmcia.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/orinoco/orinoco_cs.c
drivers/net/wireless/orinoco/spectrum_cs.c
drivers/net/wireless/wl3501_cs.c
drivers/parport/parport_amiga.c
drivers/parport/parport_cs.c
drivers/parport/parport_gsc.c
drivers/parport/parport_sunbpp.c
drivers/parport/procfs.c
drivers/pci/bus.c
drivers/pci/hotplug/Kconfig
drivers/pci/hotplug/acpiphp.h
drivers/pci/hotplug/acpiphp_core.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/cpci_hotplug.h
drivers/pci/hotplug/cpqphp.h
drivers/pci/hotplug/cpqphp_nvram.h
drivers/pci/hotplug/ibmphp.h
drivers/pci/hotplug/pci_hotplug_core.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_acpi.c
drivers/pci/hotplug/rpadlpar.h
drivers/pci/hotplug/rpaphp.h
drivers/pci/hotplug/s390_pci_hpc.c
drivers/pci/hotplug/shpchp.h
drivers/pci/hotplug/shpchp_sysfs.c
drivers/pci/msi.c
drivers/pci/msi.h [deleted file]
drivers/pci/pci-acpi.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/Kconfig
drivers/pci/pcie/aer/aer_inject.c
drivers/pci/pcie/aer/aerdrv.h
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/pme.c
drivers/pci/pcie/portdrv.h
drivers/pci/pcie/portdrv_acpi.c
drivers/pci/pcie/portdrv_pci.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/remove.c
drivers/pci/setup-bus.c
drivers/pci/setup-res.c
drivers/pci/slot.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/core.c
drivers/pinctrl/core.h
drivers/pinctrl/devicetree.c
drivers/pinctrl/mvebu/pinctrl-mvebu.c
drivers/pinctrl/pinconf-generic.c
drivers/pinctrl/pinconf.c
drivers/pinctrl/pinconf.h
drivers/pinctrl/pinctrl-ab8500.c
drivers/pinctrl/pinctrl-ab8505.c
drivers/pinctrl/pinctrl-ab8540.c
drivers/pinctrl/pinctrl-ab9540.c
drivers/pinctrl/pinctrl-abx500.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/pinctrl-bcm2835.c
drivers/pinctrl/pinctrl-coh901.c
drivers/pinctrl/pinctrl-exynos.c
drivers/pinctrl/pinctrl-exynos.h
drivers/pinctrl/pinctrl-exynos5440.c
drivers/pinctrl/pinctrl-falcon.c
drivers/pinctrl/pinctrl-imx.c
drivers/pinctrl/pinctrl-lantiq.c
drivers/pinctrl/pinctrl-mmp2.c [deleted file]
drivers/pinctrl/pinctrl-mxs.c
drivers/pinctrl/pinctrl-nomadik-db8500.c
drivers/pinctrl/pinctrl-nomadik-stn8815.c
drivers/pinctrl/pinctrl-nomadik.c
drivers/pinctrl/pinctrl-pxa168.c [deleted file]
drivers/pinctrl/pinctrl-pxa3xx.c [deleted file]
drivers/pinctrl/pinctrl-pxa3xx.h [deleted file]
drivers/pinctrl/pinctrl-pxa910.c [deleted file]
drivers/pinctrl/pinctrl-s3c64xx.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-samsung.c
drivers/pinctrl/pinctrl-samsung.h
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/pinctrl-sirf.c
drivers/pinctrl/pinctrl-sunxi.c
drivers/pinctrl/pinctrl-tegra.c
drivers/pinctrl/pinctrl-u300.c
drivers/pinctrl/pinctrl-xway.c
drivers/pinctrl/pinmux.c
drivers/pinctrl/spear/pinctrl-spear.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/block/scm_blk.c
drivers/s390/block/scm_blk_cluster.c
drivers/s390/char/con3215.c
drivers/s390/char/monreader.c
drivers/s390/char/raw3270.c
drivers/s390/char/sclp_cmd.c
drivers/s390/char/zcore.c
drivers/s390/cio/chp.c
drivers/s390/cio/chp.h
drivers/s390/cio/chsc.c
drivers/s390/cio/cio.c
drivers/s390/cio/cio.h
drivers/s390/cio/css.c
drivers/s390/cio/css.h
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_ops.c
drivers/s390/cio/idset.c
drivers/sbus/char/bbc_i2c.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/mvsas/mv_init.c
drivers/scsi/mvumi.c
drivers/scsi/mvumi.h
drivers/ssb/driver_chipcommon_pmu.c
drivers/ssbi/Kconfig [new file with mode: 0644]
drivers/ssbi/Makefile [new file with mode: 0644]
drivers/ssbi/ssbi.c [new file with mode: 0644]
drivers/tty/serial/8250/serial_cs.c
drivers/tty/tty_io.c
drivers/uio/uio.c
drivers/usb/host/sl811_cs.c
drivers/vfio/pci/vfio_pci.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/amifb.c
drivers/video/atmel_lcdfb.c
drivers/video/auo_k1900fb.c
drivers/video/auo_k1901fb.c
drivers/video/auo_k190x.c
drivers/video/controlfb.c
drivers/video/exynos/exynos_mipi_dsi.c
drivers/video/exynos/exynos_mipi_dsi_common.c
drivers/video/exynos/exynos_mipi_dsi_lowlevel.c
drivers/video/fb-puv3.c
drivers/video/fbmem.c
drivers/video/fbmon.c
drivers/video/fsl-diu-fb.c
drivers/video/gbefb.c
drivers/video/mmp/core.c
drivers/video/of_display_timing.c
drivers/video/of_videomode.c
drivers/video/omap/Kconfig
drivers/video/omap2/omapfb/omapfb-main.c
drivers/video/omap2/vrfb.c
drivers/video/ps3fb.c
drivers/video/s3c-fb.c
drivers/video/sa1100fb.c
drivers/video/sgivwfb.c
drivers/video/sh_mipi_dsi.c
drivers/video/sh_mobile_hdmi.c
drivers/video/smscufx.c
drivers/video/udlfb.c
drivers/video/vermilion/vermilion.c
drivers/video/vfb.c
drivers/video/videomode.c
drivers/video/vt8500lcdfb.c
drivers/video/wm8505fb.c
drivers/video/wmt_ge_rops.h
drivers/w1/masters/mxc_w1.c
drivers/w1/slaves/Kconfig
drivers/w1/slaves/w1_ds2408.c
drivers/xen/events.c
drivers/xen/xen-acpi-processor.c
fs/aio.c
fs/binfmt_elf.c
fs/bio.c
fs/hfsplus/extents.c
fs/hugetlbfs/inode.c
fs/proc/array.c
include/linux/acpi.h
include/linux/blktrace_api.h
include/linux/efi.h
include/linux/hyperv.h
include/linux/ipack.h
include/linux/kexec.h
include/linux/mei_cl_bus.h [new file with mode: 0644]
include/linux/mfd/arizona/core.h
include/linux/mfd/arizona/pdata.h
include/linux/mfd/arizona/registers.h
include/linux/mm.h
include/linux/mod_devicetable.h
include/linux/msi.h
include/linux/mutex.h
include/linux/netfilter/ipset/ip_set_ahash.h
include/linux/pci-acpi.h
include/linux/pci-aspm.h
include/linux/pci-ats.h
include/linux/pci.h
include/linux/pci_hotplug.h
include/linux/pci_ids.h
include/linux/pcieport_if.h
include/linux/pinctrl/pinconf.h
include/linux/pinctrl/pinctrl.h
include/linux/platform_data/emif_plat.h
include/linux/platform_data/ntc_thermistor.h
include/linux/platform_data/video-vt8500lcdfb.h [deleted file]
include/linux/platform_data/video_s3c.h [new file with mode: 0644]
include/linux/sched.h
include/linux/ssb/ssb_driver_chipcommon.h
include/linux/ssbi.h [new file with mode: 0644]
include/linux/swiotlb.h
include/linux/ucs2_string.h [new file with mode: 0644]
include/net/addrconf.h
include/net/irda/irlmp.h
include/net/scm.h
include/pcmcia/ds.h
include/trace/events/block.h
include/trace/events/sched.h
include/uapi/linux/connector.h
include/uapi/linux/fuse.h
include/uapi/linux/pci_regs.h
include/video/auo_k190xfb.h
include/video/display_timing.h
include/video/videomode.h
include/xen/events.h
kernel/.gitignore
kernel/events/core.c
kernel/hrtimer.c
kernel/kexec.c
kernel/kprobes.c
kernel/kthread.c
kernel/lockdep.c
kernel/mutex.c
kernel/rtmutex-tester.c
kernel/sched/core.c
kernel/sched/features.h
kernel/signal.c
kernel/smpboot.c
kernel/trace/blktrace.c
kernel/user_namespace.c
lib/Kconfig
lib/Makefile
lib/swiotlb.c
lib/ucs2_string.c [new file with mode: 0644]
mm/hugetlb.c
mm/memory.c
mm/nommu.c
mm/page_alloc.c
mm/vmscan.c
net/802/mrp.c
net/batman-adv/main.c
net/batman-adv/main.h
net/batman-adv/routing.c
net/batman-adv/translation-table.c
net/batman-adv/vis.c
net/bridge/br_if.c
net/bridge/br_private.h
net/bridge/br_stp_if.c
net/core/dev.c
net/ipv4/esp4.c
net/ipv4/ip_fragment.c
net/ipv4/netfilter/ipt_rpfilter.c
net/ipv4/syncookies.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv6/addrconf.c
net/ipv6/addrconf_core.c
net/ipv6/netfilter/ip6t_rpfilter.c
net/ipv6/reassembly.c
net/irda/iriap.c
net/irda/irlmp.c
net/mac80211/iface.c
net/mac80211/mlme.c
net/netfilter/ipset/ip_set_bitmap_ipmac.c
net/netfilter/ipset/ip_set_hash_ipportnet.c
net/netfilter/ipset/ip_set_hash_net.c
net/netfilter/ipset/ip_set_hash_netiface.c
net/netfilter/ipset/ip_set_hash_netport.c
net/netfilter/ipset/ip_set_list_set.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/nf_nat_core.c
net/openvswitch/datapath.c
net/openvswitch/flow.c
net/sched/cls_fw.c
scripts/checkpatch.pl
scripts/mod/devicetable-offsets.c
scripts/mod/file2alias.c
sound/core/pcm_native.c
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/pcmcia/vx/vxpocket.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
tools/hv/hv_kvp_daemon.c
tools/hv/hv_vss_daemon.c [new file with mode: 0644]
tools/power/x86/turbostat/turbostat.c

diff --git a/Documentation/ABI/testing/sysfs-bus-mei b/Documentation/ABI/testing/sysfs-bus-mei
new file mode 100644 (file)
index 0000000..2066f0b
--- /dev/null
@@ -0,0 +1,7 @@
+What:          /sys/bus/mei/devices/.../modalias
+Date:          March 2013
+KernelVersion: 3.10
+Contact:       Samuel Ortiz <sameo@linux.intel.com>
+               linux-mei@linux.intel.com
+Description:   Stores the same MODALIAS value emitted by uevent
+               Format: mei:<mei device name>
diff --git a/Documentation/devicetree/bindings/arm/msm/ssbi.txt b/Documentation/devicetree/bindings/arm/msm/ssbi.txt
new file mode 100644 (file)
index 0000000..54fd5ce
--- /dev/null
@@ -0,0 +1,18 @@
+* Qualcomm SSBI
+
+Some Qualcomm MSM devices contain a point-to-point serial bus used to
+communicate with a limited range of devices (mostly power management
+chips).
+
+These require the following properties:
+
+- compatible: "qcom,ssbi"
+
+- qcom,controller-type
+  indicates the SSBI bus variant the controller should use to talk
+  with the slave device.  This should be one of "ssbi", "ssbi2", or
+  "pmic-arbiter".  The type chosen is determined by the attached
+  slave.
+
+The slave device should be the single child node of the ssbi device
+with a compatible field.
index a336287..d933af3 100644 (file)
@@ -98,7 +98,7 @@ announce the pinrange to the pin ctrl subsystem. For example,
                compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
                reg = <0x1460 0x18>;
                gpio-controller;
-               gpio-ranges = <&pinctrl1 20 10>, <&pinctrl2 50 20>;
+               gpio-ranges = <&pinctrl1 0 20 10>, <&pinctrl2 10 50 20>;
 
     }
 
@@ -107,8 +107,8 @@ where,
 
    Next values specify the base pin and number of pins for the range
    handled by 'qe_pio_e' gpio. In the given example from base pin 20 to
-   pin 29 under pinctrl1 and pin 50 to pin 69 under pinctrl2 is handled
-   by this gpio controller.
+   pin 29 under pinctrl1 with gpio offset 0 and pin 50 to pin 69 under
+   pinctrl2 with gpio offset 10 is handled by this gpio controller.
 
 The pinctrl node must have "#gpio-range-cells" property to show number of
 arguments to pass with phandle from gpio controllers node.
diff --git a/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt b/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt
new file mode 100644 (file)
index 0000000..c6f6667
--- /dev/null
@@ -0,0 +1,29 @@
+NTC Thermistor hwmon sensors
+-------------------------------
+
+Requires node properties:
+- "compatible" value : one of
+       "ntc,ncp15wb473"
+       "ntc,ncp18wb473"
+       "ntc,ncp21wb473"
+       "ntc,ncp03wb473"
+       "ntc,ncp15wl333"
+- "pullup-uv"  Pull up voltage in micro volts
+- "pullup-ohm" Pull up resistor value in ohms
+- "pulldown-ohm" Pull down resistor value in ohms
+- "connected-positive" Always ON, If not specified.
+               Status change is possible.
+- "io-channels"        Channel node of ADC to be used for
+               conversion.
+
+Read more about iio bindings at
+       Documentation/devicetree/bindings/iio/iio-bindings.txt
+
+Example:
+       ncp15wb473@0 {
+               compatible = "ntc,ncp15wb473";
+               pullup-uv = <1800000>;
+               pullup-ohm = <47000>;
+               pulldown-ohm = <0>;
+               io-channels = <&adc 3>;
+       };
index 2c81e45..08f0c3d 100644 (file)
@@ -1,7 +1,9 @@
 One-register-per-pin type device tree based pinctrl driver
 
 Required properties:
-- compatible : "pinctrl-single"
+- compatible : "pinctrl-single" or "pinconf-single".
+  "pinctrl-single" means that pinconf isn't supported.
+  "pinconf-single" means that generic pinconf is supported.
 
 - reg : offset and length of the register set for the mux registers
 
@@ -14,9 +16,61 @@ Optional properties:
 - pinctrl-single,function-off : function off mode for disabled state if
   available and same for all registers; if not specified, disabling of
   pin functions is ignored
+
 - pinctrl-single,bit-per-mux : boolean to indicate that one register controls
   more than one pin
 
+- pinctrl-single,drive-strength : array of value that are used to configure
+  drive strength in the pinmux register. They're value of drive strength
+  current and drive strength mask.
+
+               /* drive strength current, mask */
+               pinctrl-single,power-source = <0x30 0xf0>;
+
+- pinctrl-single,bias-pullup : array of value that are used to configure the
+  input bias pullup in the pinmux register.
+
+               /* input, enabled pullup bits, disabled pullup bits, mask */
+               pinctrl-single,bias-pullup = <0 1 0 1>;
+
+- pinctrl-single,bias-pulldown : array of value that are used to configure the
+  input bias pulldown in the pinmux register.
+
+               /* input, enabled pulldown bits, disabled pulldown bits, mask */
+               pinctrl-single,bias-pulldown = <2 2 0 2>;
+
+  * Two bits to control input bias pullup and pulldown: User should use
+    pinctrl-single,bias-pullup & pinctrl-single,bias-pulldown. One bit means
+    pullup, and the other one bit means pulldown.
+  * Three bits to control input bias enable, pullup and pulldown. User should
+    use pinctrl-single,bias-pullup & pinctrl-single,bias-pulldown. Input bias
+    enable bit should be included in pullup or pulldown bits.
+  * Although driver could set PIN_CONFIG_BIAS_DISABLE, there's no property as
+    pinctrl-single,bias-disable. Because pinctrl single driver could implement
+    it by calling pulldown, pullup disabled.
+
+- pinctrl-single,input-schmitt : array of value that are used to configure
+  input schmitt in the pinmux register. In some silicons, there're two input
+  schmitt value (rising-edge & falling-edge) in the pinmux register.
+
+               /* input schmitt value, mask */
+               pinctrl-single,input-schmitt = <0x30 0x70>;
+
+- pinctrl-single,input-schmitt-enable : array of value that are used to
+  configure input schmitt enable or disable in the pinmux register.
+
+               /* input, enable bits, disable bits, mask */
+               pinctrl-single,input-schmitt-enable = <0x30 0x40 0 0x70>;
+
+- pinctrl-single,gpio-range : list of value that are used to configure a GPIO
+  range. They're value of subnode phandle, pin base in pinctrl device, pin
+  number in this range, GPIO function value of this GPIO range.
+  The number of parameters is depend on #pinctrl-single,gpio-range-cells
+  property.
+
+               /* pin base, nr pins & gpio function */
+               pinctrl-single,gpio-range = <&range 0 3 0 &range 3 9 1>;
+
 This driver assumes that there is only one register for each pin (unless the
 pinctrl-single,bit-per-mux is set), and uses the common pinctrl bindings as
 specified in the pinctrl-bindings.txt document in this directory.
@@ -42,6 +96,20 @@ Where 0xdc is the offset from the pinctrl register base address for the
 device pinctrl register, 0x18 is the desired value, and 0xff is the sub mask to
 be used when applying this change to the register.
 
+
+Optional sub-node: In case some pins could be configured as GPIO in the pinmux
+register, those pins could be defined as a GPIO range. This sub-node is required
+by pinctrl-single,gpio-range property.
+
+Required properties in sub-node:
+- #pinctrl-single,gpio-range-cells : the number of parameters after phandle in
+  pinctrl-single,gpio-range property.
+
+       range: gpio-range {
+               #pinctrl-single,gpio-range-cells = <3>;
+       };
+
+
 Example:
 
 /* SoC common file */
@@ -58,7 +126,7 @@ pmx_core: pinmux@4a100040 {
 
 /* second controller instance for pins in wkup domain */
 pmx_wkup: pinmux@4a31e040 {
-       compatible = "pinctrl-single;
+       compatible = "pinctrl-single";
        reg = <0x4a31e040 0x0038>;
        #address-cells = <1>;
        #size-cells = <0>;
@@ -76,6 +144,29 @@ control_devconf0: pinmux@48002274 {
        pinctrl-single,function-mask = <0x5F>;
 };
 
+/* third controller instance for pins in gpio domain */
+pmx_gpio: pinmux@d401e000 {
+       compatible = "pinconf-single";
+       reg = <0xd401e000 0x0330>;
+       #address-cells = <1>;
+       #size-cells = <1>;
+       ranges;
+
+       pinctrl-single,register-width = <32>;
+       pinctrl-single,function-mask = <7>;
+
+       /* sparse GPIO range could be supported */
+       pinctrl-single,gpio-range = <&range 0 3 0 &range 3 9 1
+                               &range 12 1 0 &range 13 29 1
+                               &range 43 1 0 &range 44 49 1
+                               &range 94 1 1 &range 96 2 1>;
+
+       range: gpio-range {
+               #pinctrl-single,gpio-range-cells = <3>;
+       };
+};
+
+
 /* board specific .dts file */
 
 &pmx_core {
@@ -96,6 +187,15 @@ control_devconf0: pinmux@48002274 {
                >;
        };
 
+       uart0_pins: pinmux_uart0_pins {
+               pinctrl-single,pins = <
+                       0x208 0         /* UART0_RXD (IOCFG138) */
+                       0x20c 0         /* UART0_TXD (IOCFG139) */
+               >;
+               pinctrl-single,bias-pulldown = <0 2 2>;
+               pinctrl-single,bias-pullup = <0 1 1>;
+       };
+
        /* map uart2 pins */
        uart2_pins: pinmux_uart2_pins {
                pinctrl-single,pins = <
@@ -122,6 +222,11 @@ control_devconf0: pinmux@48002274 {
 
 };
 
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_pins>;
+};
+
 &uart2 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart2_pins>;
index 4598a47..c70fca1 100644 (file)
@@ -7,6 +7,7 @@ on-chip controllers onto these pads.
 
 Required Properties:
 - compatible: should be one of the following.
+  - "samsung,s3c64xx-pinctrl": for S3C64xx-compatible pin-controller,
   - "samsung,exynos4210-pinctrl": for Exynos4210 compatible pin-controller.
   - "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller.
   - "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller.
@@ -105,6 +106,8 @@ B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
 
    - compatible: identifies the type of the external wakeup interrupt controller
      The possible values are:
+     - samsung,s3c64xx-wakeup-eint: represents wakeup interrupt controller
+       found on Samsung S3C64xx SoCs,
      - samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller
        found on Samsung Exynos4210 SoC.
    - interrupt-parent: phandle of the interrupt parent to which the external
index c870b64..2871e21 100644 (file)
@@ -5,58 +5,32 @@ Required properties:
 - compatible : "via,vt8500-fb"
 - reg : Should contain 1 register ranges(address and length)
 - interrupts : framebuffer controller interrupt
-- display: a phandle pointing to the display node
+- bits-per-pixel : bit depth of framebuffer (16 or 32)
 
-Required nodes:
-- display: a display node is required to initialize the lcd panel
-       This should be in the board dts.
-- default-mode: a videomode within the display with timing parameters
-       as specified below.
+Required subnodes:
+- display-timings: see display-timing.txt for information
 
 Example:
 
-       fb@d800e400 {
+       fb@d8050800 {
                compatible = "via,vt8500-fb";
                reg = <0xd800e400 0x400>;
                interrupts = <12>;
-               display = <&display>;
-               default-mode = <&mode0>;
-       };
-
-VIA VT8500 Display
------------------------------------------------------
-Required properties (as per of_videomode_helper):
-
- - hactive, vactive: Display resolution
- - hfront-porch, hback-porch, hsync-len: Horizontal Display timing parameters
-   in pixels
-   vfront-porch, vback-porch, vsync-len: Vertical display timing parameters in
-   lines
- - clock: displayclock in Hz
- - bpp: lcd panel bit-depth.
-       <16> for RGB565, <32> for RGB888
-
-Optional properties (as per of_videomode_helper):
- - width-mm, height-mm: Display dimensions in mm
- - hsync-active-high (bool): Hsync pulse is active high
- - vsync-active-high (bool): Vsync pulse is active high
- - interlaced (bool): This is an interlaced mode
- - doublescan (bool): This is a doublescan mode
+               bits-per-pixel = <16>;
 
-Example:
-       display: display@0 {
-               modes {
-                       mode0: mode@0 {
+               display-timings {
+                       native-mode = <&timing0>;
+                       timing0: 800x480 {
+                               clock-frequency = <0>; /* unused but required */
                                hactive = <800>;
                                vactive = <480>;
-                               hback-porch = <88>;
                                hfront-porch = <40>;
+                               hback-porch = <88>;
                                hsync-len = <0>;
                                vback-porch = <32>;
                                vfront-porch = <11>;
                                vsync-len = <1>;
-                               clock = <0>;    /* unused but required */
-                               bpp = <16>;     /* non-standard but required */
                        };
                };
        };
+
index 3d325e1..0bcadb2 100644 (file)
@@ -4,20 +4,30 @@ Wondermedia WM8505 Framebuffer
 Required properties:
 - compatible : "wm,wm8505-fb"
 - reg : Should contain 1 register ranges(address and length)
-- via,display: a phandle pointing to the display node
+- bits-per-pixel : bit depth of framebuffer (16 or 32)
 
-Required nodes:
-- display: a display node is required to initialize the lcd panel
-       This should be in the board dts. See definition in
-       Documentation/devicetree/bindings/video/via,vt8500-fb.txt
-- default-mode: a videomode node as specified in
-       Documentation/devicetree/bindings/video/via,vt8500-fb.txt
+Required subnodes:
+- display-timings: see display-timing.txt for information
 
 Example:
 
-       fb@d8050800 {
+       fb@d8051700 {
                compatible = "wm,wm8505-fb";
-               reg = <0xd8050800 0x200>;
-               display = <&display>;
-               default-mode = <&mode0>;
+               reg = <0xd8051700 0x200>;
+               bits-per-pixel = <16>;
+
+               display-timings {
+                       native-mode = <&timing0>;
+                       timing0: 800x480 {
+                               clock-frequency = <0>; /* unused but required */
+                               hactive = <800>;
+                               vactive = <480>;
+                               hfront-porch = <40>;
+                               hback-porch = <88>;
+                               hsync-len = <0>;
+                               vback-porch = <32>;
+                               vfront-porch = <11>;
+                               vsync-len = <1>;
+                       };
+               };
        };
index 58150c4..9817941 100644 (file)
@@ -12,29 +12,42 @@ Supported chips:
     Addresses scanned: None
     Datasheet: Publicly available at the Analog Devices website
                http://www.analog.com/static/imported-files/data_sheets/ADT7420.pdf
+  * Analog Devices ADT7310
+    Prefix: 'adt7310'
+    Addresses scanned: None
+    Datasheet: Publicly available at the Analog Devices website
+               http://www.analog.com/static/imported-files/data_sheets/ADT7310.pdf
+  * Analog Devices ADT7320
+    Prefix: 'adt7320'
+    Addresses scanned: None
+    Datasheet: Publicly available at the Analog Devices website
+               http://www.analog.com/static/imported-files/data_sheets/ADT7320.pdf
 
 Author: Hartmut Knaack <knaack.h@gmx.de>
 
 Description
 -----------
 
-The ADT7410 is a temperature sensor with rated temperature range of -55°C to
-+150°C. It has a high accuracy of +/-0.5°C and can be operated at a resolution
-of 13 bits (0.0625°C) or 16 bits (0.0078°C). The sensor provides an INT pin to
-indicate that a minimum or maximum temperature set point has been exceeded, as
-well as a critical temperature (CT) pin to indicate that the critical
-temperature set point has been exceeded. Both pins can be set up with a common
-hysteresis of 0°C - 15°C and a fault queue, ranging from 1 to 4 events. Both
-pins can individually set to be active-low or active-high, while the whole
-device can either run in comparator mode or interrupt mode. The ADT7410
-supports continous temperature sampling, as well as sampling one temperature
-value per second or even justget one sample on demand for power saving.
-Besides, it can completely power down its ADC, if power management is
-required.
-
-The ADT7420 is register compatible, the only differences being the package,
-a slightly narrower operating temperature range (-40°C to +150°C), and a
-better accuracy (0.25°C instead of 0.50°C.)
+The ADT7310/ADT7410 is a temperature sensor with rated temperature range of
+-55°C to +150°C. It has a high accuracy of +/-0.5°C and can be operated at a
+resolution of 13 bits (0.0625°C) or 16 bits (0.0078°C). The sensor provides an
+INT pin to indicate that a minimum or maximum temperature set point has been
+exceeded, as well as a critical temperature (CT) pin to indicate that the
+critical temperature set point has been exceeded. Both pins can be set up with a
+common hysteresis of 0°C - 15°C and a fault queue, ranging from 1 to 4 events.
+Both pins can individually set to be active-low or active-high, while the whole
+device can either run in comparator mode or interrupt mode. The ADT7410 supports
+continuous temperature sampling, as well as sampling one temperature value per
+second or even just get one sample on demand for power saving. Besides, it can
+completely power down its ADC, if power management is required.
+
+The ADT7320/ADT7420 is register compatible, the only differences being the
+package, a slightly narrower operating temperature range (-40°C to +150°C), and
+a better accuracy (0.25°C instead of 0.50°C.)
+
+The difference between the ADT7310/ADT7320 and ADT7410/ADT7420 is the control
+interface, the ADT7310 and ADT7320 use SPI while the ADT7410 and ADT7420 use
+I2C.
 
 Configuration Notes
 -------------------
index 26025e4..c1b57d7 100644 (file)
@@ -1,7 +1,13 @@
-Kernel driver max8688
+Kernel driver lm25066
 =====================
 
 Supported chips:
+  * TI LM25056
+    Prefix: 'lm25056'
+    Addresses scanned: -
+    Datasheets:
+       http://www.ti.com/lit/gpn/lm25056
+       http://www.ti.com/lit/gpn/lm25056a
   * National Semiconductor LM25066
     Prefix: 'lm25066'
     Addresses scanned: -
@@ -25,8 +31,9 @@ Author: Guenter Roeck <linux@roeck-us.net>
 Description
 -----------
 
-This driver supports hardware montoring for National Semiconductor LM25066,
-LM5064, and LM5064 Power Management, Monitoring, Control, and Protection ICs.
+This driver supports hardware montoring for National Semiconductor / TI LM25056,
+LM25066, LM5064, and LM5064 Power Management, Monitoring, Control, and
+Protection ICs.
 
 The driver is a client driver to the core PMBus driver. Please see
 Documentation/hwmon/pmbus for details on PMBus client drivers.
@@ -60,14 +67,19 @@ in1_max                     Maximum input voltage.
 in1_min_alarm          Input voltage low alarm.
 in1_max_alarm          Input voltage high alarm.
 
-in2_label              "vout1"
-in2_input              Measured output voltage.
-in2_average            Average measured output voltage.
-in2_min                        Minimum output voltage.
-in2_min_alarm          Output voltage low alarm.
-
-in3_label              "vout2"
-in3_input              Measured voltage on vaux pin
+in2_label              "vmon"
+in2_input              Measured voltage on VAUX pin
+in2_min                        Minimum VAUX voltage (LM25056 only).
+in2_max                        Maximum VAUX voltage (LM25056 only).
+in2_min_alarm          VAUX voltage low alarm (LM25056 only).
+in2_max_alarm          VAUX voltage high alarm (LM25056 only).
+
+in3_label              "vout1"
+                       Not supported on LM25056.
+in3_input              Measured output voltage.
+in3_average            Average measured output voltage.
+in3_min                        Minimum output voltage.
+in3_min_alarm          Output voltage low alarm.
 
 curr1_label            "iin"
 curr1_input            Measured input current.
diff --git a/Documentation/hwmon/lm95234 b/Documentation/hwmon/lm95234
new file mode 100644 (file)
index 0000000..a0e95dd
--- /dev/null
@@ -0,0 +1,36 @@
+Kernel driver lm95234
+=====================
+
+Supported chips:
+  * National Semiconductor / Texas Instruments LM95234
+    Addresses scanned: I2C 0x18, 0x4d, 0x4e
+    Datasheet: Publicly available at the Texas Instruments website
+               http://www.ti.com/product/lm95234
+
+
+Author: Guenter Roeck <linux@roeck-us.net>
+
+Description
+-----------
+
+LM95234 is an 11-bit digital temperature sensor with a 2-wire System Management
+Bus (SMBus) interface and TrueTherm technology that can very accurately monitor
+the temperature of four remote diodes as well as its own temperature.
+The four remote diodes can be external devices such as microprocessors,
+graphics processors or diode-connected 2N3904s. The LM95234's TruTherm
+beta compensation technology allows sensing of 90 nm or 65 nm process
+thermal diodes accurately.
+
+All temperature values are given in millidegrees Celsius. Temperature
+is provided within a range of -127 to +255 degrees (+127.875 degrees for
+the internal sensor). Resolution depends on temperature input and range.
+
+Each sensor has its own maximum limit, but the hysteresis is common to all
+channels. The hysteresis is configurable with the tem1_max_hyst attribute and
+affects the hysteresis on all channels. The first two external sensors also
+have a critical limit.
+
+The lm95234 driver can change its update interval to a fixed set of values.
+It will round up to the next selectable interval. See the datasheet for exact
+values. Reading sensor values more often will do no harm, but will return
+'old' values.
index e4d75c6..dc0d08c 100644 (file)
@@ -2,6 +2,10 @@ Kernel driver ltc2978
 =====================
 
 Supported chips:
+  * Linear Technology LTC2974
+    Prefix: 'ltc2974'
+    Addresses scanned: -
+    Datasheet: http://www.linear.com/product/ltc2974
   * Linear Technology LTC2978
     Prefix: 'ltc2978'
     Addresses scanned: -
@@ -10,6 +14,10 @@ Supported chips:
     Prefix: 'ltc3880'
     Addresses scanned: -
     Datasheet: http://www.linear.com/product/ltc3880
+  * Linear Technology LTC3883
+    Prefix: 'ltc3883'
+    Addresses scanned: -
+    Datasheet: http://www.linear.com/product/ltc3883
 
 Author: Guenter Roeck <linux@roeck-us.net>
 
@@ -17,9 +25,9 @@ Author: Guenter Roeck <linux@roeck-us.net>
 Description
 -----------
 
-The LTC2978 is an octal power supply monitor, supervisor, sequencer and
-margin controller. The LTC3880 is a dual, PolyPhase DC/DC synchronous
-step-down switching regulator controller.
+LTC2974 is a quad digital power supply manager. LTC2978 is an octal power supply
+monitor. LTC3880 is a dual output poly-phase step-down DC/DC controller. LTC3883
+is a single phase step-down DC/DC controller.
 
 
 Usage Notes
@@ -41,63 +49,90 @@ Sysfs attributes
 in1_label              "vin"
 in1_input              Measured input voltage.
 in1_min                        Minimum input voltage.
-in1_max                        Maximum input voltage.
-in1_lcrit              Critical minimum input voltage.
+in1_max                        Maximum input voltage. LTC2974 and LTC2978 only.
+in1_lcrit              Critical minimum input voltage. LTC2974 and LTC2978
+                       only.
 in1_crit               Critical maximum input voltage.
 in1_min_alarm          Input voltage low alarm.
-in1_max_alarm          Input voltage high alarm.
-in1_lcrit_alarm                Input voltage critical low alarm.
+in1_max_alarm          Input voltage high alarm. LTC2974 and LTC2978 only.
+in1_lcrit_alarm                Input voltage critical low alarm. LTC2974 and LTC2978
+                       only.
 in1_crit_alarm         Input voltage critical high alarm.
-in1_lowest             Lowest input voltage. LTC2978 only.
+in1_lowest             Lowest input voltage. LTC2974 and LTC2978 only.
 in1_highest            Highest input voltage.
-in1_reset_history      Reset history. Writing into this attribute will reset
-                       history for all attributes.
-
-in[2-9]_label          "vout[1-8]". Channels 3 to 9 on LTC2978 only.
-in[2-9]_input          Measured output voltage.
-in[2-9]_min            Minimum output voltage.
-in[2-9]_max            Maximum output voltage.
-in[2-9]_lcrit          Critical minimum output voltage.
-in[2-9]_crit           Critical maximum output voltage.
-in[2-9]_min_alarm      Output voltage low alarm.
-in[2-9]_max_alarm      Output voltage high alarm.
-in[2-9]_lcrit_alarm    Output voltage critical low alarm.
-in[2-9]_crit_alarm     Output voltage critical high alarm.
-in[2-9]_lowest         Lowest output voltage. LTC2978 only.
-in[2-9]_highest                Lowest output voltage.
-in[2-9]_reset_history  Reset history. Writing into this attribute will reset
-                       history for all attributes.
-
-temp[1-3]_input                Measured temperature.
+in1_reset_history      Reset input voltage history.
+
+in[N]_label            "vout[1-8]".
+                       LTC2974: N=2-5
+                       LTC2978: N=2-9
+                       LTC3880: N=2-3
+                       LTC3883: N=2
+in[N]_input            Measured output voltage.
+in[N]_min              Minimum output voltage.
+in[N]_max              Maximum output voltage.
+in[N]_lcrit            Critical minimum output voltage.
+in[N]_crit             Critical maximum output voltage.
+in[N]_min_alarm                Output voltage low alarm.
+in[N]_max_alarm                Output voltage high alarm.
+in[N]_lcrit_alarm      Output voltage critical low alarm.
+in[N]_crit_alarm       Output voltage critical high alarm.
+in[N]_lowest           Lowest output voltage. LTC2974 and LTC2978 only.
+in[N]_highest          Highest output voltage.
+in[N]_reset_history    Reset output voltage history.
+
+temp[N]_input          Measured temperature.
+                       On LTC2974, temp[1-4] report external temperatures,
+                       and temp5 reports the chip temperature.
                        On LTC2978, only one temperature measurement is
-                       supported and reflects the internal temperature.
+                       supported and reports the chip temperature.
                        On LTC3880, temp1 and temp2 report external
-                       temperatures, and temp3 reports the internal
-                       temperature.
-temp[1-3]_min          Mimimum temperature.
-temp[1-3]_max          Maximum temperature.
-temp[1-3]_lcrit                Critical low temperature.
-temp[1-3]_crit         Critical high temperature.
-temp[1-3]_min_alarm    Chip temperature low alarm.
-temp[1-3]_max_alarm    Chip temperature high alarm.
-temp[1-3]_lcrit_alarm  Chip temperature critical low alarm.
-temp[1-3]_crit_alarm   Chip temperature critical high alarm.
-temp[1-3]_lowest       Lowest measured temperature. LTC2978 only.
-temp[1-3]_highest      Highest measured temperature.
-temp[1-3]_reset_history        Reset history. Writing into this attribute will reset
-                       history for all attributes.
-
-power[1-2]_label       "pout[1-2]". LTC3880 only.
-power[1-2]_input       Measured power.
-
-curr1_label            "iin". LTC3880 only.
+                       temperatures, and temp3 reports the chip temperature.
+                       On LTC3883, temp1 reports an external temperature,
+                       and temp2 reports the chip temperature.
+temp[N]_min            Mimimum temperature. LTC2974 and LTC2978 only.
+temp[N]_max            Maximum temperature.
+temp[N]_lcrit          Critical low temperature.
+temp[N]_crit           Critical high temperature.
+temp[N]_min_alarm      Temperature low alarm. LTC2974 and LTC2978 only.
+temp[N]_max_alarm      Temperature high alarm.
+temp[N]_lcrit_alarm    Temperature critical low alarm.
+temp[N]_crit_alarm     Temperature critical high alarm.
+temp[N]_lowest         Lowest measured temperature. LTC2974 and LTC2978 only.
+                       Not supported for chip temperature sensor on LTC2974.
+temp[N]_highest                Highest measured temperature. Not supported for chip
+                       temperature sensor on LTC2974.
+temp[N]_reset_history  Reset temperature history. Not supported for chip
+                       temperature sensor on LTC2974.
+
+power1_label           "pin". LTC3883 only.
+power1_input           Measured input power.
+
+power[N]_label         "pout[1-4]".
+                       LTC2974: N=1-4
+                       LTC2978: Not supported
+                       LTC3880: N=1-2
+                       LTC3883: N=2
+power[N]_input         Measured output power.
+
+curr1_label            "iin". LTC3880 and LTC3883 only.
 curr1_input            Measured input current.
 curr1_max              Maximum input current.
 curr1_max_alarm                Input current high alarm.
-
-curr[2-3]_label                "iout[1-2]". LTC3880 only.
-curr[2-3]_input                Measured input current.
-curr[2-3]_max          Maximum input current.
-curr[2-3]_crit         Critical input current.
-curr[2-3]_max_alarm    Input current high alarm.
-curr[2-3]_crit_alarm   Input current critical high alarm.
+curr1_highest          Highest input current. LTC3883 only.
+curr1_reset_history    Reset input current history. LTC3883 only.
+
+curr[N]_label          "iout[1-4]".
+                       LTC2974: N=1-4
+                       LTC2978: not supported
+                       LTC3880: N=2-3
+                       LTC3883: N=2
+curr[N]_input          Measured output current.
+curr[N]_max            Maximum output current.
+curr[N]_crit           Critical high output current.
+curr[N]_lcrit          Critical low output current. LTC2974 only.
+curr[N]_max_alarm      Output current high alarm.
+curr[N]_crit_alarm     Output current critical high alarm.
+curr[N]_lcrit_alarm    Output current critical low alarm. LTC2974 only.
+curr[N]_lowest         Lowest output current. LTC2974 only.
+curr[N]_highest                Highest output current.
+curr[N]_reset_history  Reset output current history.
diff --git a/Documentation/hwmon/nct6775 b/Documentation/hwmon/nct6775
new file mode 100644 (file)
index 0000000..4e9ef60
--- /dev/null
@@ -0,0 +1,188 @@
+Note
+====
+
+This driver supersedes the NCT6775F and NCT6776F support in the W83627EHF
+driver.
+
+Kernel driver NCT6775
+=====================
+
+Supported chips:
+  * Nuvoton NCT5572D/NCT6771F/NCT6772F/NCT6775F/W83677HG-I
+    Prefix: 'nct6775'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: Available from Nuvoton upon request
+  * Nuvoton NCT5577D/NCT6776D/NCT6776F
+    Prefix: 'nct6776'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: Available from Nuvoton upon request
+  * Nuvoton NCT5532D/NCT6779D
+    Prefix: 'nct6779'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: Available from Nuvoton upon request
+
+Authors:
+        Guenter Roeck <linux@roeck-us.net>
+
+Description
+-----------
+
+This driver implements support for the Nuvoton NCT6775F, NCT6776F, and NCT6779D
+and compatible super I/O chips.
+
+The chips support up to 25 temperature monitoring sources. Up to 6 of those are
+direct temperature sensor inputs, the others are special sources such as PECI,
+PCH, and SMBUS. Depending on the chip type, 2 to 6 of the temperature sources
+can be monitored and compared against minimum, maximum, and critical
+temperatures. The driver reports up to 10 of the temperatures to the user.
+There are 4 to 5 fan rotation speed sensors, 8 to 15 analog voltage sensors,
+one VID, alarms with beep warnings (control unimplemented), and some automatic
+fan regulation strategies (plus manual fan control mode).
+
+The temperature sensor sources on all chips are configurable. The configured
+source for each of the temperature sensors is provided in tempX_label.
+
+Temperatures are measured in degrees Celsius and measurement resolution is
+either 1 degC or 0.5 degC, depending on the temperature source and
+configuration. An alarm is triggered when the temperature gets higher than
+the high limit; it stays on until the temperature falls below the hysteresis
+value. Alarms are only supported for temp1 to temp6, depending on the chip type.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. On
+NCT6775F, fan readings can be divided by a programmable divider (1, 2, 4, 8,
+16, 32, 64 or 128) to give the readings more range or accuracy; the other chips
+do not have a fan speed divider. The driver sets the most suitable fan divisor
+itself; specifically, it increases the divider value each time a fan speed
+reading returns an invalid value, and it reduces it if the fan speed reading
+is lower than optimal. Some fans might not be present because they share pins
+with other functions.
+
+Voltage sensors (also known as IN sensors) report their values in millivolts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit.
+
+The driver supports automatic fan control mode known as Thermal Cruise.
+In this mode, the chip attempts to keep the measured temperature in a
+predefined temperature range. If the temperature goes out of range, fan
+is driven slower/faster to reach the predefined range again.
+
+The mode works for fan1-fan5.
+
+sysfs attributes
+----------------
+
+pwm[1-5] - this file stores PWM duty cycle or DC value (fan speed) in range:
+          0 (lowest speed) to 255 (full)
+
+pwm[1-5]_enable - this file controls mode of fan/temperature control:
+       * 0 Fan control disabled (fans set to maximum speed)
+       * 1 Manual mode, write to pwm[0-5] any value 0-255
+       * 2 "Thermal Cruise" mode
+       * 3 "Fan Speed Cruise" mode
+       * 4 "Smart Fan III" mode (NCT6775F only)
+       * 5 "Smart Fan IV" mode
+
+pwm[1-5]_mode - controls if output is PWM or DC level
+        * 0 DC output
+        * 1 PWM output
+
+Common fan control attributes
+-----------------------------
+
+pwm[1-5]_temp_sel      Temperature source. Value is temperature sensor index.
+                       For example, select '1' for temp1_input.
+pwm[1-5]_weight_temp_sel
+                       Secondary temperature source. Value is temperature
+                       sensor index. For example, select '1' for temp1_input.
+                       Set to 0 to disable secondary temperature control.
+
+If secondary temperature functionality is enabled, it is controlled with the
+following attributes.
+
+pwm[1-5]_weight_duty_step
+                       Duty step size.
+pwm[1-5]_weight_temp_step
+                       Temperature step size. With each step over
+                       temp_step_base, the value of weight_duty_step is added
+                       to the current pwm value.
+pwm[1-5]_weight_temp_step_base
+                       Temperature at which secondary temperature control kicks
+                       in.
+pwm[1-5]_weight_temp_step_tol
+                       Temperature step tolerance.
+
+Thermal Cruise mode (2)
+-----------------------
+
+If the temperature is in the range defined by:
+
+pwm[1-5]_target_temp   Target temperature, unit millidegree Celsius
+                       (range 0 - 127000)
+pwm[1-5]_temp_tolerance
+                       Target temperature tolerance, unit millidegree Celsius
+
+there are no changes to fan speed. Once the temperature leaves the interval, fan
+speed increases (if temperature is higher that desired) or decreases (if
+temperature is lower than desired), using the following limits and time
+intervals.
+
+pwm[1-5]_start         fan pwm start value (range 1 - 255), to start fan
+                       when the temperature is above defined range.
+pwm[1-5]_floor         lowest fan pwm (range 0 - 255) if temperature is below
+                       the defined range. If set to 0, the fan is expected to
+                       stop if the temperature is below the defined range.
+pwm[1-5]_step_up_time  milliseconds before fan speed is increased
+pwm[1-5]_step_down_time        milliseconds before fan speed is decreased
+pwm[1-5]_stop_time     how many milliseconds must elapse to switch
+                       corresponding fan off (when the temperature was below
+                       defined range).
+
+Speed Cruise mode (3)
+---------------------
+
+This modes tries to keep the fan speed constant.
+
+fan[1-5]_target                Target fan speed
+fan[1-5]_tolerance
+                       Target speed tolerance
+
+
+Untested; use at your own risk.
+
+Smart Fan IV mode (5)
+---------------------
+
+This mode offers multiple slopes to control the fan speed. The slopes can be
+controlled by setting the pwm and temperature attributes. When the temperature
+rises, the chip will calculate the DC/PWM output based on the current slope.
+There are up to seven data points depending on the chip type. Subsequent data
+points should be set to higher temperatures and higher pwm values to achieve
+higher fan speeds with increasing temperature. The last data point reflects
+critical temperature mode, in which the fans should run at full speed.
+
+pwm[1-5]_auto_point[1-7]_pwm
+                       pwm value to be set if temperature reaches matching
+                       temperature range.
+pwm[1-5]_auto_point[1-7]_temp
+                       Temperature over which the matching pwm is enabled.
+pwm[1-5]_temp_tolerance
+                       Temperature tolerance, unit millidegree Celsius
+pwm[1-5]_crit_temp_tolerance
+                       Temperature tolerance for critical temperature,
+                       unit millidegree Celsius
+
+pwm[1-5]_step_up_time  milliseconds before fan speed is increased
+pwm[1-5]_step_down_time        milliseconds before fan speed is decreased
+
+Usage Notes
+-----------
+
+On various ASUS boards with NCT6776F, it appears that CPUTIN is not really
+connected to anything and floats, or that it is connected to some non-standard
+temperature measurement device. As a result, the temperature reported on CPUTIN
+will not reflect a usable value. It often reports unreasonably high
+temperatures, and in some cases the reported temperature declines if the actual
+temperature increases (similar to the raw PECI temperature value - see PECI
+specification for details). CPUTIN should therefore be be ignored on ASUS
+boards. The CPU temperature on ASUS boards is reported from PECI 0.
index 02850bd..778987d 100644 (file)
@@ -40,7 +40,7 @@ bits for humidity, or 12 bits for temperature and 8 bits for humidity.
 The humidity calibration coefficients are programmed into an OTP memory on the
 chip. These coefficients are used to internally calibrate the signals from the
 sensors. Disabling the reload of those coefficients allows saving 10ms for each
-measurement and decrease power consumption, while loosing on precision.
+measurement and decrease power consumption, while losing on precision.
 
 Some options may be set directly in the sht15_platform_data structure
 or via sysfs attributes.
index 9fc4472..f91e3fa 100644 (file)
@@ -8,8 +8,16 @@ Supported chips:
     Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp401.html
   * Texas Instruments TMP411
     Prefix: 'tmp411'
-    Addresses scanned: I2C 0x4c
+    Addresses scanned: I2C 0x4c, 0x4d, 0x4e
     Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp411.html
+  * Texas Instruments TMP431
+    Prefix: 'tmp431'
+    Addresses scanned: I2C 0x4c, 0x4d
+    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp431.html
+  * Texas Instruments TMP432
+    Prefix: 'tmp432'
+    Addresses scanned: I2C 0x4c, 0x4d
+    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp432.html
 
 Authors:
          Hans de Goede <hdegoede@redhat.com>
@@ -18,19 +26,19 @@ Authors:
 Description
 -----------
 
-This driver implements support for Texas Instruments TMP401 and
-TMP411 chips. These chips implements one remote and one local
-temperature sensor. Temperature is measured in degrees
+This driver implements support for Texas Instruments TMP401, TMP411,
+TMP431, and TMP432 chips. These chips implement one or two remote and
+one local temperature sensors. Temperature is measured in degrees
 Celsius. Resolution of the remote sensor is 0.0625 degree. Local
 sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not
 supported by the driver so far, so using the default resolution of 0.5
 degree).
 
 The driver provides the common sysfs-interface for temperatures (see
-/Documentation/hwmon/sysfs-interface under Temperatures).
+Documentation/hwmon/sysfs-interface under Temperatures).
 
-The TMP411 chip is compatible with TMP401. It provides some additional
-features.
+The TMP411 and TMP431 chips are compatible with TMP401. TMP411 provides
+some additional features.
 
 * Minimum and Maximum temperature measured since power-on, chip-reset
 
@@ -40,3 +48,6 @@ features.
 
   Exported via sysfs attribute temp_reset_history. Writing 1 to this
   file triggers a reset.
+
+TMP432 is compatible with TMP401 and TMP431. It supports two external
+temperature sensors.
index 756b57c..33908a4 100644 (file)
@@ -125,7 +125,7 @@ in2_label           "vmon"
 in2_input              Measured voltage on VMON (ZL2004) or VDRV (ZL9101M,
                        ZL9117M) pin. Reported voltage is 16x the voltage on the
                        pin (adjusted internally by the chip).
-in2_lcrit              Critical minumum VMON/VDRV Voltage.
+in2_lcrit              Critical minimum VMON/VDRV Voltage.
 in2_crit               Critical maximum VMON/VDRV voltage.
 in2_lcrit_alarm                VMON/VDRV voltage critical low alarm.
 in2_crit_alarm         VMON/VDRV voltage critical high alarm.
index 223e4f0..9f651c1 100644 (file)
@@ -882,7 +882,7 @@ int err_inj()
                        cpu=parameters[i].cpu;
                        k = cpu%64;
                        j = cpu/64;
-                       mask[j]=1<<k;
+                       mask[j] = 1UL << k;
 
                        if (sched_setaffinity(0, MASK_SIZE*8, mask)==-1) {
                                perror("Error sched_setaffinity:");
index 13f1aa0..9c7fd98 100644 (file)
@@ -297,6 +297,7 @@ Boot into System Kernel
    On ia64, 256M@256M is a generous value that typically works.
    The region may be automatically placed on ia64, see the
    dump-capture kernel config option notes above.
+   If use sparse memory, the size should be rounded to GRANULE boundaries.
 
    On s390x, typically use "crashkernel=xxM". The value of xx is dependent
    on the memory consumption of the kdump system. In general this is not
index 4609e81..8ccbf27 100644 (file)
@@ -596,9 +596,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        is selected automatically. Check
                        Documentation/kdump/kdump.txt for further details.
 
-       crashkernel_low=size[KMG]
-                       [KNL, x86] parts under 4G.
-
        crashkernel=range1:size1[,range2:size2,...][@offset]
                        [KNL] Same as above, but depends on the memory
                        in the running system. The syntax of range is
@@ -606,6 +603,26 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        a memory unit (amount[KMG]). See also
                        Documentation/kdump/kdump.txt for an example.
 
+       crashkernel=size[KMG],high
+                       [KNL, x86_64] range could be above 4G. Allow kernel
+                       to allocate physical memory region from top, so could
+                       be above 4G if system have more than 4G ram installed.
+                       Otherwise memory region will be allocated below 4G, if
+                       available.
+                       It will be ignored if crashkernel=X is specified.
+       crashkernel=size[KMG],low
+                       [KNL, x86_64] range under 4G. When crashkernel=X,high
+                       is passed, kernel could allocate physical memory region
+                       above 4G, that cause second kernel crash on system
+                       that require some amount of low memory, e.g. swiotlb
+                       requires at least 64M+32K low memory.  Kernel would
+                       try to allocate 72M below 4G automatically.
+                       This one let user to specify own low range under 4G
+                       for second kernel instead.
+                       0: to disable low allocation.
+                       It will be ignored when crashkernel=X,high is not used
+                       or memory reserved is below 4G.
+
        cs89x0_dma=     [HW,NET]
                        Format: <dma>
 
@@ -788,6 +805,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        edd=            [EDD]
                        Format: {"off" | "on" | "skip[mbr]"}
 
+       efi_no_storage_paranoia [EFI; X86]
+                       Using this parameter you can use more than 50% of
+                       your efi variable storage. Use this parameter only if
+                       you are really sure that your UEFI does sane gc and
+                       fulfills the spec otherwise your board may brick.
+
        eisa_irq_edge=  [PARISC,HW]
                        See header of drivers/parisc/eisa.c.
 
diff --git a/Documentation/misc-devices/mei/mei-client-bus.txt b/Documentation/misc-devices/mei/mei-client-bus.txt
new file mode 100644 (file)
index 0000000..f83910a
--- /dev/null
@@ -0,0 +1,138 @@
+Intel(R) Management Engine (ME) Client bus API
+===============================================
+
+
+Rationale
+=========
+MEI misc character device is useful for dedicated applications to send and receive
+data to the many FW appliance found in Intel's ME from the user space.
+However for some of the ME functionalities it make sense to leverage existing software
+stack and expose them through existing kernel subsystems.
+
+In order to plug seamlessly into the kernel device driver model we add kernel virtual
+bus abstraction on top of the MEI driver. This allows implementing linux kernel drivers
+for the various MEI features as a stand alone entities found in their respective subsystem.
+Existing device drivers can even potentially be re-used by adding an MEI CL bus layer to
+the existing code.
+
+
+MEI CL bus API
+===========
+A driver implementation for an MEI Client is very similar to existing bus
+based device drivers. The driver registers itself as an MEI CL bus driver through
+the mei_cl_driver structure:
+
+struct mei_cl_driver {
+       struct device_driver driver;
+       const char *name;
+
+       const struct mei_cl_device_id *id_table;
+
+       int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id);
+       int (*remove)(struct mei_cl_device *dev);
+};
+
+struct mei_cl_id {
+       char name[MEI_NAME_SIZE];
+       kernel_ulong_t driver_info;
+};
+
+The mei_cl_id structure allows the driver to bind itself against a device name.
+
+To actually register a driver on the ME Client bus one must call the mei_cl_add_driver()
+API. This is typically called at module init time.
+
+Once registered on the ME Client bus, a driver will typically try to do some I/O on
+this bus and this should be done through the mei_cl_send() and mei_cl_recv()
+routines. The latter is synchronous (blocks and sleeps until data shows up).
+In order for drivers to be notified of pending events waiting for them (e.g.
+an Rx event) they can register an event handler through the
+mei_cl_register_event_cb() routine. Currently only the MEI_EVENT_RX event
+will trigger an event handler call and the driver implementation is supposed
+to call mei_recv() from the event handler in order to fetch the pending
+received buffers.
+
+
+Example
+=======
+As a theoretical example let's pretend the ME comes with a "contact" NFC IP.
+The driver init and exit routines for this device would look like:
+
+#define CONTACT_DRIVER_NAME "contact"
+
+static struct mei_cl_device_id contact_mei_cl_tbl[] = {
+       { CONTACT_DRIVER_NAME, },
+
+       /* required last entry */
+       { }
+};
+MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl);
+
+static struct mei_cl_driver contact_driver = {
+       .id_table = contact_mei_tbl,
+       .name = CONTACT_DRIVER_NAME,
+
+       .probe = contact_probe,
+       .remove = contact_remove,
+};
+
+static int contact_init(void)
+{
+       int r;
+
+       r = mei_cl_driver_register(&contact_driver);
+       if (r) {
+               pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n");
+               return r;
+       }
+
+       return 0;
+}
+
+static void __exit contact_exit(void)
+{
+       mei_cl_driver_unregister(&contact_driver);
+}
+
+module_init(contact_init);
+module_exit(contact_exit);
+
+And the driver's simplified probe routine would look like that:
+
+int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id)
+{
+       struct contact_driver *contact;
+
+       [...]
+       mei_cl_enable_device(dev);
+
+       mei_cl_register_event_cb(dev, contact_event_cb, contact);
+
+       return 0;
+ }
+
+In the probe routine the driver first enable the MEI device and then registers
+an ME bus event handler which is as close as it can get to registering a
+threaded IRQ handler.
+The handler implementation will typically call some I/O routine depending on
+the pending events:
+
+#define MAX_NFC_PAYLOAD 128
+
+static void contact_event_cb(struct mei_cl_device *dev, u32 events,
+                            void *context)
+{
+       struct contact_driver *contact = context;
+
+       if (events & BIT(MEI_EVENT_RX)) {
+               u8 payload[MAX_NFC_PAYLOAD];
+               int payload_size;
+
+               payload_size = mei_recv(dev, payload, MAX_NFC_PAYLOAD);
+               if (payload_size <= 0)
+                       return;
+
+               /* Hook to the NFC subsystem */
+               nfc_hci_recv_frame(contact->hdev, payload, payload_size);
+       }
+}
index a2b57e0..447fd4c 100644 (file)
@@ -736,6 +736,13 @@ All the above functions are mandatory to implement for a pinmux driver.
 Pin control interaction with the GPIO subsystem
 ===============================================
 
+Note that the following implies that the use case is to use a certain pin
+from the Linux kernel using the API in <linux/gpio.h> with gpio_request()
+and similar functions. There are cases where you may be using something
+that your datasheet calls "GPIO mode" but actually is just an electrical
+configuration for a certain device. See the section below named
+"GPIO mode pitfalls" for more details on this scenario.
+
 The public pinmux API contains two functions named pinctrl_request_gpio()
 and pinctrl_free_gpio(). These two functions shall *ONLY* be called from
 gpiolib-based drivers as part of their gpio_request() and
@@ -774,6 +781,111 @@ obtain the function "gpioN" where "N" is the global GPIO pin number if no
 special GPIO-handler is registered.
 
 
+GPIO mode pitfalls
+==================
+
+Sometime the developer may be confused by a datasheet talking about a pin
+being possible to set into "GPIO mode". It appears that what hardware
+engineers mean with "GPIO mode" is not necessarily the use case that is
+implied in the kernel interface <linux/gpio.h>: a pin that you grab from
+kernel code and then either listen for input or drive high/low to
+assert/deassert some external line.
+
+Rather hardware engineers think that "GPIO mode" means that you can
+software-control a few electrical properties of the pin that you would
+not be able to control if the pin was in some other mode, such as muxed in
+for a device.
+
+Example: a pin is usually muxed in to be used as a UART TX line. But during
+system sleep, we need to put this pin into "GPIO mode" and ground it.
+
+If you make a 1-to-1 map to the GPIO subsystem for this pin, you may start
+to think that you need to come up with something real complex, that the
+pin shall be used for UART TX and GPIO at the same time, that you will grab
+a pin control handle and set it to a certain state to enable UART TX to be
+muxed in, then twist it over to GPIO mode and use gpio_direction_output()
+to drive it low during sleep, then mux it over to UART TX again when you
+wake up and maybe even gpio_request/gpio_free as part of this cycle. This
+all gets very complicated.
+
+The solution is to not think that what the datasheet calls "GPIO mode"
+has to be handled by the <linux/gpio.h> interface. Instead view this as
+a certain pin config setting. Look in e.g. <linux/pinctrl/pinconf-generic.h>
+and you find this in the documentation:
+
+  PIN_CONFIG_OUTPUT: this will configure the pin in output, use argument
+     1 to indicate high level, argument 0 to indicate low level.
+
+So it is perfectly possible to push a pin into "GPIO mode" and drive the
+line low as part of the usual pin control map. So for example your UART
+driver may look like this:
+
+#include <linux/pinctrl/consumer.h>
+
+struct pinctrl          *pinctrl;
+struct pinctrl_state    *pins_default;
+struct pinctrl_state    *pins_sleep;
+
+pins_default = pinctrl_lookup_state(uap->pinctrl, PINCTRL_STATE_DEFAULT);
+pins_sleep = pinctrl_lookup_state(uap->pinctrl, PINCTRL_STATE_SLEEP);
+
+/* Normal mode */
+retval = pinctrl_select_state(pinctrl, pins_default);
+/* Sleep mode */
+retval = pinctrl_select_state(pinctrl, pins_sleep);
+
+And your machine configuration may look like this:
+--------------------------------------------------
+
+static unsigned long uart_default_mode[] = {
+    PIN_CONF_PACKED(PIN_CONFIG_DRIVE_PUSH_PULL, 0),
+};
+
+static unsigned long uart_sleep_mode[] = {
+    PIN_CONF_PACKED(PIN_CONFIG_OUTPUT, 0),
+};
+
+static struct pinctrl_map __initdata pinmap[] = {
+    PIN_MAP_MUX_GROUP("uart", PINCTRL_STATE_DEFAULT, "pinctrl-foo",
+                      "u0_group", "u0"),
+    PIN_MAP_CONFIGS_PIN("uart", PINCTRL_STATE_DEFAULT, "pinctrl-foo",
+                        "UART_TX_PIN", uart_default_mode),
+    PIN_MAP_MUX_GROUP("uart", PINCTRL_STATE_SLEEP, "pinctrl-foo",
+                      "u0_group", "gpio-mode"),
+    PIN_MAP_CONFIGS_PIN("uart", PINCTRL_STATE_SLEEP, "pinctrl-foo",
+                        "UART_TX_PIN", uart_sleep_mode),
+};
+
+foo_init(void) {
+    pinctrl_register_mappings(pinmap, ARRAY_SIZE(pinmap));
+}
+
+Here the pins we want to control are in the "u0_group" and there is some
+function called "u0" that can be enabled on this group of pins, and then
+everything is UART business as usual. But there is also some function
+named "gpio-mode" that can be mapped onto the same pins to move them into
+GPIO mode.
+
+This will give the desired effect without any bogus interaction with the
+GPIO subsystem. It is just an electrical configuration used by that device
+when going to sleep, it might imply that the pin is set into something the
+datasheet calls "GPIO mode" but that is not the point: it is still used
+by that UART device to control the pins that pertain to that very UART
+driver, putting them into modes needed by the UART. GPIO in the Linux
+kernel sense are just some 1-bit line, and is a different use case.
+
+How the registers are poked to attain the push/pull and output low
+configuration and the muxing of the "u0" or "gpio-mode" group onto these
+pins is a question for the driver.
+
+Some datasheets will be more helpful and refer to the "GPIO mode" as
+"low power mode" rather than anything to do with GPIO. This often means
+the same thing electrically speaking, but in this latter case the
+software engineers will usually quickly identify that this is some
+specific muxing/configuration rather than anything related to the GPIO
+API.
+
+
 Board/machine configuration
 ==================================
 
index ae66f9b..fcaf0b4 100644 (file)
@@ -143,7 +143,8 @@ Parameter:     id:   handle for debug log
 
 Return Value:  none 
 
-Description:   frees memory for a debug log     
+Description:   frees memory for a debug log and removes all registered debug
+              views.
                Must not be called within an interrupt handler 
 
 ---------------------------------------------------------------------------
index 8bdd7a7..8ba3b48 100644 (file)
@@ -1031,6 +1031,7 @@ F:        drivers/mmc/host/msm_sdcc.h
 F:     drivers/tty/serial/msm_serial.h
 F:     drivers/tty/serial/msm_serial.c
 F:     drivers/*/pm8???-*
+F:     drivers/ssbi/
 F:     include/linux/mfd/pm8xxx/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm.git
 S:     Maintained
@@ -5412,6 +5413,13 @@ L:       linux-scsi@vger.kernel.org
 S:     Maintained
 F:     drivers/scsi/NCR_D700.*
 
+NCT6775 HARDWARE MONITOR DRIVER
+M:     Guenter Roeck <linux@roeck-us.net>
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+F:     Documentation/hwmon/nct6775
+F:     drivers/hwmon/nct6775.c
+
 NETEFFECT IWARP RNIC DRIVER (IW_NES)
 M:     Faisal Latif <faisal.latif@intel.com>
 L:     linux-rdma@vger.kernel.org
index 9cf6783..8fe6991 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 9
 SUBLEVEL = 0
-EXTRAVERSION = -rc7
+EXTRAVERSION =
 NAME = Unicycling Gorilla
 
 # *DOCUMENTATION*
@@ -513,7 +513,8 @@ ifeq ($(KBUILD_EXTMOD),)
 # Carefully list dependencies so we do not try to build scripts twice
 # in parallel
 PHONY += scripts
-scripts: scripts_basic include/config/auto.conf include/config/tristate.conf
+scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \
+        asm-generic
        $(Q)$(MAKE) $(build)=$(@)
 
 # Objects we will link into vmlinux / subdirs we need to visit
index 31f2157..67f8670 100644 (file)
                      <0x19c00000 0x1000>;
                interrupts = <0 195 0x0>;
        };
+
+       qcom,ssbi@500000 {
+               compatible = "qcom,ssbi";
+               reg = <0x500000 0x1000>;
+               qcom,controller-type = "pmic-arbiter";
+       };
 };
index 9e621b5..c9b09a8 100644 (file)
                      <0x16400000 0x1000>;
                interrupts = <0 154 0x0>;
        };
+
+       qcom,ssbi@500000 {
+               compatible = "qcom,ssbi";
+               reg = <0x500000 0x1000>;
+               qcom,controller-type = "pmic-arbiter";
+       };
 };
index 1513c19..122ae94 100644 (file)
@@ -89,7 +89,7 @@
                pinmux: pinmux@e0700000 {
                        compatible = "st,spear1310-pinmux";
                        reg = <0xe0700000 0x1000>;
-                       #gpio-range-cells = <2>;
+                       #gpio-range-cells = <3>;
                };
 
                apb {
                                interrupt-controller;
                                gpio-controller;
                                #gpio-cells = <2>;
-                               gpio-ranges = <&pinmux 0 246>;
+                               gpio-ranges = <&pinmux 0 246>;
                                status = "disabled";
 
                                st-plgpio,ngpio = <246>;
index 34da11a..c511c47 100644 (file)
@@ -63,7 +63,7 @@
                pinmux: pinmux@e0700000 {
                        compatible = "st,spear1340-pinmux";
                        reg = <0xe0700000 0x1000>;
-                       #gpio-range-cells = <2>;
+                       #gpio-range-cells = <3>;
                };
 
                pwm: pwm@e0180000 {
                                interrupt-controller;
                                gpio-controller;
                                #gpio-cells = <2>;
-                               gpio-ranges = <&pinmux 0 252>;
+                               gpio-ranges = <&pinmux 0 252>;
                                status = "disabled";
 
                                st-plgpio,ngpio = <250>;
index ab45b8c..9537208 100644 (file)
@@ -25,7 +25,7 @@
                pinmux: pinmux@b4000000 {
                        compatible = "st,spear310-pinmux";
                        reg = <0xb4000000 0x1000>;
-                       #gpio-range-cells = <2>;
+                       #gpio-range-cells = <3>;
                };
 
                fsmc: flash@44000000 {
                                interrupt-controller;
                                gpio-controller;
                                #gpio-cells = <2>;
-                               gpio-ranges = <&pinmux 0 102>;
+                               gpio-ranges = <&pinmux 0 102>;
                                status = "disabled";
 
                                st-plgpio,ngpio = <102>;
index caa5520..ffea342 100644 (file)
@@ -24,7 +24,7 @@
                pinmux: pinmux@b3000000 {
                        compatible = "st,spear320-pinmux";
                        reg = <0xb3000000 0x1000>;
-                       #gpio-range-cells = <2>;
+                       #gpio-range-cells = <3>;
                };
 
                clcd@90000000 {
                                interrupt-controller;
                                gpio-controller;
                                #gpio-cells = <2>;
-                               gpio-ranges = <&pinmux 0 102>;
+                               gpio-ranges = <&pinmux 0 102>;
                                status = "disabled";
 
                                st-plgpio,ngpio = <102>;
index 567cf4e..877b33a 100644 (file)
 
 / {
        model = "Benign BV07 Netbook";
+};
 
-       /*
-        * Display node is based on Sascha Hauer's patch on dri-devel.
-        * Added a bpp property to calculate the size of the framebuffer
-        * until the binding is formalized.
-        */
-       display: display@0 {
-               modes {
-                       mode0: mode@0 {
-                               hactive = <800>;
-                               vactive = <480>;
-                               hback-porch = <88>;
-                               hfront-porch = <40>;
-                               hsync-len = <0>;
-                               vback-porch = <32>;
-                               vfront-porch = <11>;
-                               vsync-len = <1>;
-                               clock = <0>;    /* unused but required */
-                               bpp = <16>;     /* non-standard but required */
-                       };
+&fb {
+       bits-per-pixel = <16>;
+       display-timings {
+               native-mode = <&timing0>;
+               timing0: 800x480 {
+                       clock-frequency = <0>; /* unused but required */
+                       hactive = <800>;
+                       vactive = <480>;
+                       hfront-porch = <40>;
+                       hback-porch = <88>;
+                       hsync-len = <0>;
+                       vback-porch = <32>;
+                       vfront-porch = <11>;
+                       vsync-len = <1>;
                };
        };
 };
index cf31ced..68c8dc6 100644 (file)
                        interrupts = <43>;
                };
 
-               fb@d800e400 {
+               fb: fb@d8050800 {
                        compatible = "via,vt8500-fb";
                        reg = <0xd800e400 0x400>;
                        interrupts = <12>;
-                       display = <&display>;
-                       default-mode = <&mode0>;
                };
 
                ge_rops@d8050400 {
index fd4e248..edd2cec 100644 (file)
 
 / {
        model = "Wondermedia WM8505 Netbook";
+};
 
-       /*
-        * Display node is based on Sascha Hauer's patch on dri-devel.
-        * Added a bpp property to calculate the size of the framebuffer
-        * until the binding is formalized.
-        */
-       display: display@0 {
-               modes {
-                       mode0: mode@0 {
-                               hactive = <800>;
-                               vactive = <480>;
-                               hback-porch = <88>;
-                               hfront-porch = <40>;
-                               hsync-len = <0>;
-                               vback-porch = <32>;
-                               vfront-porch = <11>;
-                               vsync-len = <1>;
-                               clock = <0>;    /* unused but required */
-                               bpp = <32>;     /* non-standard but required */
-                       };
+&fb {
+       bits-per-pixel = <32>;
+       display-timings {
+               native-mode = <&timing0>;
+               timing0: 800x480 {
+                       clock-frequency = <0>; /* unused but required */
+                       hactive = <800>;
+                       vactive = <480>;
+                       hfront-porch = <40>;
+                       hback-porch = <88>;
+                       hsync-len = <0>;
+                       vback-porch = <32>;
+                       vfront-porch = <11>;
+                       vsync-len = <1>;
                };
        };
 };
index e74a1c0..bcf668d 100644 (file)
                        interrupts = <0>;
                };
 
-               fb@d8050800 {
+               fb: fb@d8050800 {
                        compatible = "wm,wm8505-fb";
                        reg = <0xd8050800 0x200>;
-                       display = <&display>;
-                       default-mode = <&mode0>;
                };
 
                ge_rops@d8050400 {
index cefd938..61671a0 100644 (file)
 
 / {
        model = "Wondermedia WM8650-MID Tablet";
+};
+
+&fb {
+       bits-per-pixel = <16>;
 
-       /*
-        * Display node is based on Sascha Hauer's patch on dri-devel.
-        * Added a bpp property to calculate the size of the framebuffer
-        * until the binding is formalized.
-        */
-       display: display@0 {
-               modes {
-                       mode0: mode@0 {
-                               hactive = <800>;
-                               vactive = <480>;
-                               hback-porch = <88>;
-                               hfront-porch = <40>;
-                               hsync-len = <0>;
-                               vback-porch = <32>;
-                               vfront-porch = <11>;
-                               vsync-len = <1>;
-                               clock = <0>;    /* unused but required */
-                               bpp = <16>;     /* non-standard but required */
-                       };
+       display-timings {
+               native-mode = <&timing0>;
+               timing0: 800x480 {
+                       clock-frequency = <0>; /* unused but required */
+                       hactive = <800>;
+                       vactive = <480>;
+                       hfront-porch = <40>;
+                       hback-porch = <88>;
+                       hsync-len = <0>;
+                       vback-porch = <32>;
+                       vfront-porch = <11>;
+                       vsync-len = <1>;
                };
        };
 };
+
index db3c0a1..9313407 100644 (file)
                        interrupts = <43>;
                };
 
-               fb@d8050800 {
+               fb: fb@d8050800 {
                        compatible = "wm,wm8505-fb";
                        reg = <0xd8050800 0x200>;
-                       display = <&display>;
-                       default-mode = <&mode0>;
                };
 
                ge_rops@d8050400 {
index fcc660c..32d2253 100644 (file)
 / {
        model = "Wondermedia WM8850-W70v2 Tablet";
 
-       /*
-        * Display node is based on Sascha Hauer's patch on dri-devel.
-        * Added a bpp property to calculate the size of the framebuffer
-        * until the binding is formalized.
-        */
-       display: display@0 {
-               modes {
-                       mode0: mode@0 {
-                               hactive = <800>;
-                               vactive = <480>;
-                               hback-porch = <88>;
-                               hfront-porch = <40>;
-                               hsync-len = <0>;
-                               vback-porch = <32>;
-                               vfront-porch = <11>;
-                               vsync-len = <1>;
-                               clock = <0>;    /* unused but required */
-                               bpp = <16>;     /* non-standard but required */
-                       };
-               };
-       };
-
        backlight {
                compatible = "pwm-backlight";
                pwms = <&pwm 0 50000 1>;        /* duty inverted */
                default-brightness-level = <5>;
        };
 };
+
+&fb {
+       bits-per-pixel = <16>;
+       display-timings {
+               native-mode = <&timing0>;
+               timing0: 800x480 {
+                       clock-frequency = <0>; /* unused but required */
+                       hactive = <800>;
+                       vactive = <480>;
+                       hfront-porch = <40>;
+                       hback-porch = <88>;
+                       hsync-len = <0>;
+                       vback-porch = <32>;
+                       vfront-porch = <11>;
+                       vsync-len = <1>;
+               };
+       };
+};
index e8cbfdc..7149cd1 100644 (file)
                        };
                };
 
-               fb@d8051700 {
+               fb: fb@d8051700 {
                        compatible = "wm,wm8505-fb";
                        reg = <0xd8051700 0x200>;
-                       display = <&display>;
-                       default-mode = <&mode0>;
                };
 
                ge_rops@d8050400 {
index cca9f15..ea289e1 100644 (file)
 #undef _CACHE
 #undef MULTI_CACHE
 
-#if defined(CONFIG_CPU_CACHE_V3)
-# ifdef _CACHE
-#  define MULTI_CACHE 1
-# else
-#  define _CACHE v3
-# endif
-#endif
-
 #if defined(CONFIG_CPU_CACHE_V4)
 # ifdef _CACHE
 #  define MULTI_CACHE 1
index 02fe2fb..ed94b1a 100644 (file)
@@ -37,7 +37,7 @@ extern int iop3xx_get_init_atu(void);
  * IOP3XX processor registers
  */
 #define IOP3XX_PERIPHERAL_PHYS_BASE    0xffffe000
-#define IOP3XX_PERIPHERAL_VIRT_BASE    0xfeffe000
+#define IOP3XX_PERIPHERAL_VIRT_BASE    0xfedfe000
 #define IOP3XX_PERIPHERAL_SIZE         0x00002000
 #define IOP3XX_PERIPHERAL_UPPER_PA (IOP3XX_PERIPHERAL_PHYS_BASE +\
                                        IOP3XX_PERIPHERAL_SIZE - 1)
index 6ef8afd..86b8fe3 100644 (file)
 #define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* MemAttr[3:0] */
 #define L_PTE_S2_MT_WRITEBACK   (_AT(pteval_t, 0xf) << 2) /* MemAttr[3:0] */
 #define L_PTE_S2_RDONLY                 (_AT(pteval_t, 1) << 6)   /* HAP[1]   */
-#define L_PTE_S2_RDWR           (_AT(pteval_t, 2) << 6)   /* HAP[2:1] */
+#define L_PTE_S2_RDWR           (_AT(pteval_t, 3) << 6)   /* HAP[2:1] */
 
 /*
  * Hyp-mode PL2 PTE definitions for LPAE.
index 9e9c041..ab865e6 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <asm/glue.h>
 
-#define TLB_V3_PAGE    (1 << 0)
 #define TLB_V4_U_PAGE  (1 << 1)
 #define TLB_V4_D_PAGE  (1 << 2)
 #define TLB_V4_I_PAGE  (1 << 3)
@@ -22,7 +21,6 @@
 #define TLB_V6_D_PAGE  (1 << 5)
 #define TLB_V6_I_PAGE  (1 << 6)
 
-#define TLB_V3_FULL    (1 << 8)
 #define TLB_V4_U_FULL  (1 << 9)
 #define TLB_V4_D_FULL  (1 << 10)
 #define TLB_V4_I_FULL  (1 << 11)
@@ -52,7 +50,6 @@
  *     =============
  *
  *     We have the following to choose from:
- *       v3    - ARMv3
  *       v4    - ARMv4 without write buffer
  *       v4wb  - ARMv4 with write buffer without I TLB flush entry instruction
  *       v4wbi - ARMv4 with write buffer with I TLB flush entry instruction
@@ -330,7 +327,6 @@ static inline void local_flush_tlb_all(void)
        if (tlb_flag(TLB_WB))
                dsb();
 
-       tlb_op(TLB_V3_FULL, "c6, c0, 0", zero);
        tlb_op(TLB_V4_U_FULL | TLB_V6_U_FULL, "c8, c7, 0", zero);
        tlb_op(TLB_V4_D_FULL | TLB_V6_D_FULL, "c8, c6, 0", zero);
        tlb_op(TLB_V4_I_FULL | TLB_V6_I_FULL, "c8, c5, 0", zero);
@@ -351,9 +347,8 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
        if (tlb_flag(TLB_WB))
                dsb();
 
-       if (possible_tlb_flags & (TLB_V3_FULL|TLB_V4_U_FULL|TLB_V4_D_FULL|TLB_V4_I_FULL)) {
+       if (possible_tlb_flags & (TLB_V4_U_FULL|TLB_V4_D_FULL|TLB_V4_I_FULL)) {
                if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) {
-                       tlb_op(TLB_V3_FULL, "c6, c0, 0", zero);
                        tlb_op(TLB_V4_U_FULL, "c8, c7, 0", zero);
                        tlb_op(TLB_V4_D_FULL, "c8, c6, 0", zero);
                        tlb_op(TLB_V4_I_FULL, "c8, c5, 0", zero);
@@ -385,9 +380,8 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
        if (tlb_flag(TLB_WB))
                dsb();
 
-       if (possible_tlb_flags & (TLB_V3_PAGE|TLB_V4_U_PAGE|TLB_V4_D_PAGE|TLB_V4_I_PAGE|TLB_V4_I_FULL) &&
+       if (possible_tlb_flags & (TLB_V4_U_PAGE|TLB_V4_D_PAGE|TLB_V4_I_PAGE|TLB_V4_I_FULL) &&
            cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
-               tlb_op(TLB_V3_PAGE, "c6, c0, 0", uaddr);
                tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", uaddr);
                tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", uaddr);
                tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", uaddr);
@@ -418,7 +412,6 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
        if (tlb_flag(TLB_WB))
                dsb();
 
-       tlb_op(TLB_V3_PAGE, "c6, c0, 0", kaddr);
        tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", kaddr);
        tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", kaddr);
        tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", kaddr);
index 5dc1aa6..1fd749e 100644 (file)
@@ -1043,7 +1043,7 @@ static int dbg_cpu_pm_notify(struct notifier_block *self, unsigned long action,
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata dbg_cpu_pm_nb = {
+static struct notifier_block dbg_cpu_pm_nb = {
        .notifier_call = dbg_cpu_pm_notify,
 };
 
index 146157d..8c3094d 100644 (file)
@@ -253,7 +253,10 @@ validate_event(struct pmu_hw_events *hw_events,
        struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
        struct pmu *leader_pmu = event->group_leader->pmu;
 
-       if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF)
+       if (event->pmu != leader_pmu || event->state < PERF_EVENT_STATE_OFF)
+               return 1;
+
+       if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec)
                return 1;
 
        return armpmu->get_event_idx(hw_events, event) >= 0;
index bd6f56b..59d2adb 100644 (file)
@@ -45,12 +45,12 @@ static u32 notrace jiffy_sched_clock_read(void)
 
 static u32 __read_mostly (*read_sched_clock)(void) = jiffy_sched_clock_read;
 
-static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift)
+static inline u64 notrace cyc_to_ns(u64 cyc, u32 mult, u32 shift)
 {
        return (cyc * mult) >> shift;
 }
 
-static unsigned long long cyc_to_sched_clock(u32 cyc, u32 mask)
+static unsigned long long notrace cyc_to_sched_clock(u32 cyc, u32 mask)
 {
        u64 epoch_ns;
        u32 epoch_cyc;
index d343a6c..234e339 100644 (file)
@@ -56,7 +56,6 @@
 #include <asm/virt.h>
 
 #include "atags.h"
-#include "tcm.h"
 
 
 #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
@@ -798,8 +797,6 @@ void __init setup_arch(char **cmdline_p)
 
        reserve_crashkernel();
 
-       tcm_init();
-
 #ifdef CONFIG_MULTI_IRQ_HANDLER
        handle_arch_irq = mdesc->handle_irq;
 #endif
index 30ae6bb..f50f19e 100644 (file)
@@ -17,7 +17,6 @@
 #include <asm/mach/map.h>
 #include <asm/memory.h>
 #include <asm/system_info.h>
-#include "tcm.h"
 
 static struct gen_pool *tcm_pool;
 static bool dtcm_present;
index 5a93698..c1fe498 100644 (file)
@@ -201,6 +201,7 @@ int kvm_dev_ioctl_check_extension(long ext)
                break;
        case KVM_CAP_ARM_SET_DEVICE_ADDR:
                r = 1;
+               break;
        case KVM_CAP_NR_VCPUS:
                r = num_online_cpus();
                break;
index 4ea9a98..7bed755 100644 (file)
@@ -79,11 +79,11 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
        u32 val;
        int cpu;
 
-       cpu = get_cpu();
-
        if (!p->is_write)
                return read_from_write_only(vcpu, p);
 
+       cpu = get_cpu();
+
        cpumask_setall(&vcpu->arch.require_dcache_flush);
        cpumask_clear_cpu(cpu, &vcpu->arch.require_dcache_flush);
 
index f30c528..890cae2 100644 (file)
@@ -28,13 +28,11 @@ extern void secondary_startup(void);
  */
 void __ref highbank_cpu_die(unsigned int cpu)
 {
-       flush_cache_all();
-
        highbank_set_cpu_jump(cpu, phys_to_virt(0));
-       highbank_set_core_pwr();
 
-       cpu_do_idle();
+       flush_cache_louis();
+       highbank_set_core_pwr();
 
-       /* We should never return from idle */
-       panic("highbank: cpu %d unexpectedly exit from shutdown\n", cpu);
+       while (1)
+               cpu_do_idle();
 }
index 9e05765..eaba9dc 100644 (file)
@@ -2714,16 +2714,22 @@ static struct omap_ocp2scp_dev ocp2scp_dev_attr[] = {
        { }
 };
 
-static struct omap_hwmod_opt_clk ocp2scp_usb_phy_opt_clks[] = {
-       { .role = "48mhz", .clk = "ocp2scp_usb_phy_phy_48m" },
-};
-
 /* ocp2scp_usb_phy */
 static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = {
        .name           = "ocp2scp_usb_phy",
        .class          = &omap44xx_ocp2scp_hwmod_class,
        .clkdm_name     = "l3_init_clkdm",
-       .main_clk       = "func_48m_fclk",
+       /*
+        * ocp2scp_usb_phy_phy_48m is provided by the OMAP4 PRCM IP
+        * block as an "optional clock," and normally should never be
+        * specified as the main_clk for an OMAP IP block.  However it
+        * turns out that this clock is actually the main clock for
+        * the ocp2scp_usb_phy IP block:
+        * http://lists.infradead.org/pipermail/linux-arm-kernel/2012-September/119943.html
+        * So listing ocp2scp_usb_phy_phy_48m as a main_clk here seems
+        * to be the best workaround.
+        */
+       .main_clk       = "ocp2scp_usb_phy_phy_48m",
        .prcm = {
                .omap4 = {
                        .clkctrl_offs = OMAP4_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL_OFFSET,
@@ -2732,8 +2738,6 @@ static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = {
                },
        },
        .dev_attr       = ocp2scp_dev_attr,
-       .opt_clks       = ocp2scp_usb_phy_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(ocp2scp_usb_phy_opt_clks),
 };
 
 /*
index 025d173..4045c49 100644 (file)
@@ -43,7 +43,7 @@ config CPU_ARM740T
        depends on !MMU
        select CPU_32v4T
        select CPU_ABRT_LV4T
-       select CPU_CACHE_V3     # although the core is v4t
+       select CPU_CACHE_V4
        select CPU_CP15_MPU
        select CPU_PABRT_LEGACY
        help
@@ -469,9 +469,6 @@ config CPU_PABRT_V7
        bool
 
 # The cache model
-config CPU_CACHE_V3
-       bool
-
 config CPU_CACHE_V4
        bool
 
index 4e333fa..9e51be9 100644 (file)
@@ -33,7 +33,6 @@ obj-$(CONFIG_CPU_PABRT_LEGACY)        += pabort-legacy.o
 obj-$(CONFIG_CPU_PABRT_V6)     += pabort-v6.o
 obj-$(CONFIG_CPU_PABRT_V7)     += pabort-v7.o
 
-obj-$(CONFIG_CPU_CACHE_V3)     += cache-v3.o
 obj-$(CONFIG_CPU_CACHE_V4)     += cache-v4.o
 obj-$(CONFIG_CPU_CACHE_V4WT)   += cache-v4wt.o
 obj-$(CONFIG_CPU_CACHE_V4WB)   += cache-v4wb.o
index dd3d591..48bc3c0 100644 (file)
@@ -343,6 +343,7 @@ void __init feroceon_l2_init(int __l2_wt_override)
        outer_cache.inv_range = feroceon_l2_inv_range;
        outer_cache.clean_range = feroceon_l2_clean_range;
        outer_cache.flush_range = feroceon_l2_flush_range;
+       outer_cache.inv_all = l2_inv_all;
 
        enable_l2();
 
diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S
deleted file mode 100644 (file)
index 8a3fade..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- *  linux/arch/arm/mm/cache-v3.S
- *
- *  Copyright (C) 1997-2002 Russell king
- *
- * 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/linkage.h>
-#include <linux/init.h>
-#include <asm/page.h>
-#include "proc-macros.S"
-
-/*
- *     flush_icache_all()
- *
- *     Unconditionally clean and invalidate the entire icache.
- */
-ENTRY(v3_flush_icache_all)
-       mov     pc, lr
-ENDPROC(v3_flush_icache_all)
-
-/*
- *     flush_user_cache_all()
- *
- *     Invalidate all cache entries in a particular address
- *     space.
- *
- *     - mm    - mm_struct describing address space
- */
-ENTRY(v3_flush_user_cache_all)
-       /* FALLTHROUGH */
-/*
- *     flush_kern_cache_all()
- *
- *     Clean and invalidate the entire cache.
- */
-ENTRY(v3_flush_kern_cache_all)
-       /* FALLTHROUGH */
-
-/*
- *     flush_user_cache_range(start, end, flags)
- *
- *     Invalidate a range of cache entries in the specified
- *     address space.
- *
- *     - start - start address (may not be aligned)
- *     - end   - end address (exclusive, may not be aligned)
- *     - flags - vma_area_struct flags describing address space
- */
-ENTRY(v3_flush_user_cache_range)
-       mov     ip, #0
-       mcreq   p15, 0, ip, c7, c0, 0           @ flush ID cache
-       mov     pc, lr
-
-/*
- *     coherent_kern_range(start, end)
- *
- *     Ensure coherency between the Icache and the Dcache in the
- *     region described by start.  If you have non-snooping
- *     Harvard caches, you need to implement this function.
- *
- *     - start  - virtual start address
- *     - end    - virtual end address
- */
-ENTRY(v3_coherent_kern_range)
-       /* FALLTHROUGH */
-
-/*
- *     coherent_user_range(start, end)
- *
- *     Ensure coherency between the Icache and the Dcache in the
- *     region described by start.  If you have non-snooping
- *     Harvard caches, you need to implement this function.
- *
- *     - start  - virtual start address
- *     - end    - virtual end address
- */
-ENTRY(v3_coherent_user_range)
-       mov     r0, #0
-       mov     pc, lr
-
-/*
- *     flush_kern_dcache_area(void *page, size_t size)
- *
- *     Ensure no D cache aliasing occurs, either with itself or
- *     the I cache
- *
- *     - addr  - kernel address
- *     - size  - region size
- */
-ENTRY(v3_flush_kern_dcache_area)
-       /* FALLTHROUGH */
-
-/*
- *     dma_flush_range(start, end)
- *
- *     Clean and invalidate the specified virtual address range.
- *
- *     - start  - virtual start address
- *     - end    - virtual end address
- */
-ENTRY(v3_dma_flush_range)
-       mov     r0, #0
-       mcr     p15, 0, r0, c7, c0, 0           @ flush ID cache
-       mov     pc, lr
-
-/*
- *     dma_unmap_area(start, size, dir)
- *     - start - kernel virtual start address
- *     - size  - size of region
- *     - dir   - DMA direction
- */
-ENTRY(v3_dma_unmap_area)
-       teq     r2, #DMA_TO_DEVICE
-       bne     v3_dma_flush_range
-       /* FALLTHROUGH */
-
-/*
- *     dma_map_area(start, size, dir)
- *     - start - kernel virtual start address
- *     - size  - size of region
- *     - dir   - DMA direction
- */
-ENTRY(v3_dma_map_area)
-       mov     pc, lr
-ENDPROC(v3_dma_unmap_area)
-ENDPROC(v3_dma_map_area)
-
-       .globl  v3_flush_kern_cache_louis
-       .equ    v3_flush_kern_cache_louis, v3_flush_kern_cache_all
-
-       __INITDATA
-
-       @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
-       define_cache_functions v3
index 43e5d77..a7ba68f 100644 (file)
@@ -58,7 +58,7 @@ ENTRY(v4_flush_kern_cache_all)
 ENTRY(v4_flush_user_cache_range)
 #ifdef CONFIG_CPU_CP15
        mov     ip, #0
-       mcreq   p15, 0, ip, c7, c7, 0           @ flush ID cache
+       mcr     p15, 0, ip, c7, c7, 0           @ flush ID cache
        mov     pc, lr
 #else
        /* FALLTHROUGH */
index 7897894..a84ff76 100644 (file)
@@ -34,6 +34,7 @@
 #include <asm/mach/pci.h>
 
 #include "mm.h"
+#include "tcm.h"
 
 /*
  * empty_zero_page is a special page that is used for
@@ -1277,6 +1278,7 @@ void __init paging_init(struct machine_desc *mdesc)
        dma_contiguous_remap();
        devicemaps_init(mdesc);
        kmap_init();
+       tcm_init();
 
        top_pmd = pmd_off_k(0xffff0000);
 
index dc5de5d..fde2d2a 100644 (file)
@@ -77,24 +77,27 @@ __arm740_setup:
        mcr     p15, 0, r0, c6, c0              @ set area 0, default
 
        ldr     r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM
-       ldr     r1, =(CONFIG_DRAM_SIZE >> 12)   @ size of RAM (must be >= 4KB)
-       mov     r2, #10                         @ 11 is the minimum (4KB)
-1:     add     r2, r2, #1                      @ area size *= 2
-       mov     r1, r1, lsr #1
+       ldr     r3, =(CONFIG_DRAM_SIZE >> 12)   @ size of RAM (must be >= 4KB)
+       mov     r4, #10                         @ 11 is the minimum (4KB)
+1:     add     r4, r4, #1                      @ area size *= 2
+       movs    r3, r3, lsr #1
        bne     1b                              @ count not zero r-shift
-       orr     r0, r0, r2, lsl #1              @ the area register value
+       orr     r0, r0, r4, lsl #1              @ the area register value
        orr     r0, r0, #1                      @ set enable bit
        mcr     p15, 0, r0, c6, c1              @ set area 1, RAM
 
        ldr     r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH
-       ldr     r1, =(CONFIG_FLASH_SIZE >> 12)  @ size of FLASH (must be >= 4KB)
-       mov     r2, #10                         @ 11 is the minimum (4KB)
-1:     add     r2, r2, #1                      @ area size *= 2
-       mov     r1, r1, lsr #1
+       ldr     r3, =(CONFIG_FLASH_SIZE >> 12)  @ size of FLASH (must be >= 4KB)
+       cmp     r3, #0
+       moveq   r0, #0
+       beq     2f
+       mov     r4, #10                         @ 11 is the minimum (4KB)
+1:     add     r4, r4, #1                      @ area size *= 2
+       movs    r3, r3, lsr #1
        bne     1b                              @ count not zero r-shift
-       orr     r0, r0, r2, lsl #1              @ the area register value
+       orr     r0, r0, r4, lsl #1              @ the area register value
        orr     r0, r0, #1                      @ set enable bit
-       mcr     p15, 0, r0, c6, c2              @ set area 2, ROM/FLASH
+2:     mcr     p15, 0, r0, c6, c2              @ set area 2, ROM/FLASH
 
        mov     r0, #0x06
        mcr     p15, 0, r0, c2, c0              @ Region 1&2 cacheable
@@ -137,13 +140,14 @@ __arm740_proc_info:
        .long   0x41807400
        .long   0xfffffff0
        .long   0
+       .long   0
        b       __arm740_setup
        .long   cpu_arch_name
        .long   cpu_elf_name
-       .long   HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+       .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_26BIT
        .long   cpu_arm740_name
        .long   arm740_processor_functions
        .long   0
        .long   0
-       .long   v3_cache_fns                    @ cache model
+       .long   v4_cache_fns                    @ cache model
        .size   __arm740_proc_info, . - __arm740_proc_info
index 2c3b942..2556cf1 100644 (file)
@@ -387,7 +387,7 @@ ENTRY(cpu_arm920_set_pte_ext)
 /* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
 .globl cpu_arm920_suspend_size
 .equ   cpu_arm920_suspend_size, 4 * 3
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
 ENTRY(cpu_arm920_do_suspend)
        stmfd   sp!, {r4 - r6, lr}
        mrc     p15, 0, r4, c13, c0, 0  @ PID
index f1803f7..344c8a5 100644 (file)
@@ -402,7 +402,7 @@ ENTRY(cpu_arm926_set_pte_ext)
 /* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
 .globl cpu_arm926_suspend_size
 .equ   cpu_arm926_suspend_size, 4 * 3
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
 ENTRY(cpu_arm926_do_suspend)
        stmfd   sp!, {r4 - r6, lr}
        mrc     p15, 0, r4, c13, c0, 0  @ PID
index 82f9cdc..0b60dd3 100644 (file)
@@ -350,7 +350,7 @@ ENTRY(cpu_mohawk_set_pte_ext)
 
 .globl cpu_mohawk_suspend_size
 .equ   cpu_mohawk_suspend_size, 4 * 6
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
 ENTRY(cpu_mohawk_do_suspend)
        stmfd   sp!, {r4 - r9, lr}
        mrc     p14, 0, r4, c6, c0, 0   @ clock configuration, for turbo mode
index 3aa0da1..d92dfd0 100644 (file)
@@ -172,7 +172,7 @@ ENTRY(cpu_sa1100_set_pte_ext)
 
 .globl cpu_sa1100_suspend_size
 .equ   cpu_sa1100_suspend_size, 4 * 3
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
 ENTRY(cpu_sa1100_do_suspend)
        stmfd   sp!, {r4 - r6, lr}
        mrc     p15, 0, r4, c3, c0, 0           @ domain ID
index 3e6210b..054b491 100644 (file)
@@ -17,7 +17,9 @@
 
 #ifndef MULTI_CPU
 EXPORT_SYMBOL(cpu_dcache_clean_area);
+#ifdef CONFIG_MMU
 EXPORT_SYMBOL(cpu_set_pte_ext);
+#endif
 #else
 EXPORT_SYMBOL(processor);
 #endif
index bcaaa8d..5c07ee4 100644 (file)
@@ -138,7 +138,7 @@ ENTRY(cpu_v6_set_pte_ext)
 /* Suspend/resume support: taken from arch/arm/mach-s3c64xx/sleep.S */
 .globl cpu_v6_suspend_size
 .equ   cpu_v6_suspend_size, 4 * 6
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
 ENTRY(cpu_v6_do_suspend)
        stmfd   sp!, {r4 - r9, lr}
        mrc     p15, 0, r4, c13, c0, 0  @ FCSE/PID
index eb93d64..e8efd83 100644 (file)
@@ -413,7 +413,7 @@ ENTRY(cpu_xsc3_set_pte_ext)
 
 .globl cpu_xsc3_suspend_size
 .equ   cpu_xsc3_suspend_size, 4 * 6
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
 ENTRY(cpu_xsc3_do_suspend)
        stmfd   sp!, {r4 - r9, lr}
        mrc     p14, 0, r4, c6, c0, 0   @ clock configuration, for turbo mode
index 2551036..e766f88 100644 (file)
@@ -528,7 +528,7 @@ ENTRY(cpu_xscale_set_pte_ext)
 
 .globl cpu_xscale_suspend_size
 .equ   cpu_xscale_suspend_size, 4 * 6
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
 ENTRY(cpu_xscale_do_suspend)
        stmfd   sp!, {r4 - r9, lr}
        mrc     p14, 0, r4, c6, c0, 0   @ clock configuration, for turbo mode
similarity index 100%
rename from arch/arm/kernel/tcm.h
rename to arch/arm/mm/tcm.h
index b885322..9ae5072 100644 (file)
 #ifndef __PLAT_S3C_FB_H
 #define __PLAT_S3C_FB_H __FILE__
 
-/* S3C_FB_MAX_WIN
- * Set to the maximum number of windows that any of the supported hardware
- * can use. Since the platform data uses this for an array size, having it
- * set to the maximum of any version of the hardware can do is safe.
- */
-#define S3C_FB_MAX_WIN (5)
-
-/**
- * struct s3c_fb_pd_win - per window setup data
- * @xres     : The window X size.
- * @yres     : The window Y size.
- * @virtual_x: The virtual X size.
- * @virtual_y: The virtual Y size.
- */
-struct s3c_fb_pd_win {
-       unsigned short          default_bpp;
-       unsigned short          max_bpp;
-       unsigned short          xres;
-       unsigned short          yres;
-       unsigned short          virtual_x;
-       unsigned short          virtual_y;
-};
-
-/**
- * struct s3c_fb_platdata -  S3C driver platform specific information
- * @setup_gpio: Setup the external GPIO pins to the right state to transfer
- *             the data from the display system to the connected display
- *             device.
- * @vidcon0: The base vidcon0 values to control the panel data format.
- * @vidcon1: The base vidcon1 values to control the panel data output.
- * @vtiming: Video timing when connected to a RGB type panel.
- * @win: The setup data for each hardware window, or NULL for unused.
- * @display_mode: The LCD output display mode.
- *
- * The platform data supplies the video driver with all the information
- * it requires to work with the display(s) attached to the machine. It
- * controls the initial mode, the number of display windows (0 is always
- * the base framebuffer) that are initialised etc.
- *
- */
-struct s3c_fb_platdata {
-       void    (*setup_gpio)(void);
-
-       struct s3c_fb_pd_win    *win[S3C_FB_MAX_WIN];
-       struct fb_videomode     *vtiming;
-
-       u32                      vidcon0;
-       u32                      vidcon1;
-};
+#include <linux/platform_data/video_s3c.h>
 
 /**
  * s3c_fb_set_platdata() - Setup the FB device with platform data.
index cf60d0a..fc6483f 100644 (file)
@@ -165,6 +165,10 @@ BUILDIO_IOPORT(l, u32)
 #define readw_be                       __raw_readw
 #define readl_be                       __raw_readl
 
+#define writeb_relaxed                 writeb
+#define writew_relaxed                 writew
+#define writel_relaxed                 writel
+
 #define writeb_be                      __raw_writeb
 #define writew_be                      __raw_writew
 #define writel_be                      __raw_writel
index 9a02f71..e7e55a0 100644 (file)
@@ -187,7 +187,7 @@ config IA64_DIG
 
 config IA64_DIG_VTD
        bool "DIG+Intel+IOMMU"
-       select DMAR
+       select INTEL_IOMMU
        select PCI_MSI
 
 config IA64_HP_ZX1
index d2bf1fd..76acbcd 100644 (file)
@@ -106,16 +106,15 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
                return -EFAULT;
 
        {
-               register unsigned long r8 __asm ("r8");
+               register unsigned long r8 __asm ("r8") = 0;
                unsigned long prev;
                __asm__ __volatile__(
                        "       mf;;                                    \n"
-                       "       mov %0=r0                               \n"
                        "       mov ar.ccv=%4;;                         \n"
                        "[1:]   cmpxchg4.acq %1=[%2],%3,ar.ccv          \n"
                        "       .xdata4 \"__ex_table\", 1b-., 2f-.      \n"
                        "[2:]"
-                       : "=r" (r8), "=r" (prev)
+                       : "+r" (r8), "=&r" (prev)
                        : "r" (uaddr), "r" (newval),
                          "rO" ((long) (unsigned) oldval)
                        : "memory");
index 43f96ab..8c70961 100644 (file)
@@ -143,6 +143,7 @@ extern unsigned long __per_cpu_mca[NR_CPUS];
 extern int cpe_vector;
 extern int ia64_cpe_irq;
 extern void ia64_mca_init(void);
+extern void ia64_mca_irq_init(void);
 extern void ia64_mca_cpu_init(void *);
 extern void ia64_os_mca_dispatch(void);
 extern void ia64_os_mca_dispatch_end(void);
index 2e27ef1..2db0a6c 100644 (file)
@@ -67,14 +67,13 @@ extern int paddr_to_nid(unsigned long paddr);
 
 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);
 
 #else /* !CONFIG_NUMA */
 #define map_cpu_to_node(cpu, nid)      do{}while(0)
 #define unmap_cpu_from_node(cpu, nid)  do{}while(0)
-
 #define paddr_to_nid(addr)     0
-
+#define numa_clear_node(cpu)   do { } while (0)
 #endif /* CONFIG_NUMA */
 
 #endif /* _ASM_IA64_NUMA_H */
index c4cd45d..abc6dee 100644 (file)
@@ -90,53 +90,6 @@ ENTRY(fsys_getpid)
        FSYS_RETURN
 END(fsys_getpid)
 
-ENTRY(fsys_getppid)
-       .prologue
-       .altrp b6
-       .body
-       add r17=IA64_TASK_GROUP_LEADER_OFFSET,r16
-       ;;
-       ld8 r17=[r17]                           // r17 = current->group_leader
-       add r9=TI_FLAGS+IA64_TASK_SIZE,r16
-       ;;
-
-       ld4 r9=[r9]
-       add r17=IA64_TASK_REAL_PARENT_OFFSET,r17 // r17 = &current->group_leader->real_parent
-       ;;
-       and r9=TIF_ALLWORK_MASK,r9
-
-1:     ld8 r18=[r17]                           // r18 = current->group_leader->real_parent
-       ;;
-       cmp.ne p8,p0=0,r9
-       add r8=IA64_TASK_TGID_OFFSET,r18        // r8 = &current->group_leader->real_parent->tgid
-       ;;
-
-       /*
-        * The .acq is needed to ensure that the read of tgid has returned its data before
-        * we re-check "real_parent".
-        */
-       ld4.acq r8=[r8]                         // r8 = current->group_leader->real_parent->tgid
-#ifdef CONFIG_SMP
-       /*
-        * Re-read current->group_leader->real_parent.
-        */
-       ld8 r19=[r17]                           // r19 = current->group_leader->real_parent
-(p8)   br.spnt.many fsys_fallback_syscall
-       ;;
-       cmp.ne p6,p0=r18,r19                    // did real_parent change?
-       mov r19=0                       // i must not leak kernel bits...
-(p6)   br.cond.spnt.few 1b                     // yes -> redo the read of tgid and the check
-       ;;
-       mov r17=0                       // i must not leak kernel bits...
-       mov r18=0                       // i must not leak kernel bits...
-#else
-       mov r17=0                       // i must not leak kernel bits...
-       mov r18=0                       // i must not leak kernel bits...
-       mov r19=0                       // i must not leak kernel bits...
-#endif
-       FSYS_RETURN
-END(fsys_getppid)
-
 ENTRY(fsys_set_tid_address)
        .prologue
        .altrp b6
@@ -614,7 +567,7 @@ paravirt_fsyscall_table:
        data8 0                         // chown
        data8 0                         // lseek                // 1040
        data8 fsys_getpid               // getpid
-       data8 fsys_getppid              // getppid
+       data8 0                         // getppid
        data8 0                         // mount
        data8 0                         // umount
        data8 0                         // setuid               // 1045
index ee33c3a..19f107b 100644 (file)
@@ -76,7 +76,7 @@
  *     PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ
  *
  * Note: The term "IRQ" is loosely used everywhere in Linux kernel to
- * describeinterrupts.  Now we use "IRQ" only for Linux IRQ's.  ISA IRQ
+ * describe interrupts.  Now we use "IRQ" only for Linux IRQ's.  ISA IRQ
  * (isa_irq) is the only exception in this source code.
  */
 
@@ -1010,6 +1010,26 @@ iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
        return 0;
 }
 
+static int
+iosapic_delete_rte(unsigned int irq, unsigned int gsi)
+{
+       struct iosapic_rte_info *rte, *temp;
+
+       list_for_each_entry_safe(rte, temp, &iosapic_intr_info[irq].rtes,
+                                                               rte_list) {
+               if (rte->iosapic->gsi_base + rte->rte_index == gsi) {
+                       if (rte->refcnt)
+                               return -EBUSY;
+
+                       list_del(&rte->rte_list);
+                       kfree(rte);
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
 int iosapic_init(unsigned long phys_addr, unsigned int gsi_base)
 {
        int num_rte, err, index;
@@ -1069,7 +1089,7 @@ int iosapic_init(unsigned long phys_addr, unsigned int gsi_base)
 
 int iosapic_remove(unsigned int gsi_base)
 {
-       int index, err = 0;
+       int i, irq, index, err = 0;
        unsigned long flags;
 
        spin_lock_irqsave(&iosapic_lock, flags);
@@ -1087,6 +1107,16 @@ int iosapic_remove(unsigned int gsi_base)
                goto out;
        }
 
+       for (i = gsi_base; i < gsi_base + iosapic_lists[index].num_rte; i++) {
+               irq = __gsi_to_irq(i);
+               if (irq < 0)
+                       continue;
+
+               err = iosapic_delete_rte(irq, i);
+               if (err)
+                       goto out;
+       }
+
        iounmap(iosapic_lists[index].addr);
        iosapic_free(index);
  out:
index ad69606..f2c4182 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 
+#include <asm/mca.h>
+
 /*
  * 'what should we do if we get a hw irq event on an illegal vector'.
  * each architecture has to answer this themselves.
@@ -83,6 +85,12 @@ bool is_affinity_mask_valid(const struct cpumask *cpumask)
 
 #endif /* CONFIG_SMP */
 
+int __init arch_early_irq_init(void)
+{
+       ia64_mca_irq_init();
+       return 0;
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 unsigned int vectors_in_migration[NR_IRQS];
 
index 65bf9cd..d7396db 100644 (file)
@@ -2074,22 +2074,16 @@ ia64_mca_init(void)
        printk(KERN_INFO "MCA related initialization done\n");
 }
 
+
 /*
- * ia64_mca_late_init
- *
- *     Opportunity to setup things that require initialization later
- *     than ia64_mca_init.  Setup a timer to poll for CPEs if the
- *     platform doesn't support an interrupt driven mechanism.
- *
- *  Inputs  :   None
- *  Outputs :   Status
+ * These pieces cannot be done in ia64_mca_init() because it is called before
+ * early_irq_init() which would wipe out our percpu irq registrations. But we
+ * cannot leave them until ia64_mca_late_init() because by then all the other
+ * processors have been brought online and have set their own CMC vectors to
+ * point at a non-existant action. Called from arch_early_irq_init().
  */
-static int __init
-ia64_mca_late_init(void)
+void __init ia64_mca_irq_init(void)
 {
-       if (!mca_init)
-               return 0;
-
        /*
         *  Configure the CMCI/P vector and handler. Interrupts for CMC are
         *  per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c).
@@ -2108,6 +2102,23 @@ ia64_mca_late_init(void)
        /* Setup the CPEI/P handler */
        register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
 #endif
+}
+
+/*
+ * ia64_mca_late_init
+ *
+ *     Opportunity to setup things that require initialization later
+ *     than ia64_mca_init.  Setup a timer to poll for CPEs if the
+ *     platform doesn't support an interrupt driven mechanism.
+ *
+ *  Inputs  :   None
+ *  Outputs :   Status
+ */
+static int __init
+ia64_mca_late_init(void)
+{
+       if (!mca_init)
+               return 0;
 
        register_hotcpu_notifier(&mca_cpu_notifier);
 
index 9392e02..94f8bf7 100644 (file)
@@ -349,7 +349,7 @@ init_record_index_pools(void)
 
        /* - 3 - */
        slidx_pool.max_idx = (rec_max_size/sect_min_size) * 2 + 1;
-       slidx_pool.buffer = (slidx_list_t *)
+       slidx_pool.buffer =
                kmalloc(slidx_pool.max_idx * sizeof(slidx_list_t), GFP_KERNEL);
 
        return slidx_pool.buffer ? 0 : -ENOMEM;
index 4332f7e..a7869f8 100644 (file)
@@ -256,7 +256,7 @@ u64 guest_vhpt_lookup(u64 iha, u64 *pte)
                        "srlz.d;;"
                        "ssm psr.i;;"
                        "srlz.d;;"
-                       : "=r"(ret) : "r"(iha), "r"(pte):"memory");
+                       : "=&r"(ret) : "r"(iha), "r"(pte) : "memory");
 
        return ret;
 }
index 3dccdd8..43964cd 100644 (file)
@@ -16,7 +16,7 @@
 #include <asm/meminit.h>
 
 static inline void __iomem *
-__ioremap (unsigned long phys_addr)
+__ioremap_uc(unsigned long phys_addr)
 {
        return (void __iomem *) (__IA64_UNCACHED_OFFSET | phys_addr);
 }
@@ -24,7 +24,11 @@ __ioremap (unsigned long phys_addr)
 void __iomem *
 early_ioremap (unsigned long phys_addr, unsigned long size)
 {
-       return __ioremap(phys_addr);
+       u64 attr;
+       attr = kern_mem_attribute(phys_addr, size);
+       if (attr & EFI_MEMORY_WB)
+               return (void __iomem *) phys_to_virt(phys_addr);
+       return __ioremap_uc(phys_addr);
 }
 
 void __iomem *
@@ -47,7 +51,7 @@ ioremap (unsigned long phys_addr, unsigned long size)
        if (attr & EFI_MEMORY_WB)
                return (void __iomem *) phys_to_virt(phys_addr);
        else if (attr & EFI_MEMORY_UC)
-               return __ioremap(phys_addr);
+               return __ioremap_uc(phys_addr);
 
        /*
         * Some chipsets don't support UC access to memory.  If
@@ -93,7 +97,7 @@ ioremap (unsigned long phys_addr, unsigned long size)
                return (void __iomem *) (offset + (char __iomem *)addr);
        }
 
-       return __ioremap(phys_addr);
+       return __ioremap_uc(phys_addr);
 }
 EXPORT_SYMBOL(ioremap);
 
@@ -103,7 +107,7 @@ ioremap_nocache (unsigned long phys_addr, unsigned long size)
        if (kern_mem_attribute(phys_addr, size) & EFI_MEMORY_WB)
                return NULL;
 
-       return __ioremap(phys_addr);
+       return __ioremap_uc(phys_addr);
 }
 EXPORT_SYMBOL(ioremap_nocache);
 
index 3efea7d..def782e 100644 (file)
@@ -73,6 +73,11 @@ int __meminit __early_pfn_to_nid(unsigned long pfn)
        return -1;
 }
 
+void __cpuinit numa_clear_node(int cpu)
+{
+       unmap_cpu_from_node(cpu, NUMA_NO_NODE);
+}
+
 #ifdef CONFIG_MEMORY_HOTPLUG
 /*
  *  SRAT information is stored in node_memblk[], then we can use SRAT
index 60532ab..de1474f 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/pci-acpi.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
@@ -458,6 +459,16 @@ void pcibios_fixup_bus(struct pci_bus *b)
        platform_pci_fixup_bus(b);
 }
 
+void pcibios_add_bus(struct pci_bus *bus)
+{
+       acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+       acpi_pci_remove_bus(bus);
+}
+
 void pcibios_set_master (struct pci_dev *dev)
 {
        /* No special bus mastering setup handling */
index 14c1711..e35f648 100644 (file)
@@ -490,11 +490,14 @@ static int __init tiocx_init(void)
 {
        cnodeid_t cnodeid;
        int found_tiocx_device = 0;
+       int err;
 
        if (!ia64_platform_is("sn2"))
                return 0;
 
-       bus_register(&tiocx_bus_type);
+       err = bus_register(&tiocx_bus_type);
+       if (err)
+               return err;
 
        for (cnodeid = 0; cnodeid < num_cnodes; cnodeid++) {
                nasid_t nasid;
index 99fc547..eab99e5 100644 (file)
@@ -31,7 +31,7 @@
 #define PAGE_SHIFT     16
 #endif
 #define PAGE_SIZE      (_AC(1,UL) << PAGE_SHIFT)
-#define PAGE_MASK      (~(PAGE_SIZE - 1))
+#define PAGE_MASK      (~((1 << PAGE_SHIFT) - 1))
 
 #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
 #define HPAGE_SHIFT    (PAGE_SHIFT + PAGE_SHIFT - 3)
index 0872f12..594e60d 100644 (file)
@@ -115,7 +115,6 @@ static void pcibios_scanbus(struct pci_controller *hose)
                        pci_bus_assign_resources(bus);
                        pci_enable_bridges(bus);
                }
-               bus->dev.of_node = hose->of_node;
        }
 }
 
@@ -169,6 +168,13 @@ void pci_load_of_ranges(struct pci_controller *hose, struct device_node *node)
                }
        }
 }
+
+struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
+{
+       struct pci_controller *hose = bus->sysdata;
+
+       return of_node_get(hose->of_node);
+}
 #endif
 
 static DEFINE_MUTEX(pci_scan_mutex);
index 01d95e2..113e282 100644 (file)
@@ -65,8 +65,10 @@ ifndef CONFIG_FUNCTION_TRACER
 endif
 
 # Use long jumps instead of long branches (needed if your linker fails to
-# link a too big vmlinux executable)
-cflags-$(CONFIG_MLONGCALLS)    += -mlong-calls
+# link a too big vmlinux executable). Not enabled for building modules.
+ifdef CONFIG_MLONGCALLS
+KBUILD_CFLAGS_KERNEL += -mlong-calls
+endif
 
 # select which processor to optimise for
 cflags-$(CONFIG_PA7100)                += -march=1.1 -mschedule=7100
index 79f694f..f0e2784 100644 (file)
@@ -140,7 +140,10 @@ static inline void *kmap(struct page *page)
        return page_address(page);
 }
 
-#define kunmap(page)                   kunmap_parisc(page_address(page))
+static inline void kunmap(struct page *page)
+{
+       kunmap_parisc(page_address(page));
+}
 
 static inline void *kmap_atomic(struct page *page)
 {
index 7df49fa..1e40d7f 100644 (file)
@@ -16,6 +16,8 @@
 #include <asm/processor.h>
 #include <asm/cache.h>
 
+extern spinlock_t pa_dbit_lock;
+
 /*
  * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
  * memory.  For the return value to be meaningful, ADDR must be >=
@@ -44,8 +46,11 @@ extern void purge_tlb_entries(struct mm_struct *, unsigned long);
 
 #define set_pte_at(mm, addr, ptep, pteval)                      \
        do {                                                    \
+               unsigned long flags;                            \
+               spin_lock_irqsave(&pa_dbit_lock, flags);        \
                set_pte(ptep, pteval);                          \
                purge_tlb_entries(mm, addr);                    \
+               spin_unlock_irqrestore(&pa_dbit_lock, flags);   \
        } while (0)
 
 #endif /* !__ASSEMBLY__ */
@@ -435,48 +440,46 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
 
 static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
-#ifdef CONFIG_SMP
+       pte_t pte;
+       unsigned long flags;
+
        if (!pte_young(*ptep))
                return 0;
-       return test_and_clear_bit(xlate_pabit(_PAGE_ACCESSED_BIT), &pte_val(*ptep));
-#else
-       pte_t pte = *ptep;
-       if (!pte_young(pte))
+
+       spin_lock_irqsave(&pa_dbit_lock, flags);
+       pte = *ptep;
+       if (!pte_young(pte)) {
+               spin_unlock_irqrestore(&pa_dbit_lock, flags);
                return 0;
-       set_pte_at(vma->vm_mm, addr, ptep, pte_mkold(pte));
+       }
+       set_pte(ptep, pte_mkold(pte));
+       purge_tlb_entries(vma->vm_mm, addr);
+       spin_unlock_irqrestore(&pa_dbit_lock, flags);
        return 1;
-#endif
 }
 
-extern spinlock_t pa_dbit_lock;
-
 struct mm_struct;
 static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
        pte_t old_pte;
+       unsigned long flags;
 
-       spin_lock(&pa_dbit_lock);
+       spin_lock_irqsave(&pa_dbit_lock, flags);
        old_pte = *ptep;
        pte_clear(mm,addr,ptep);
-       spin_unlock(&pa_dbit_lock);
+       purge_tlb_entries(mm, addr);
+       spin_unlock_irqrestore(&pa_dbit_lock, flags);
 
        return old_pte;
 }
 
 static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
-#ifdef CONFIG_SMP
-       unsigned long new, old;
-
-       do {
-               old = pte_val(*ptep);
-               new = pte_val(pte_wrprotect(__pte (old)));
-       } while (cmpxchg((unsigned long *) ptep, old, new) != old);
+       unsigned long flags;
+       spin_lock_irqsave(&pa_dbit_lock, flags);
+       set_pte(ptep, pte_wrprotect(*ptep));
        purge_tlb_entries(mm, addr);
-#else
-       pte_t old_pte = *ptep;
-       set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
-#endif
+       spin_unlock_irqrestore(&pa_dbit_lock, flags);
 }
 
 #define pte_same(A,B)  (pte_val(A) == pte_val(B))
index 4ba2c93..e0a8235 100644 (file)
@@ -181,30 +181,24 @@ struct exception_data {
 #if !defined(CONFIG_64BIT)
 
 #define __put_kernel_asm64(__val,ptr) do {                 \
-       u64 __val64 = (u64)(__val);                         \
-       u32 hi = (__val64) >> 32;                           \
-       u32 lo = (__val64) & 0xffffffff;                    \
        __asm__ __volatile__ (                              \
                "\n1:\tstw %2,0(%1)"                        \
-               "\n2:\tstw %3,4(%1)\n\t"                    \
+               "\n2:\tstw %R2,4(%1)\n\t"                   \
                ASM_EXCEPTIONTABLE_ENTRY(1b,fixup_put_user_skip_2)\
                ASM_EXCEPTIONTABLE_ENTRY(2b,fixup_put_user_skip_1)\
                : "=r"(__pu_err)                            \
-               : "r"(ptr), "r"(hi), "r"(lo), "0"(__pu_err) \
+               : "r"(ptr), "r"(__val), "0"(__pu_err) \
                : "r1");                                    \
 } while (0)
 
 #define __put_user_asm64(__val,ptr) do {                   \
-       u64 __val64 = (u64)(__val);                         \
-       u32 hi = (__val64) >> 32;                           \
-       u32 lo = (__val64) & 0xffffffff;                    \
        __asm__ __volatile__ (                              \
                "\n1:\tstw %2,0(%%sr3,%1)"                  \
-               "\n2:\tstw %3,4(%%sr3,%1)\n\t"              \
+               "\n2:\tstw %R2,4(%%sr3,%1)\n\t"             \
                ASM_EXCEPTIONTABLE_ENTRY(1b,fixup_put_user_skip_2)\
                ASM_EXCEPTIONTABLE_ENTRY(2b,fixup_put_user_skip_1)\
                : "=r"(__pu_err)                            \
-               : "r"(ptr), "r"(hi), "r"(lo), "0"(__pu_err) \
+               : "r"(ptr), "r"(__val), "0"(__pu_err) \
                : "r1");                                    \
 } while (0)
 
index 4b12890..83ded26 100644 (file)
@@ -421,14 +421,11 @@ void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
        /* Note: purge_tlb_entries can be called at startup with
           no context.  */
 
-       /* Disable preemption while we play with %sr1.  */
-       preempt_disable();
-       mtsp(mm->context, 1);
        purge_tlb_start(flags);
+       mtsp(mm->context, 1);
        pdtlb(addr);
        pitlb(addr);
        purge_tlb_end(flags);
-       preempt_enable();
 }
 EXPORT_SYMBOL(purge_tlb_entries);
 
index 6795dc6..568b2c6 100644 (file)
@@ -120,11 +120,13 @@ extern void __ashrdi3(void);
 extern void __ashldi3(void);
 extern void __lshrdi3(void);
 extern void __muldi3(void);
+extern void __ucmpdi2(void);
 
 EXPORT_SYMBOL(__ashrdi3);
 EXPORT_SYMBOL(__ashldi3);
 EXPORT_SYMBOL(__lshrdi3);
 EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__ucmpdi2);
 
 asmlinkage void * __canonicalize_funcptr_for_compare(void *);
 EXPORT_SYMBOL(__canonicalize_funcptr_for_compare);
index 5f2e690..5651536 100644 (file)
@@ -2,6 +2,7 @@
 # Makefile for parisc-specific library files
 #
 
-lib-y  := lusercopy.o bitops.o checksum.o io.o memset.o fixup.o memcpy.o
+lib-y  := lusercopy.o bitops.o checksum.o io.o memset.o fixup.o memcpy.o \
+          ucmpdi2.o
 
 obj-y  := iomap.o
diff --git a/arch/parisc/lib/ucmpdi2.c b/arch/parisc/lib/ucmpdi2.c
new file mode 100644 (file)
index 0000000..149c016
--- /dev/null
@@ -0,0 +1,25 @@
+#include <linux/module.h>
+
+union ull_union {
+       unsigned long long ull;
+       struct {
+               unsigned int high;
+               unsigned int low;
+       } ui;
+};
+
+int __ucmpdi2(unsigned long long a, unsigned long long b)
+{
+       union ull_union au = {.ull = a};
+       union ull_union bu = {.ull = b};
+
+       if (au.ui.high < bu.ui.high)
+               return 0;
+       else if (au.ui.high > bu.ui.high)
+               return 2;
+       if (au.ui.low < bu.ui.low)
+               return 0;
+       else if (au.ui.low > bu.ui.low)
+               return 2;
+       return 1;
+}
index 256c5bf..04d69c4 100644 (file)
@@ -304,7 +304,7 @@ syscall_exit_work:
        subi    r12,r12,TI_FLAGS
 
 4:     /* Anything else left to do? */
-       SET_DEFAULT_THREAD_PPR(r3, r9)          /* Set thread.ppr = 3 */
+       SET_DEFAULT_THREAD_PPR(r3, r10)         /* Set thread.ppr = 3 */
        andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
        beq     .ret_from_except_lite
 
@@ -657,7 +657,7 @@ resume_kernel:
        /* Clear _TIF_EMULATE_STACK_STORE flag */
        lis     r11,_TIF_EMULATE_STACK_STORE@h
        addi    r5,r9,TI_FLAGS
-       ldarx   r4,0,r5
+0:     ldarx   r4,0,r5
        andc    r4,r4,r11
        stdcx.  r4,0,r5
        bne-    0b
index 59dd545..16e77a8 100644 (file)
@@ -555,10 +555,12 @@ static inline void tm_recheckpoint_new_task(struct task_struct *new)
                new->thread.regs->msr |=
                        (MSR_FP | new->thread.fpexc_mode);
        }
+#ifdef CONFIG_ALTIVEC
        if (msr & MSR_VEC) {
                do_load_up_transact_altivec(&new->thread);
                new->thread.regs->msr |= MSR_VEC;
        }
+#endif
        /* We may as well turn on VSX too since all the state is restored now */
        if (msr & MSR_VSX)
                new->thread.regs->msr |= MSR_VSX;
index 3acb28e..95068bf 100644 (file)
@@ -866,10 +866,12 @@ static long restore_tm_user_regs(struct pt_regs *regs,
                do_load_up_transact_fpu(&current->thread);
                regs->msr |= (MSR_FP | current->thread.fpexc_mode);
        }
+#ifdef CONFIG_ALTIVEC
        if (msr & MSR_VEC) {
                do_load_up_transact_altivec(&current->thread);
                regs->msr |= MSR_VEC;
        }
+#endif
 
        return 0;
 }
index 995f854..c179428 100644 (file)
@@ -522,10 +522,12 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
                do_load_up_transact_fpu(&current->thread);
                regs->msr |= (MSR_FP | current->thread.fpexc_mode);
        }
+#ifdef CONFIG_ALTIVEC
        if (msr & MSR_VEC) {
                do_load_up_transact_altivec(&current->thread);
                regs->msr |= MSR_VEC;
        }
+#endif
 
        return err;
 }
index 84dbace..2da67e7 100644 (file)
@@ -309,6 +309,7 @@ _GLOBAL(tm_recheckpoint)
        or      r5, r6, r5                      /* Set MSR.FP+.VSX/.VEC */
        mtmsr   r5
 
+#ifdef CONFIG_ALTIVEC
        /* FP and VEC registers:  These are recheckpointed from thread.fpr[]
         * and thread.vr[] respectively.  The thread.transact_fpr[] version
         * is more modern, and will be loaded subsequently by any FPUnavailable
@@ -323,6 +324,7 @@ _GLOBAL(tm_recheckpoint)
        REST_32VRS(0, r5, r3)                   /* r5 scratch, r3 THREAD ptr */
        ld      r5, THREAD_VRSAVE(r3)
        mtspr   SPRN_VRSAVE, r5
+#endif
 
 dont_restore_vec:
        andi.   r0, r4, MSR_FP
index 41cefd4..33db48a 100644 (file)
 #define E500_PID_NUM   3
 #define E500_TLB_NUM   2
 
-#define E500_TLB_VALID 1
-#define E500_TLB_BITMAP 2
+/* entry is mapped somewhere in host TLB */
+#define E500_TLB_VALID         (1 << 0)
+/* TLB1 entry is mapped by host TLB1, tracked by bitmaps */
+#define E500_TLB_BITMAP                (1 << 1)
+/* TLB1 entry is mapped by host TLB0 */
 #define E500_TLB_TLB0          (1 << 2)
 
 struct tlbe_ref {
-       pfn_t pfn;
-       unsigned int flags; /* E500_TLB_* */
+       pfn_t pfn;              /* valid only for TLB0, except briefly */
+       unsigned int flags;     /* E500_TLB_* */
 };
 
 struct tlbe_priv {
-       struct tlbe_ref ref; /* TLB0 only -- TLB1 uses tlb_refs */
+       struct tlbe_ref ref;
 };
 
 #ifdef CONFIG_KVM_E500V2
@@ -63,17 +66,6 @@ struct kvmppc_vcpu_e500 {
 
        unsigned int gtlb_nv[E500_TLB_NUM];
 
-       /*
-        * information associated with each host TLB entry --
-        * TLB1 only for now.  If/when guest TLB1 entries can be
-        * mapped with host TLB0, this will be used for that too.
-        *
-        * We don't want to use this for guest TLB0 because then we'd
-        * have the overhead of doing the translation again even if
-        * the entry is still in the guest TLB (e.g. we swapped out
-        * and back, and our host TLB entries got evicted).
-        */
-       struct tlbe_ref *tlb_refs[E500_TLB_NUM];
        unsigned int host_tlb1_nv;
 
        u32 svr;
index a222edf..1c6a9d7 100644 (file)
@@ -193,8 +193,11 @@ void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
        struct tlbe_ref *ref = &vcpu_e500->gtlb_priv[tlbsel][esel].ref;
 
        /* Don't bother with unmapped entries */
-       if (!(ref->flags & E500_TLB_VALID))
-               return;
+       if (!(ref->flags & E500_TLB_VALID)) {
+               WARN(ref->flags & (E500_TLB_BITMAP | E500_TLB_TLB0),
+                    "%s: flags %x\n", __func__, ref->flags);
+               WARN_ON(tlbsel == 1 && vcpu_e500->g2h_tlb1_map[esel]);
+       }
 
        if (tlbsel == 1 && ref->flags & E500_TLB_BITMAP) {
                u64 tmp = vcpu_e500->g2h_tlb1_map[esel];
@@ -248,7 +251,7 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
                                         pfn_t pfn)
 {
        ref->pfn = pfn;
-       ref->flags = E500_TLB_VALID;
+       ref->flags |= E500_TLB_VALID;
 
        if (tlbe_is_writable(gtlbe))
                kvm_set_pfn_dirty(pfn);
@@ -257,6 +260,7 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
 static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
 {
        if (ref->flags & E500_TLB_VALID) {
+               /* FIXME: don't log bogus pfn for TLB1 */
                trace_kvm_booke206_ref_release(ref->pfn, ref->flags);
                ref->flags = 0;
        }
@@ -274,36 +278,23 @@ static void clear_tlb1_bitmap(struct kvmppc_vcpu_e500 *vcpu_e500)
 
 static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
-       int tlbsel = 0;
-       int i;
-
-       for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) {
-               struct tlbe_ref *ref =
-                       &vcpu_e500->gtlb_priv[tlbsel][i].ref;
-               kvmppc_e500_ref_release(ref);
-       }
-}
-
-static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500)
-{
-       int stlbsel = 1;
+       int tlbsel;
        int i;
 
-       kvmppc_e500_tlbil_all(vcpu_e500);
-
-       for (i = 0; i < host_tlb_params[stlbsel].entries; i++) {
-               struct tlbe_ref *ref =
-                       &vcpu_e500->tlb_refs[stlbsel][i];
-               kvmppc_e500_ref_release(ref);
+       for (tlbsel = 0; tlbsel <= 1; tlbsel++) {
+               for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) {
+                       struct tlbe_ref *ref =
+                               &vcpu_e500->gtlb_priv[tlbsel][i].ref;
+                       kvmppc_e500_ref_release(ref);
+               }
        }
-
-       clear_tlb_privs(vcpu_e500);
 }
 
 void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
-       clear_tlb_refs(vcpu_e500);
+       kvmppc_e500_tlbil_all(vcpu_e500);
+       clear_tlb_privs(vcpu_e500);
        clear_tlb1_bitmap(vcpu_e500);
 }
 
@@ -458,8 +449,6 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
                gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
        }
 
-       /* Drop old ref and setup new one. */
-       kvmppc_e500_ref_release(ref);
        kvmppc_e500_ref_setup(ref, gtlbe, pfn);
 
        kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize,
@@ -507,14 +496,15 @@ static int kvmppc_e500_tlb1_map_tlb1(struct kvmppc_vcpu_e500 *vcpu_e500,
        if (unlikely(vcpu_e500->host_tlb1_nv >= tlb1_max_shadow_size()))
                vcpu_e500->host_tlb1_nv = 0;
 
-       vcpu_e500->tlb_refs[1][sesel] = *ref;
-       vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << sesel;
-       vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP;
        if (vcpu_e500->h2g_tlb1_rmap[sesel]) {
-               unsigned int idx = vcpu_e500->h2g_tlb1_rmap[sesel];
+               unsigned int idx = vcpu_e500->h2g_tlb1_rmap[sesel] - 1;
                vcpu_e500->g2h_tlb1_map[idx] &= ~(1ULL << sesel);
        }
-       vcpu_e500->h2g_tlb1_rmap[sesel] = esel;
+
+       vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP;
+       vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << sesel;
+       vcpu_e500->h2g_tlb1_rmap[sesel] = esel + 1;
+       WARN_ON(!(ref->flags & E500_TLB_VALID));
 
        return sesel;
 }
@@ -526,13 +516,12 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500,
                u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,
                struct kvm_book3e_206_tlb_entry *stlbe, int esel)
 {
-       struct tlbe_ref ref;
+       struct tlbe_ref *ref = &vcpu_e500->gtlb_priv[1][esel].ref;
        int sesel;
        int r;
 
-       ref.flags = 0;
        r = kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe,
-                                  &ref);
+                                  ref);
        if (r)
                return r;
 
@@ -544,7 +533,7 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500,
        }
 
        /* Otherwise map into TLB1 */
-       sesel = kvmppc_e500_tlb1_map_tlb1(vcpu_e500, &ref, esel);
+       sesel = kvmppc_e500_tlb1_map_tlb1(vcpu_e500, ref, esel);
        write_stlbe(vcpu_e500, gtlbe, stlbe, 1, sesel);
 
        return 0;
@@ -565,7 +554,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
        case 0:
                priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
 
-               /* Triggers after clear_tlb_refs or on initial mapping */
+               /* Triggers after clear_tlb_privs or on initial mapping */
                if (!(priv->ref.flags & E500_TLB_VALID)) {
                        kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);
                } else {
@@ -665,35 +654,16 @@ int e500_mmu_host_init(struct kvmppc_vcpu_e500 *vcpu_e500)
                host_tlb_params[0].entries / host_tlb_params[0].ways;
        host_tlb_params[1].sets = 1;
 
-       vcpu_e500->tlb_refs[0] =
-               kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[0].entries,
-                       GFP_KERNEL);
-       if (!vcpu_e500->tlb_refs[0])
-               goto err;
-
-       vcpu_e500->tlb_refs[1] =
-               kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[1].entries,
-                       GFP_KERNEL);
-       if (!vcpu_e500->tlb_refs[1])
-               goto err;
-
        vcpu_e500->h2g_tlb1_rmap = kzalloc(sizeof(unsigned int) *
                                           host_tlb_params[1].entries,
                                           GFP_KERNEL);
        if (!vcpu_e500->h2g_tlb1_rmap)
-               goto err;
+               return -EINVAL;
 
        return 0;
-
-err:
-       kfree(vcpu_e500->tlb_refs[0]);
-       kfree(vcpu_e500->tlb_refs[1]);
-       return -EINVAL;
 }
 
 void e500_mmu_host_uninit(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
        kfree(vcpu_e500->h2g_tlb1_rmap);
-       kfree(vcpu_e500->tlb_refs[0]);
-       kfree(vcpu_e500->tlb_refs[1]);
 }
index 1f89d26..2f4baa0 100644 (file)
@@ -108,6 +108,8 @@ void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr)
 {
 }
 
+static DEFINE_PER_CPU(struct kvm_vcpu *, last_vcpu_on_cpu);
+
 void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
@@ -136,8 +138,11 @@ void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        mtspr(SPRN_GDEAR, vcpu->arch.shared->dar);
        mtspr(SPRN_GESR, vcpu->arch.shared->esr);
 
-       if (vcpu->arch.oldpir != mfspr(SPRN_PIR))
+       if (vcpu->arch.oldpir != mfspr(SPRN_PIR) ||
+           __get_cpu_var(last_vcpu_on_cpu) != vcpu) {
                kvmppc_e500_tlbil_all(vcpu_e500);
+               __get_cpu_var(last_vcpu_on_cpu) = vcpu;
+       }
 
        kvmppc_load_guest_fp(vcpu);
 }
index eb8fb62..bda6ba6 100644 (file)
@@ -375,19 +375,6 @@ config PACK_STACK
 
          Say Y if you are unsure.
 
-config SMALL_STACK
-       def_bool n
-       prompt "Use 8kb for kernel stack instead of 16kb"
-       depends on PACK_STACK && 64BIT && !LOCKDEP
-       help
-         If you say Y here and the compiler supports the -mkernel-backchain
-         option the kernel will use a smaller kernel stack size. The reduced
-         size is 8kb instead of 16kb. This allows to run more threads on a
-         system and reduces the pressure on the memory management for higher
-         order page allocations.
-
-         Say N if you are unsure.
-
 config CHECK_STACK
        def_bool y
        prompt "Detect kernel stack overflow"
index 7e3ce78..a7d68a4 100644 (file)
@@ -55,22 +55,12 @@ cflags-$(CONFIG_FRAME_POINTER) += -fno-optimize-sibling-calls
 ifeq ($(call cc-option-yn,-mkernel-backchain),y)
 cflags-$(CONFIG_PACK_STACK)  += -mkernel-backchain -D__PACK_STACK
 aflags-$(CONFIG_PACK_STACK)  += -D__PACK_STACK
-cflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
-aflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
-ifdef CONFIG_SMALL_STACK
-STACK_SIZE := $(shell echo $$(($(STACK_SIZE)/2)) )
-endif
 endif
 
 # new style option for packed stacks
 ifeq ($(call cc-option-yn,-mpacked-stack),y)
 cflags-$(CONFIG_PACK_STACK)  += -mpacked-stack -D__PACK_STACK
 aflags-$(CONFIG_PACK_STACK)  += -D__PACK_STACK
-cflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
-aflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
-ifdef CONFIG_SMALL_STACK
-STACK_SIZE := $(shell echo $$(($(STACK_SIZE)/2)) )
-endif
 endif
 
 ifeq ($(call cc-option-yn,-mstack-size=8192 -mstack-guard=128),y)
index 9fd4a40..bb5dd49 100644 (file)
@@ -105,9 +105,7 @@ void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df)
 int hypfs_dbfs_init(void)
 {
        dbfs_dir = debugfs_create_dir("s390_hypfs", NULL);
-       if (IS_ERR(dbfs_dir))
-               return PTR_ERR(dbfs_dir);
-       return 0;
+       return PTR_RET(dbfs_dir);
 }
 
 void hypfs_dbfs_exit(void)
index 1542293..4d8604e 100644 (file)
@@ -61,8 +61,6 @@ extern const char _sb_findmap[];
 
 #ifndef CONFIG_64BIT
 
-#define __BITOPS_ALIGN         3
-#define __BITOPS_WORDSIZE      32
 #define __BITOPS_OR            "or"
 #define __BITOPS_AND           "nr"
 #define __BITOPS_XOR           "xr"
@@ -81,8 +79,6 @@ extern const char _sb_findmap[];
 
 #else /* CONFIG_64BIT */
 
-#define __BITOPS_ALIGN         7
-#define __BITOPS_WORDSIZE      64
 #define __BITOPS_OR            "ogr"
 #define __BITOPS_AND           "ngr"
 #define __BITOPS_XOR           "xgr"
@@ -101,8 +97,7 @@ extern const char _sb_findmap[];
 
 #endif /* CONFIG_64BIT */
 
-#define __BITOPS_WORDS(bits) (((bits)+__BITOPS_WORDSIZE-1)/__BITOPS_WORDSIZE)
-#define __BITOPS_BARRIER() asm volatile("" : : : "memory")
+#define __BITOPS_WORDS(bits) (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG)
 
 #ifdef CONFIG_SMP
 /*
@@ -114,9 +109,9 @@ static inline void set_bit_cs(unsigned long nr, volatile unsigned long *ptr)
 
        addr = (unsigned long) ptr;
        /* calculate address for CS */
-       addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
+       addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
        /* make OR mask */
-       mask = 1UL << (nr & (__BITOPS_WORDSIZE - 1));
+       mask = 1UL << (nr & (BITS_PER_LONG - 1));
        /* Do the atomic update. */
        __BITOPS_LOOP(old, new, addr, mask, __BITOPS_OR);
 }
@@ -130,9 +125,9 @@ static inline void clear_bit_cs(unsigned long nr, volatile unsigned long *ptr)
 
        addr = (unsigned long) ptr;
        /* calculate address for CS */
-       addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
+       addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
        /* make AND mask */
-       mask = ~(1UL << (nr & (__BITOPS_WORDSIZE - 1)));
+       mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
        /* Do the atomic update. */
        __BITOPS_LOOP(old, new, addr, mask, __BITOPS_AND);
 }
@@ -146,9 +141,9 @@ static inline void change_bit_cs(unsigned long nr, volatile unsigned long *ptr)
 
        addr = (unsigned long) ptr;
        /* calculate address for CS */
-       addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
+       addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
        /* make XOR mask */
-       mask = 1UL << (nr & (__BITOPS_WORDSIZE - 1));
+       mask = 1UL << (nr & (BITS_PER_LONG - 1));
        /* Do the atomic update. */
        __BITOPS_LOOP(old, new, addr, mask, __BITOPS_XOR);
 }
@@ -163,12 +158,12 @@ test_and_set_bit_cs(unsigned long nr, volatile unsigned long *ptr)
 
        addr = (unsigned long) ptr;
        /* calculate address for CS */
-       addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
+       addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
        /* make OR/test mask */
-       mask = 1UL << (nr & (__BITOPS_WORDSIZE - 1));
+       mask = 1UL << (nr & (BITS_PER_LONG - 1));
        /* Do the atomic update. */
        __BITOPS_LOOP(old, new, addr, mask, __BITOPS_OR);
-       __BITOPS_BARRIER();
+       barrier();
        return (old & mask) != 0;
 }
 
@@ -182,12 +177,12 @@ test_and_clear_bit_cs(unsigned long nr, volatile unsigned long *ptr)
 
        addr = (unsigned long) ptr;
        /* calculate address for CS */
-       addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
+       addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
        /* make AND/test mask */
-       mask = ~(1UL << (nr & (__BITOPS_WORDSIZE - 1)));
+       mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
        /* Do the atomic update. */
        __BITOPS_LOOP(old, new, addr, mask, __BITOPS_AND);
-       __BITOPS_BARRIER();
+       barrier();
        return (old ^ new) != 0;
 }
 
@@ -201,12 +196,12 @@ test_and_change_bit_cs(unsigned long nr, volatile unsigned long *ptr)
 
        addr = (unsigned long) ptr;
        /* calculate address for CS */
-       addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
+       addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
        /* make XOR/test mask */
-       mask = 1UL << (nr & (__BITOPS_WORDSIZE - 1));
+       mask = 1UL << (nr & (BITS_PER_LONG - 1));
        /* Do the atomic update. */
        __BITOPS_LOOP(old, new, addr, mask, __BITOPS_XOR);
-       __BITOPS_BARRIER();
+       barrier();
        return (old & mask) != 0;
 }
 #endif /* CONFIG_SMP */
@@ -218,7 +213,7 @@ static inline void __set_bit(unsigned long nr, volatile unsigned long *ptr)
 {
        unsigned long addr;
 
-       addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+       addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
        asm volatile(
                "       oc      %O0(1,%R0),%1"
                : "=Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) : "cc" );
@@ -229,7 +224,7 @@ __constant_set_bit(const unsigned long nr, volatile unsigned long *ptr)
 {
        unsigned long addr;
 
-       addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+       addr = ((unsigned long) ptr) + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
        *(unsigned char *) addr |= 1 << (nr & 7);
 }
 
@@ -246,7 +241,7 @@ __clear_bit(unsigned long nr, volatile unsigned long *ptr)
 {
        unsigned long addr;
 
-       addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+       addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
        asm volatile(
                "       nc      %O0(1,%R0),%1"
                : "=Q" (*(char *) addr) : "Q" (_ni_bitmap[nr & 7]) : "cc" );
@@ -257,7 +252,7 @@ __constant_clear_bit(const unsigned long nr, volatile unsigned long *ptr)
 {
        unsigned long addr;
 
-       addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+       addr = ((unsigned long) ptr) + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
        *(unsigned char *) addr &= ~(1 << (nr & 7));
 }
 
@@ -273,7 +268,7 @@ static inline void __change_bit(unsigned long nr, volatile unsigned long *ptr)
 {
        unsigned long addr;
 
-       addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+       addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
        asm volatile(
                "       xc      %O0(1,%R0),%1"
                : "=Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) : "cc" );
@@ -284,7 +279,7 @@ __constant_change_bit(const unsigned long nr, volatile unsigned long *ptr)
 {
        unsigned long addr;
 
-       addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+       addr = ((unsigned long) ptr) + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
        *(unsigned char *) addr ^= 1 << (nr & 7);
 }
 
@@ -302,7 +297,7 @@ test_and_set_bit_simple(unsigned long nr, volatile unsigned long *ptr)
        unsigned long addr;
        unsigned char ch;
 
-       addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+       addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
        ch = *(unsigned char *) addr;
        asm volatile(
                "       oc      %O0(1,%R0),%1"
@@ -321,7 +316,7 @@ test_and_clear_bit_simple(unsigned long nr, volatile unsigned long *ptr)
        unsigned long addr;
        unsigned char ch;
 
-       addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+       addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
        ch = *(unsigned char *) addr;
        asm volatile(
                "       nc      %O0(1,%R0),%1"
@@ -340,7 +335,7 @@ test_and_change_bit_simple(unsigned long nr, volatile unsigned long *ptr)
        unsigned long addr;
        unsigned char ch;
 
-       addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+       addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
        ch = *(unsigned char *) addr;
        asm volatile(
                "       xc      %O0(1,%R0),%1"
@@ -376,7 +371,7 @@ static inline int __test_bit(unsigned long nr, const volatile unsigned long *ptr
        unsigned long addr;
        unsigned char ch;
 
-       addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+       addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
        ch = *(volatile unsigned char *) addr;
        return (ch >> (nr & 7)) & 1;
 }
@@ -384,7 +379,7 @@ static inline int __test_bit(unsigned long nr, const volatile unsigned long *ptr
 static inline int 
 __constant_test_bit(unsigned long nr, const volatile unsigned long *addr) {
     return (((volatile char *) addr)
-           [(nr^(__BITOPS_WORDSIZE-8))>>3] & (1<<(nr&7))) != 0;
+           [(nr^(BITS_PER_LONG-8))>>3] & (1<<(nr&7))) != 0;
 }
 
 #define test_bit(nr,addr) \
@@ -693,18 +688,18 @@ static inline int find_next_bit_left(const unsigned long *addr,
 
        if (offset >= size)
                return size;
-       bit = offset & (__BITOPS_WORDSIZE - 1);
+       bit = offset & (BITS_PER_LONG - 1);
        offset -= bit;
        size -= offset;
-       p = addr + offset / __BITOPS_WORDSIZE;
+       p = addr + offset / BITS_PER_LONG;
        if (bit) {
                set = __flo_word(0, *p & (~0UL << bit));
                if (set >= size)
                        return size + offset;
-               if (set < __BITOPS_WORDSIZE)
+               if (set < BITS_PER_LONG)
                        return set + offset;
-               offset += __BITOPS_WORDSIZE;
-               size -= __BITOPS_WORDSIZE;
+               offset += BITS_PER_LONG;
+               size -= BITS_PER_LONG;
                p++;
        }
        return offset + find_first_bit_left(p, size);
@@ -736,22 +731,22 @@ static inline int find_next_zero_bit (const unsigned long * addr,
 
        if (offset >= size)
                return size;
-       bit = offset & (__BITOPS_WORDSIZE - 1);
+       bit = offset & (BITS_PER_LONG - 1);
        offset -= bit;
        size -= offset;
-       p = addr + offset / __BITOPS_WORDSIZE;
+       p = addr + offset / BITS_PER_LONG;
        if (bit) {
                /*
-                * __ffz_word returns __BITOPS_WORDSIZE
+                * __ffz_word returns BITS_PER_LONG
                 * if no zero bit is present in the word.
                 */
                set = __ffz_word(bit, *p >> bit);
                if (set >= size)
                        return size + offset;
-               if (set < __BITOPS_WORDSIZE)
+               if (set < BITS_PER_LONG)
                        return set + offset;
-               offset += __BITOPS_WORDSIZE;
-               size -= __BITOPS_WORDSIZE;
+               offset += BITS_PER_LONG;
+               size -= BITS_PER_LONG;
                p++;
        }
        return offset + find_first_zero_bit(p, size);
@@ -773,22 +768,22 @@ static inline int find_next_bit (const unsigned long * addr,
 
        if (offset >= size)
                return size;
-       bit = offset & (__BITOPS_WORDSIZE - 1);
+       bit = offset & (BITS_PER_LONG - 1);
        offset -= bit;
        size -= offset;
-       p = addr + offset / __BITOPS_WORDSIZE;
+       p = addr + offset / BITS_PER_LONG;
        if (bit) {
                /*
-                * __ffs_word returns __BITOPS_WORDSIZE
+                * __ffs_word returns BITS_PER_LONG
                 * if no one bit is present in the word.
                 */
                set = __ffs_word(0, *p & (~0UL << bit));
                if (set >= size)
                        return size + offset;
-               if (set < __BITOPS_WORDSIZE)
+               if (set < BITS_PER_LONG)
                        return set + offset;
-               offset += __BITOPS_WORDSIZE;
-               size -= __BITOPS_WORDSIZE;
+               offset += BITS_PER_LONG;
+               size -= BITS_PER_LONG;
                p++;
        }
        return offset + find_first_bit(p, size);
@@ -843,22 +838,22 @@ static inline int find_next_zero_bit_le(void *vaddr, unsigned long size,
 
         if (offset >= size)
                 return size;
-       bit = offset & (__BITOPS_WORDSIZE - 1);
+       bit = offset & (BITS_PER_LONG - 1);
        offset -= bit;
        size -= offset;
-       p = addr + offset / __BITOPS_WORDSIZE;
+       p = addr + offset / BITS_PER_LONG;
         if (bit) {
                /*
-                * s390 version of ffz returns __BITOPS_WORDSIZE
+                * s390 version of ffz returns BITS_PER_LONG
                 * if no zero bit is present in the word.
                 */
                set = __ffz_word(bit, __load_ulong_le(p, 0) >> bit);
                if (set >= size)
                        return size + offset;
-               if (set < __BITOPS_WORDSIZE)
+               if (set < BITS_PER_LONG)
                        return set + offset;
-               offset += __BITOPS_WORDSIZE;
-               size -= __BITOPS_WORDSIZE;
+               offset += BITS_PER_LONG;
+               size -= BITS_PER_LONG;
                p++;
         }
        return offset + find_first_zero_bit_le(p, size);
@@ -885,22 +880,22 @@ static inline int find_next_bit_le(void *vaddr, unsigned long size,
 
        if (offset >= size)
                return size;
-       bit = offset & (__BITOPS_WORDSIZE - 1);
+       bit = offset & (BITS_PER_LONG - 1);
        offset -= bit;
        size -= offset;
-       p = addr + offset / __BITOPS_WORDSIZE;
+       p = addr + offset / BITS_PER_LONG;
        if (bit) {
                /*
-                * s390 version of ffz returns __BITOPS_WORDSIZE
+                * s390 version of ffz returns BITS_PER_LONG
                 * if no zero bit is present in the word.
                 */
                set = __ffs_word(0, __load_ulong_le(p, 0) & (~0UL << bit));
                if (set >= size)
                        return size + offset;
-               if (set < __BITOPS_WORDSIZE)
+               if (set < BITS_PER_LONG)
                        return set + offset;
-               offset += __BITOPS_WORDSIZE;
-               size -= __BITOPS_WORDSIZE;
+               offset += BITS_PER_LONG;
+               size -= BITS_PER_LONG;
                p++;
        }
        return offset + find_first_bit_le(p, size);
index e606161..f201af8 100644 (file)
@@ -220,7 +220,8 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
 #define to_ccwdrv(n) container_of(n, struct ccw_driver, driver)
 
 extern struct ccw_device *ccw_device_probe_console(void);
-extern int ccw_device_force_console(void);
+extern void ccw_device_wait_idle(struct ccw_device *);
+extern int ccw_device_force_console(struct ccw_device *);
 
 int ccw_device_siosl(struct ccw_device *);
 
index ad2b924..ffb8989 100644 (file)
@@ -296,8 +296,6 @@ static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1,
        return 0;
 }
 
-extern void wait_cons_dev(void);
-
 extern void css_schedule_reprobe(void);
 
 extern void reipl_ccw_dev(struct ccw_dev_id *id);
index f8c6df6..c1e7c64 100644 (file)
@@ -70,6 +70,22 @@ typedef u32          compat_ulong_t;
 typedef u64            compat_u64;
 typedef u32            compat_uptr_t;
 
+typedef struct {
+       u32 mask;
+       u32 addr;
+} __aligned(8) psw_compat_t;
+
+typedef struct {
+       psw_compat_t psw;
+       u32 gprs[NUM_GPRS];
+       u32 acrs[NUM_ACRS];
+       u32 orig_gpr2;
+} s390_compat_regs;
+
+typedef struct {
+       u32 gprs_high[NUM_GPRS];
+} s390_compat_regs_high;
+
 struct compat_timespec {
        compat_time_t   tv_sec;
        s32             tv_nsec;
@@ -124,18 +140,33 @@ struct compat_flock64 {
 };
 
 struct compat_statfs {
-       s32             f_type;
-       s32             f_bsize;
-       s32             f_blocks;
-       s32             f_bfree;
-       s32             f_bavail;
-       s32             f_files;
-       s32             f_ffree;
+       u32             f_type;
+       u32             f_bsize;
+       u32             f_blocks;
+       u32             f_bfree;
+       u32             f_bavail;
+       u32             f_files;
+       u32             f_ffree;
+       compat_fsid_t   f_fsid;
+       u32             f_namelen;
+       u32             f_frsize;
+       u32             f_flags;
+       u32             f_spare[4];
+};
+
+struct compat_statfs64 {
+       u32             f_type;
+       u32             f_bsize;
+       u64             f_blocks;
+       u64             f_bfree;
+       u64             f_bavail;
+       u64             f_files;
+       u64             f_ffree;
        compat_fsid_t   f_fsid;
-       s32             f_namelen;
-       s32             f_frsize;
-       s32             f_flags;
-       s32             f_spare[5];
+       u32             f_namelen;
+       u32             f_frsize;
+       u32             f_flags;
+       u32             f_spare[4];
 };
 
 #define COMPAT_RLIM_OLD_INFINITY       0x7fffffff
@@ -248,8 +279,6 @@ static inline int is_compat_task(void)
        return is_32bit_task();
 }
 
-#endif
-
 static inline void __user *arch_compat_alloc_user_space(long len)
 {
        unsigned long stack;
@@ -260,6 +289,8 @@ static inline void __user *arch_compat_alloc_user_space(long len)
        return (void __user *) (stack - len);
 }
 
+#endif
+
 struct compat_ipc64_perm {
        compat_key_t key;
        __compat_uid32_t uid;
index 1bfdf24..78f4f87 100644 (file)
  */
 
 #include <asm/ptrace.h>
+#include <asm/compat.h>
+#include <asm/syscall.h>
 #include <asm/user.h>
 
 typedef s390_fp_regs elf_fpregset_t;
@@ -180,18 +182,31 @@ extern unsigned long elf_hwcap;
 extern char elf_platform[];
 #define ELF_PLATFORM (elf_platform)
 
-#ifdef CONFIG_64BIT
+#ifndef CONFIG_COMPAT
+#define SET_PERSONALITY(ex) \
+do {                                                           \
+       set_personality(PER_LINUX |                             \
+               (current->personality & (~PER_MASK)));          \
+       current_thread_info()->sys_call_table =                 \
+               (unsigned long) &sys_call_table;                \
+} while (0)
+#else /* CONFIG_COMPAT */
 #define SET_PERSONALITY(ex)                                    \
 do {                                                           \
        if (personality(current->personality) != PER_LINUX32)   \
                set_personality(PER_LINUX |                     \
                        (current->personality & ~PER_MASK));    \
-       if ((ex).e_ident[EI_CLASS] == ELFCLASS32)               \
+       if ((ex).e_ident[EI_CLASS] == ELFCLASS32) {             \
                set_thread_flag(TIF_31BIT);                     \
-       else                                                    \
+               current_thread_info()->sys_call_table =         \
+                       (unsigned long) &sys_call_table_emu;    \
+       } else {                                                \
                clear_thread_flag(TIF_31BIT);                   \
+               current_thread_info()->sys_call_table =         \
+                       (unsigned long) &sys_call_table;        \
+       }                                                       \
 } while (0)
-#endif /* CONFIG_64BIT */
+#endif /* CONFIG_COMPAT */
 
 #define STACK_RND_MASK 0x7ffUL
 
index 27cb321..379d96e 100644 (file)
@@ -50,10 +50,6 @@ void unxlate_dev_mem_ptr(unsigned long phys, void *addr);
 #define ioremap_nocache(addr, size)    ioremap(addr, size)
 #define ioremap_wc                     ioremap_nocache
 
-/* TODO: s390 cannot support io_remap_pfn_range... */
-#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)               \
-       remap_pfn_range(vma, vaddr, pfn, size, prot)
-
 static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
 {
        return (void __iomem *) offset;
index 05333b7..6c18012 100644 (file)
@@ -140,6 +140,7 @@ static inline bool zdev_enabled(struct zpci_dev *zdev)
 struct zpci_dev *zpci_alloc_device(void);
 int zpci_create_device(struct zpci_dev *);
 int zpci_enable_device(struct zpci_dev *);
+int zpci_disable_device(struct zpci_dev *);
 void zpci_stop_device(struct zpci_dev *);
 void zpci_free_device(struct zpci_dev *);
 int zpci_scan_device(struct zpci_dev *);
index 6bbec42..1ca5d10 100644 (file)
@@ -7,14 +7,11 @@ extern debug_info_t *pci_debug_msg_id;
 extern debug_info_t *pci_debug_err_id;
 
 #ifdef CONFIG_PCI_DEBUG
-#define zpci_dbg(fmt, args...)                                                 \
-       do {                                                                    \
-               if (pci_debug_msg_id->level >= 2)                               \
-                       debug_sprintf_event(pci_debug_msg_id, 2, fmt , ## args);\
-       } while (0)
+#define zpci_dbg(imp, fmt, args...)                            \
+       debug_sprintf_event(pci_debug_msg_id, imp, fmt, ##args)
 
 #else /* !CONFIG_PCI_DEBUG */
-#define zpci_dbg(fmt, args...) do { } while (0)
+#define zpci_dbg(imp, fmt, args...) do { } while (0)
 #endif
 
 #define zpci_err(text...)                                                      \
index 1486a98..e6a2bdd 100644 (file)
@@ -1,10 +1,6 @@
 #ifndef _ASM_S390_PCI_INSN_H
 #define _ASM_S390_PCI_INSN_H
 
-#include <linux/delay.h>
-
-#define ZPCI_INSN_BUSY_DELAY   1       /* 1 microsecond */
-
 /* Load/Store status codes */
 #define ZPCI_PCI_ST_FUNC_NOT_ENABLED           4
 #define ZPCI_PCI_ST_FUNC_IN_ERR                        8
@@ -82,199 +78,12 @@ struct zpci_fib {
        u64 reserved7;
 } __packed;
 
-/* Modify PCI Function Controls */
-static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
-{
-       u8 cc;
-
-       asm volatile (
-               "       .insn   rxy,0xe300000000d0,%[req],%[fib]\n"
-               "       ipm     %[cc]\n"
-               "       srl     %[cc],28\n"
-               : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
-               : : "cc");
-       *status = req >> 24 & 0xff;
-       return cc;
-}
-
-static inline int mpcifc_instr(u64 req, struct zpci_fib *fib)
-{
-       u8 cc, status;
-
-       do {
-               cc = __mpcifc(req, fib, &status);
-               if (cc == 2)
-                       msleep(ZPCI_INSN_BUSY_DELAY);
-       } while (cc == 2);
-
-       if (cc)
-               printk_once(KERN_ERR "%s: error cc: %d  status: %d\n",
-                            __func__, cc, status);
-       return (cc) ? -EIO : 0;
-}
-
-/* Refresh PCI Translations */
-static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
-{
-       register u64 __addr asm("2") = addr;
-       register u64 __range asm("3") = range;
-       u8 cc;
-
-       asm volatile (
-               "       .insn   rre,0xb9d30000,%[fn],%[addr]\n"
-               "       ipm     %[cc]\n"
-               "       srl     %[cc],28\n"
-               : [cc] "=d" (cc), [fn] "+d" (fn)
-               : [addr] "d" (__addr), "d" (__range)
-               : "cc");
-       *status = fn >> 24 & 0xff;
-       return cc;
-}
-
-static inline int rpcit_instr(u64 fn, u64 addr, u64 range)
-{
-       u8 cc, status;
-
-       do {
-               cc = __rpcit(fn, addr, range, &status);
-               if (cc == 2)
-                       udelay(ZPCI_INSN_BUSY_DELAY);
-       } while (cc == 2);
-
-       if (cc)
-               printk_once(KERN_ERR "%s: error cc: %d  status: %d  dma_addr: %Lx  size: %Lx\n",
-                           __func__, cc, status, addr, range);
-       return (cc) ? -EIO : 0;
-}
-
-/* Store PCI function controls */
-static inline u8 __stpcifc(u32 handle, u8 space, struct zpci_fib *fib, u8 *status)
-{
-       u64 fn = (u64) handle << 32 | space << 16;
-       u8 cc;
-
-       asm volatile (
-               "       .insn   rxy,0xe300000000d4,%[fn],%[fib]\n"
-               "       ipm     %[cc]\n"
-               "       srl     %[cc],28\n"
-               : [cc] "=d" (cc), [fn] "+d" (fn), [fib] "=m" (*fib)
-               : : "cc");
-       *status = fn >> 24 & 0xff;
-       return cc;
-}
-
-/* Set Interruption Controls */
-static inline void sic_instr(u16 ctl, char *unused, u8 isc)
-{
-       asm volatile (
-               "       .insn   rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
-               : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused));
-}
-
-/* PCI Load */
-static inline u8 __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
-{
-       register u64 __req asm("2") = req;
-       register u64 __offset asm("3") = offset;
-       u64 __data;
-       u8 cc;
-
-       asm volatile (
-               "       .insn   rre,0xb9d20000,%[data],%[req]\n"
-               "       ipm     %[cc]\n"
-               "       srl     %[cc],28\n"
-               : [cc] "=d" (cc), [data] "=d" (__data), [req] "+d" (__req)
-               :  "d" (__offset)
-               : "cc");
-       *status = __req >> 24 & 0xff;
-       *data = __data;
-       return cc;
-}
-
-static inline int pcilg_instr(u64 *data, u64 req, u64 offset)
-{
-       u8 cc, status;
-
-       do {
-               cc = __pcilg(data, req, offset, &status);
-               if (cc == 2)
-                       udelay(ZPCI_INSN_BUSY_DELAY);
-       } while (cc == 2);
-
-       if (cc) {
-               printk_once(KERN_ERR "%s: error cc: %d  status: %d  req: %Lx  offset: %Lx\n",
-                           __func__, cc, status, req, offset);
-               /* TODO: on IO errors set data to 0xff...
-                * here or in users of pcilg (le conversion)?
-                */
-       }
-       return (cc) ? -EIO : 0;
-}
-
-/* PCI Store */
-static inline u8 __pcistg(u64 data, u64 req, u64 offset, u8 *status)
-{
-       register u64 __req asm("2") = req;
-       register u64 __offset asm("3") = offset;
-       u8 cc;
-
-       asm volatile (
-               "       .insn   rre,0xb9d00000,%[data],%[req]\n"
-               "       ipm     %[cc]\n"
-               "       srl     %[cc],28\n"
-               : [cc] "=d" (cc), [req] "+d" (__req)
-               : "d" (__offset), [data] "d" (data)
-               : "cc");
-       *status = __req >> 24 & 0xff;
-       return cc;
-}
-
-static inline int pcistg_instr(u64 data, u64 req, u64 offset)
-{
-       u8 cc, status;
-
-       do {
-               cc = __pcistg(data, req, offset, &status);
-               if (cc == 2)
-                       udelay(ZPCI_INSN_BUSY_DELAY);
-       } while (cc == 2);
-
-       if (cc)
-               printk_once(KERN_ERR "%s: error cc: %d  status: %d  req: %Lx  offset: %Lx\n",
-                       __func__, cc, status, req, offset);
-       return (cc) ? -EIO : 0;
-}
-
-/* PCI Store Block */
-static inline u8 __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
-{
-       u8 cc;
-
-       asm volatile (
-               "       .insn   rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
-               "       ipm     %[cc]\n"
-               "       srl     %[cc],28\n"
-               : [cc] "=d" (cc), [req] "+d" (req)
-               : [offset] "d" (offset), [data] "Q" (*data)
-               : "cc");
-       *status = req >> 24 & 0xff;
-       return cc;
-}
-
-static inline int pcistb_instr(const u64 *data, u64 req, u64 offset)
-{
-       u8 cc, status;
-
-       do {
-               cc = __pcistb(data, req, offset, &status);
-               if (cc == 2)
-                       udelay(ZPCI_INSN_BUSY_DELAY);
-       } while (cc == 2);
 
-       if (cc)
-               printk_once(KERN_ERR "%s: error cc: %d  status: %d  req: %Lx  offset: %Lx\n",
-                           __func__, cc, status, req, offset);
-       return (cc) ? -EIO : 0;
-}
+int s390pci_mod_fc(u64 req, struct zpci_fib *fib);
+int s390pci_refresh_trans(u64 fn, u64 addr, u64 range);
+int s390pci_load(u64 *data, u64 req, u64 offset);
+int s390pci_store(u64 data, u64 req, u64 offset);
+int s390pci_store_block(const u64 *data, u64 req, u64 offset);
+void set_irq_ctrl(u16 ctl, char *unused, u8 isc);
 
 #endif
index 5fd81f3..83a9caa 100644 (file)
@@ -36,7 +36,7 @@ static inline RETTYPE zpci_read_##RETTYPE(const volatile void __iomem *addr)  \
        u64 data;                                                               \
        int rc;                                                                 \
                                                                                \
-       rc = pcilg_instr(&data, req, ZPCI_OFFSET(addr));                        \
+       rc = s390pci_load(&data, req, ZPCI_OFFSET(addr));                       \
        if (rc)                                                                 \
                data = -1ULL;                                                   \
        return (RETTYPE) data;                                                  \
@@ -50,7 +50,7 @@ static inline void zpci_write_##VALTYPE(VALTYPE val,                          \
        u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH);               \
        u64 data = (VALTYPE) val;                                               \
                                                                                \
-       pcistg_instr(data, req, ZPCI_OFFSET(addr));                             \
+       s390pci_store(data, req, ZPCI_OFFSET(addr));                            \
 }
 
 zpci_read(8, u64)
@@ -83,15 +83,18 @@ static inline int zpci_write_single(u64 req, const u64 *data, u64 offset, u8 len
                val = 0;                /* let FW report error */
                break;
        }
-       return pcistg_instr(val, req, offset);
+       return s390pci_store(val, req, offset);
 }
 
 static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len)
 {
        u64 data;
-       u8 cc;
+       int cc;
+
+       cc = s390pci_load(&data, req, offset);
+       if (cc)
+               goto out;
 
-       cc = pcilg_instr(&data,  req, offset);
        switch (len) {
        case 1:
                *((u8 *) dst) = (u8) data;
@@ -106,12 +109,13 @@ static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len)
                *((u64 *) dst) = (u64) data;
                break;
        }
+out:
        return cc;
 }
 
 static inline int zpci_write_block(u64 req, const u64 *data, u64 offset)
 {
-       return pcistb_instr(data, req, offset);
+       return s390pci_store_block(data, req, offset);
 }
 
 static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max)
index 4a54431..4a64c0e 100644 (file)
@@ -57,6 +57,10 @@ extern unsigned long zero_page_mask;
         (((unsigned long)(vaddr)) &zero_page_mask))))
 #define __HAVE_COLOR_ZERO_PAGE
 
+/* TODO: s390 cannot support io_remap_pfn_range... */
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)               \
+       remap_pfn_range(vma, vaddr, pfn, size, prot)
+
 #endif /* !__ASSEMBLY__ */
 
 /*
@@ -760,6 +764,8 @@ void gmap_disable(struct gmap *gmap);
 int gmap_map_segment(struct gmap *gmap, unsigned long from,
                     unsigned long to, unsigned long length);
 int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len);
+unsigned long __gmap_translate(unsigned long address, struct gmap *);
+unsigned long gmap_translate(unsigned long address, struct gmap *);
 unsigned long __gmap_fault(unsigned long address, struct gmap *);
 unsigned long gmap_fault(unsigned long address, struct gmap *);
 void gmap_discard(unsigned long from, unsigned long to, struct gmap *);
index 94e749c..6b49987 100644 (file)
@@ -161,7 +161,8 @@ extern unsigned long thread_saved_pc(struct task_struct *t);
 
 extern void show_code(struct pt_regs *regs);
 extern void print_fn_code(unsigned char *code, unsigned long len);
-extern int insn_to_mnemonic(unsigned char *instruction, char buf[8]);
+extern int insn_to_mnemonic(unsigned char *instruction, char *buf,
+                           unsigned int len);
 
 unsigned long get_wchan(struct task_struct *p);
 #define task_pt_regs(tsk) ((struct pt_regs *) \
index 3ee5da3..559512a 100644 (file)
@@ -9,9 +9,7 @@
 #include <uapi/asm/ptrace.h>
 
 #ifndef __ASSEMBLY__
-#ifndef __s390x__
-#else /* __s390x__ */
-#endif /* __s390x__ */
+
 extern long psw_kernel_bits;
 extern long psw_user_bits;
 
@@ -77,8 +75,6 @@ struct per_struct_kernel {
 #define PER_CONTROL_SUSPENSION         0x00400000UL
 #define PER_CONTROL_ALTERATION         0x00200000UL
 
-#ifdef __s390x__
-#endif /* __s390x__ */
 /*
  * These are defined as per linux/ptrace.h, which see.
  */
index fe7b997..cd29d2f 100644 (file)
@@ -23,6 +23,7 @@
  * type here is what we want [need] for both 32 bit and 64 bit systems.
  */
 extern const unsigned int sys_call_table[];
+extern const unsigned int sys_call_table_emu[];
 
 static inline long syscall_get_nr(struct task_struct *task,
                                  struct pt_regs *regs)
index 9e2cfe0..eb5f64d 100644 (file)
 #define THREAD_ORDER 1
 #define ASYNC_ORDER  1
 #else /* CONFIG_64BIT */
-#ifndef __SMALL_STACK
 #define THREAD_ORDER 2
 #define ASYNC_ORDER  2
-#else
-#define THREAD_ORDER 1
-#define ASYNC_ORDER  1
-#endif
 #endif /* CONFIG_64BIT */
 
 #define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
@@ -41,6 +36,7 @@ struct thread_info {
        struct task_struct      *task;          /* main task structure */
        struct exec_domain      *exec_domain;   /* execution domain */
        unsigned long           flags;          /* low level flags */
+       unsigned long           sys_call_table; /* System call table address */
        unsigned int            cpu;            /* current CPU */
        int                     preempt_count;  /* 0 => preemptable, <0 => BUG */
        struct restart_block    restart_block;
index a5ca214..3aa9f1e 100644 (file)
@@ -215,12 +215,6 @@ typedef struct
         unsigned long addr;
 } __attribute__ ((aligned(8))) psw_t;
 
-typedef struct
-{
-       __u32   mask;
-       __u32   addr;
-} __attribute__ ((aligned(8))) psw_compat_t;
-
 #ifndef __s390x__
 
 #define PSW_MASK_PER           0x40000000UL
@@ -295,20 +289,6 @@ typedef struct
        unsigned long orig_gpr2;
 } s390_regs;
 
-typedef struct
-{
-       psw_compat_t    psw;
-       __u32           gprs[NUM_GPRS];
-       __u32           acrs[NUM_ACRS];
-       __u32           orig_gpr2;
-} s390_compat_regs;
-
-typedef struct
-{
-       __u32           gprs_high[NUM_GPRS];
-} s390_compat_regs_high;
-
-
 /*
  * Now for the user space program event recording (trace) definitions.
  * The following structures are used only for the ptrace interface, don't
index 5acca0a..a61d538 100644 (file)
@@ -7,9 +7,6 @@
 #ifndef _S390_STATFS_H
 #define _S390_STATFS_H
 
-#ifndef __s390x__
-#include <asm-generic/statfs.h>
-#else
 /*
  * We can't use <asm-generic/statfs.h> because in 64-bit mode
  * we mix ints of different sizes in our struct statfs.
@@ -21,49 +18,33 @@ typedef __kernel_fsid_t     fsid_t;
 #endif
 
 struct statfs {
-       int  f_type;
-       int  f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
+       unsigned int    f_type;
+       unsigned int    f_bsize;
+       unsigned long   f_blocks;
+       unsigned long   f_bfree;
+       unsigned long   f_bavail;
+       unsigned long   f_files;
+       unsigned long   f_ffree;
        __kernel_fsid_t f_fsid;
-       int  f_namelen;
-       int  f_frsize;
-       int  f_flags;
-       int  f_spare[4];
+       unsigned int    f_namelen;
+       unsigned int    f_frsize;
+       unsigned int    f_flags;
+       unsigned int    f_spare[4];
 };
 
 struct statfs64 {
-       int  f_type;
-       int  f_bsize;
-       long f_blocks;
-       long f_bfree;
-       long f_bavail;
-       long f_files;
-       long f_ffree;
+       unsigned int    f_type;
+       unsigned int    f_bsize;
+       unsigned long   f_blocks;
+       unsigned long   f_bfree;
+       unsigned long   f_bavail;
+       unsigned long   f_files;
+       unsigned long   f_ffree;
        __kernel_fsid_t f_fsid;
-       int  f_namelen;
-       int  f_frsize;
-       int  f_flags;
-       int  f_spare[4];
+       unsigned int    f_namelen;
+       unsigned int    f_frsize;
+       unsigned int    f_flags;
+       unsigned int    f_spare[4];
 };
 
-struct compat_statfs64 {
-       __u32 f_type;
-       __u32 f_bsize;
-       __u64 f_blocks;
-       __u64 f_bfree;
-       __u64 f_bavail;
-       __u64 f_files;
-       __u64 f_ffree;
-       __kernel_fsid_t f_fsid;
-       __u32 f_namelen;
-       __u32 f_frsize;
-       __u32 f_flags;
-       __u32 f_spare[4];
-};
-
-#endif /* __s390x__ */
 #endif
index 2ac311e..1386fca 100644 (file)
@@ -14,16 +14,25 @@ endif
 CFLAGS_smp.o   := -Wno-nonnull
 
 #
+# Disable tailcall optimizations for stack / callchain walking functions
+# since this might generate broken code when accessing register 15 and
+# passing its content to other functions.
+#
+CFLAGS_stacktrace.o    += -fno-optimize-sibling-calls
+CFLAGS_dumpstack.o     += -fno-optimize-sibling-calls
+
+#
 # Pass UTS_MACHINE for user_regset definition
 #
 CFLAGS_ptrace.o                += -DUTS_MACHINE='"$(UTS_MACHINE)"'
 
 CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
 
-obj-y  :=  bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \
-           processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \
-           debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \
-           sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
+obj-y  := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o
+obj-y  += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
+obj-y  += debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o
+obj-y  += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
+obj-y  += dumpstack.o
 
 obj-y  += $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y  += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
index fface87..7a82f9f 100644 (file)
@@ -35,6 +35,7 @@ int main(void)
        DEFINE(__TI_task, offsetof(struct thread_info, task));
        DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain));
        DEFINE(__TI_flags, offsetof(struct thread_info, flags));
+       DEFINE(__TI_sysc_table, offsetof(struct thread_info, sys_call_table));
        DEFINE(__TI_cpu, offsetof(struct thread_info, cpu));
        DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count));
        DEFINE(__TI_user_timer, offsetof(struct thread_info, user_timer));
index 6de049f..c439ac9 100644 (file)
@@ -362,6 +362,7 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
                /* set extra registers only for synchronous signals */
                regs->gprs[4] = regs->int_code & 127;
                regs->gprs[5] = regs->int_parm_long;
+               regs->gprs[6] = task_thread_info(current)->last_break;
        }
 
        /* Place signal number on stack to allow backtrace from handler.  */
@@ -421,6 +422,7 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->gprs[2] = map_signal(sig);
        regs->gprs[3] = (__force __u64) &frame->info;
        regs->gprs[4] = (__force __u64) &frame->uc;
+       regs->gprs[5] = task_thread_info(current)->last_break;
        return 0;
 
 give_sigsegv:
index 3ad5e95..7f4a4a8 100644 (file)
@@ -1696,14 +1696,15 @@ static struct insn *find_insn(unsigned char *code)
  * insn_to_mnemonic - decode an s390 instruction
  * @instruction: instruction to decode
  * @buf: buffer to fill with mnemonic
+ * @len: length of buffer
  *
  * Decode the instruction at @instruction and store the corresponding
- * mnemonic into @buf.
+ * mnemonic into @buf of length @len.
  * @buf is left unchanged if the instruction could not be decoded.
  * Returns:
  *  %0 on success, %-ENOENT if the instruction was not found.
  */
-int insn_to_mnemonic(unsigned char *instruction, char buf[8])
+int insn_to_mnemonic(unsigned char *instruction, char *buf, unsigned int len)
 {
        struct insn *insn;
 
@@ -1711,10 +1712,10 @@ int insn_to_mnemonic(unsigned char *instruction, char buf[8])
        if (!insn)
                return -ENOENT;
        if (insn->name[0] == '\0')
-               snprintf(buf, 8, "%s",
+               snprintf(buf, len, "%s",
                         long_insn_name[(int) insn->name[1]]);
        else
-               snprintf(buf, 8, "%.5s", insn->name);
+               snprintf(buf, len, "%.5s", insn->name);
        return 0;
 }
 EXPORT_SYMBOL_GPL(insn_to_mnemonic);
diff --git a/arch/s390/kernel/dumpstack.c b/arch/s390/kernel/dumpstack.c
new file mode 100644 (file)
index 0000000..03dce39
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Stack dumping functions
+ *
+ *  Copyright IBM Corp. 1999, 2013
+ */
+
+#include <linux/kallsyms.h>
+#include <linux/hardirq.h>
+#include <linux/kprobes.h>
+#include <linux/utsname.h>
+#include <linux/export.h>
+#include <linux/kdebug.h>
+#include <linux/ptrace.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/processor.h>
+#include <asm/debug.h>
+#include <asm/ipl.h>
+
+#ifndef CONFIG_64BIT
+#define LONG "%08lx "
+#define FOURLONG "%08lx %08lx %08lx %08lx\n"
+static int kstack_depth_to_print = 12;
+#else /* CONFIG_64BIT */
+#define LONG "%016lx "
+#define FOURLONG "%016lx %016lx %016lx %016lx\n"
+static int kstack_depth_to_print = 20;
+#endif /* CONFIG_64BIT */
+
+/*
+ * For show_trace we have tree different stack to consider:
+ *   - the panic stack which is used if the kernel stack has overflown
+ *   - the asynchronous interrupt stack (cpu related)
+ *   - the synchronous kernel stack (process related)
+ * The stack trace can start at any of the three stack and can potentially
+ * touch all of them. The order is: panic stack, async stack, sync stack.
+ */
+static unsigned long
+__show_trace(unsigned long sp, unsigned long low, unsigned long high)
+{
+       struct stack_frame *sf;
+       struct pt_regs *regs;
+
+       while (1) {
+               sp = sp & PSW_ADDR_INSN;
+               if (sp < low || sp > high - sizeof(*sf))
+                       return sp;
+               sf = (struct stack_frame *) sp;
+               printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
+               print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN);
+               /* Follow the backchain. */
+               while (1) {
+                       low = sp;
+                       sp = sf->back_chain & PSW_ADDR_INSN;
+                       if (!sp)
+                               break;
+                       if (sp <= low || sp > high - sizeof(*sf))
+                               return sp;
+                       sf = (struct stack_frame *) sp;
+                       printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
+                       print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN);
+               }
+               /* Zero backchain detected, check for interrupt frame. */
+               sp = (unsigned long) (sf + 1);
+               if (sp <= low || sp > high - sizeof(*regs))
+                       return sp;
+               regs = (struct pt_regs *) sp;
+               printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN);
+               print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN);
+               low = sp;
+               sp = regs->gprs[15];
+       }
+}
+
+static void show_trace(struct task_struct *task, unsigned long *stack)
+{
+       register unsigned long __r15 asm ("15");
+       unsigned long sp;
+
+       sp = (unsigned long) stack;
+       if (!sp)
+               sp = task ? task->thread.ksp : __r15;
+       printk("Call Trace:\n");
+#ifdef CONFIG_CHECK_STACK
+       sp = __show_trace(sp, S390_lowcore.panic_stack - 4096,
+                         S390_lowcore.panic_stack);
+#endif
+       sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE,
+                         S390_lowcore.async_stack);
+       if (task)
+               __show_trace(sp, (unsigned long) task_stack_page(task),
+                            (unsigned long) task_stack_page(task) + THREAD_SIZE);
+       else
+               __show_trace(sp, S390_lowcore.thread_info,
+                            S390_lowcore.thread_info + THREAD_SIZE);
+       if (!task)
+               task = current;
+       debug_show_held_locks(task);
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+       register unsigned long *__r15 asm ("15");
+       unsigned long *stack;
+       int i;
+
+       if (!sp)
+               stack = task ? (unsigned long *) task->thread.ksp : __r15;
+       else
+               stack = sp;
+
+       for (i = 0; i < kstack_depth_to_print; i++) {
+               if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
+                       break;
+               if ((i * sizeof(long) % 32) == 0)
+                       printk("%s       ", i == 0 ? "" : "\n");
+               printk(LONG, *stack++);
+       }
+       printk("\n");
+       show_trace(task, sp);
+}
+
+static void show_last_breaking_event(struct pt_regs *regs)
+{
+#ifdef CONFIG_64BIT
+       printk("Last Breaking-Event-Address:\n");
+       printk(" [<%016lx>] ", regs->args[0] & PSW_ADDR_INSN);
+       print_symbol("%s\n", regs->args[0] & PSW_ADDR_INSN);
+#endif
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+       printk("CPU: %d %s %s %.*s\n",
+              task_thread_info(current)->cpu, print_tainted(),
+              init_utsname()->release,
+              (int)strcspn(init_utsname()->version, " "),
+              init_utsname()->version);
+       printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
+              current->comm, current->pid, current,
+              (void *) current->thread.ksp);
+       show_stack(NULL, NULL);
+}
+EXPORT_SYMBOL(dump_stack);
+
+static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
+{
+       return (regs->psw.mask & bits) / ((~bits + 1) & bits);
+}
+
+void show_registers(struct pt_regs *regs)
+{
+       char *mode;
+
+       mode = user_mode(regs) ? "User" : "Krnl";
+       printk("%s PSW : %p %p",
+              mode, (void *) regs->psw.mask,
+              (void *) regs->psw.addr);
+       print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN);
+       printk("           R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
+              "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER),
+              mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO),
+              mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY),
+              mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT),
+              mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC),
+              mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM));
+#ifdef CONFIG_64BIT
+       printk(" EA:%x", mask_bits(regs, PSW_MASK_EA | PSW_MASK_BA));
+#endif
+       printk("\n%s GPRS: " FOURLONG, mode,
+              regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
+       printk("           " FOURLONG,
+              regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
+       printk("           " FOURLONG,
+              regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
+       printk("           " FOURLONG,
+              regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
+       show_code(regs);
+}
+
+void show_regs(struct pt_regs *regs)
+{
+       printk("CPU: %d %s %s %.*s\n",
+              task_thread_info(current)->cpu, print_tainted(),
+              init_utsname()->release,
+              (int)strcspn(init_utsname()->version, " "),
+              init_utsname()->version);
+       printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
+              current->comm, current->pid, current,
+              (void *) current->thread.ksp);
+       show_registers(regs);
+       /* Show stack backtrace if pt_regs is from kernel mode */
+       if (!user_mode(regs))
+               show_trace(NULL, (unsigned long *) regs->gprs[15]);
+       show_last_breaking_event(regs);
+}
+
+static DEFINE_SPINLOCK(die_lock);
+
+void die(struct pt_regs *regs, const char *str)
+{
+       static int die_counter;
+
+       oops_enter();
+       lgr_info_log();
+       debug_stop_all();
+       console_verbose();
+       spin_lock_irq(&die_lock);
+       bust_spinlocks(1);
+       printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+       printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+       printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       printk("DEBUG_PAGEALLOC");
+#endif
+       printk("\n");
+       notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV);
+       print_modules();
+       show_regs(regs);
+       bust_spinlocks(0);
+       add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
+       spin_unlock_irq(&die_lock);
+       if (in_interrupt())
+               panic("Fatal exception in interrupt");
+       if (panic_on_oops)
+               panic("Fatal exception: panic_on_oops");
+       oops_exit();
+       do_exit(SIGSEGV);
+}
index 94feff7..4d5e6f8 100644 (file)
@@ -45,6 +45,7 @@ _TIF_TRACE    = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
 
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
+STACK_INIT  = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
 
 #define BASED(name) name-system_call(%r13)
 
@@ -97,10 +98,10 @@ STACK_SIZE  = 1 << STACK_SHIFT
        sra     %r14,\shift
        jnz     1f
        CHECK_STACK 1<<\shift,\savearea
+       ahi     %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        j       2f
 1:     l       %r15,\stack             # load target stack
-2:     ahi     %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
-       la      %r11,STACK_FRAME_OVERHEAD(%r15)
+2:     la      %r11,STACK_FRAME_OVERHEAD(%r15)
        .endm
 
        .macro  ADD64 high,low,timer
@@ -150,7 +151,7 @@ ENTRY(__switch_to)
        l       %r4,__THREAD_info(%r2)          # get thread_info of prev
        l       %r5,__THREAD_info(%r3)          # get thread_info of next
        lr      %r15,%r5
-       ahi     %r15,STACK_SIZE                 # end of kernel stack of next
+       ahi     %r15,STACK_INIT                 # end of kernel stack of next
        st      %r3,__LC_CURRENT                # store task struct of next
        st      %r5,__LC_THREAD_INFO            # store thread info of next
        st      %r15,__LC_KERNEL_STACK          # store end of kernel stack
@@ -178,7 +179,6 @@ sysc_stm:
        l       %r13,__LC_SVC_NEW_PSW+4
 sysc_per:
        l       %r15,__LC_KERNEL_STACK
-       ahi     %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        la      %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs
 sysc_vtime:
        UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER
@@ -188,6 +188,7 @@ sysc_vtime:
        mvc     __PT_INT_CODE(4,%r11),__LC_SVC_ILC
 sysc_do_svc:
        oi      __TI_flags+3(%r12),_TIF_SYSCALL
+       l       %r10,__TI_sysc_table(%r12)      # 31 bit system call table
        lh      %r8,__PT_INT_CODE+2(%r11)
        sla     %r8,2                           # shift and test for svc0
        jnz     sysc_nr_ok
@@ -198,7 +199,6 @@ sysc_do_svc:
        lr      %r8,%r1
        sla     %r8,2
 sysc_nr_ok:
-       l       %r10,BASED(.Lsys_call_table)    # 31 bit system call table
        xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
        st      %r2,__PT_ORIG_GPR2(%r11)
        st      %r7,STACK_FRAME_OVERHEAD(%r15)
@@ -359,11 +359,11 @@ ENTRY(pgm_check_handler)
        tm      __LC_PGM_ILC+3,0x80     # check for per exception
        jnz     pgm_svcper              # -> single stepped svc
 0:     CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC
+       ahi     %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        j       2f
 1:     UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
        l       %r15,__LC_KERNEL_STACK
-2:     ahi     %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
-       la      %r11,STACK_FRAME_OVERHEAD(%r15)
+2:     la      %r11,STACK_FRAME_OVERHEAD(%r15)
        stm     %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC
        stm     %r8,%r9,__PT_PSW(%r11)
@@ -485,7 +485,6 @@ io_work:
 #
 io_work_user:
        l       %r1,__LC_KERNEL_STACK
-       ahi     %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        mvc     STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11)
        xc      __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1)
        la      %r11,STACK_FRAME_OVERHEAD(%r1)
@@ -646,7 +645,6 @@ mcck_skip:
        tm      __PT_PSW+1(%r11),0x01   # returning to user ?
        jno     mcck_return
        l       %r1,__LC_KERNEL_STACK   # switch to kernel stack
-       ahi     %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        mvc     STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11)
        xc      __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1)
        la      %r11,STACK_FRAME_OVERHEAD(%r15)
@@ -674,6 +672,7 @@ mcck_panic:
        sra     %r14,PAGE_SHIFT
        jz      0f
        l       %r15,__LC_PANIC_STACK
+       j       mcck_skip
 0:     ahi     %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        j       mcck_skip
 
@@ -714,12 +713,10 @@ ENTRY(restart_int_handler)
  */
 stack_overflow:
        l       %r15,__LC_PANIC_STACK   # change to panic stack
-       ahi     %r15,-__PT_SIZE         # create pt_regs
-       stm     %r0,%r7,__PT_R0(%r15)
-       stm     %r8,%r9,__PT_PSW(%r15)
+       la      %r11,STACK_FRAME_OVERHEAD(%r15)
+       stm     %r0,%r7,__PT_R0(%r11)
+       stm     %r8,%r9,__PT_PSW(%r11)
        mvc     __PT_R8(32,%r11),0(%r14)
-       lr      %r15,%r11
-       ahi     %r15,-STACK_FRAME_OVERHEAD
        l       %r1,BASED(1f)
        xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
        lr      %r2,%r11                # pass pointer to pt_regs
@@ -799,15 +796,14 @@ cleanup_system_call:
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
        # set up saved register 11
        l       %r15,__LC_KERNEL_STACK
-       ahi     %r15,-__PT_SIZE
-       st      %r15,12(%r11)           # r11 pt_regs pointer
+       la      %r9,STACK_FRAME_OVERHEAD(%r15)
+       st      %r9,12(%r11)            # r11 pt_regs pointer
        # fill pt_regs
-       mvc     __PT_R8(32,%r15),__LC_SAVE_AREA_SYNC
-       stm     %r0,%r7,__PT_R0(%r15)
-       mvc     __PT_PSW(8,%r15),__LC_SVC_OLD_PSW
-       mvc     __PT_INT_CODE(4,%r15),__LC_SVC_ILC
+       mvc     __PT_R8(32,%r9),__LC_SAVE_AREA_SYNC
+       stm     %r0,%r7,__PT_R0(%r9)
+       mvc     __PT_PSW(8,%r9),__LC_SVC_OLD_PSW
+       mvc     __PT_INT_CODE(4,%r9),__LC_SVC_ILC
        # setup saved register 15
-       ahi     %r15,-STACK_FRAME_OVERHEAD
        st      %r15,28(%r11)           # r15 stack pointer
        # set new psw address and exit
        l       %r9,BASED(cleanup_table+4)      # sysc_do_svc + 0x80000000
@@ -910,7 +906,6 @@ cleanup_idle_wait:
 .Ltrace_enter:         .long   do_syscall_trace_enter
 .Ltrace_exit:          .long   do_syscall_trace_exit
 .Lschedule_tail:       .long   schedule_tail
-.Lsys_call_table:      .long   sys_call_table
 .Lsysc_per:            .long   sysc_per + 0x80000000
 #ifdef CONFIG_TRACE_IRQFLAGS
 .Lhardirqs_on:         .long   trace_hardirqs_on_caller
index c3a736a..aa0ab02 100644 (file)
@@ -7,6 +7,7 @@
 #include <asm/cputime.h>
 
 extern void *restart_stack;
+extern unsigned long suspend_zero_pages;
 
 void system_call(void);
 void pgm_check_handler(void);
index 2e6d60c..4c17eec 100644 (file)
@@ -39,6 +39,7 @@ __PT_R15     =        __PT_GPRS + 120
 
 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
 STACK_SIZE  = 1 << STACK_SHIFT
+STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
 
 _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
                 _TIF_MCCK_PENDING | _TIF_PER_TRAP )
@@ -124,10 +125,10 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
        srag    %r14,%r14,\shift
        jnz     1f
        CHECK_STACK 1<<\shift,\savearea
+       aghi    %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        j       2f
 1:     lg      %r15,\stack             # load target stack
-2:     aghi    %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
-       la      %r11,STACK_FRAME_OVERHEAD(%r15)
+2:     la      %r11,STACK_FRAME_OVERHEAD(%r15)
        .endm
 
        .macro UPDATE_VTIME scratch,enter_timer
@@ -177,7 +178,7 @@ ENTRY(__switch_to)
        lg      %r4,__THREAD_info(%r2)          # get thread_info of prev
        lg      %r5,__THREAD_info(%r3)          # get thread_info of next
        lgr     %r15,%r5
-       aghi    %r15,STACK_SIZE                 # end of kernel stack of next
+       aghi    %r15,STACK_INIT                 # end of kernel stack of next
        stg     %r3,__LC_CURRENT                # store task struct of next
        stg     %r5,__LC_THREAD_INFO            # store thread info of next
        stg     %r15,__LC_KERNEL_STACK          # store end of kernel stack
@@ -203,10 +204,8 @@ sysc_stmg:
        stmg    %r8,%r15,__LC_SAVE_AREA_SYNC
        lg      %r10,__LC_LAST_BREAK
        lg      %r12,__LC_THREAD_INFO
-       larl    %r13,system_call
 sysc_per:
        lg      %r15,__LC_KERNEL_STACK
-       aghi    %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        la      %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs
 sysc_vtime:
        UPDATE_VTIME %r13,__LC_SYNC_ENTER_TIMER
@@ -217,6 +216,7 @@ sysc_vtime:
        mvc     __PT_INT_CODE(4,%r11),__LC_SVC_ILC
 sysc_do_svc:
        oi      __TI_flags+7(%r12),_TIF_SYSCALL
+       lg      %r10,__TI_sysc_table(%r12)      # address of system call table
        llgh    %r8,__PT_INT_CODE+2(%r11)
        slag    %r8,%r8,2                       # shift and test for svc 0
        jnz     sysc_nr_ok
@@ -227,13 +227,6 @@ sysc_do_svc:
        sth     %r1,__PT_INT_CODE+2(%r11)
        slag    %r8,%r1,2
 sysc_nr_ok:
-       larl    %r10,sys_call_table             # 64 bit system call table
-#ifdef CONFIG_COMPAT
-       tm      __TI_flags+5(%r12),(_TIF_31BIT>>16)
-       jno     sysc_noemu
-       larl    %r10,sys_call_table_emu         # 31 bit system call table
-sysc_noemu:
-#endif
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
        stg     %r2,__PT_ORIG_GPR2(%r11)
        stg     %r7,STACK_FRAME_OVERHEAD(%r15)
@@ -389,6 +382,7 @@ ENTRY(pgm_check_handler)
        tm      __LC_PGM_ILC+3,0x80     # check for per exception
        jnz     pgm_svcper              # -> single stepped svc
 0:     CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC
+       aghi    %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        j       2f
 1:     UPDATE_VTIME %r14,__LC_SYNC_ENTER_TIMER
        LAST_BREAK %r14
@@ -398,8 +392,7 @@ ENTRY(pgm_check_handler)
        tm      __LC_PGM_ILC+2,0x02     # check for transaction abort
        jz      2f
        mvc     __THREAD_trap_tdb(256,%r14),0(%r13)
-2:     aghi    %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
-       la      %r11,STACK_FRAME_OVERHEAD(%r15)
+2:     la      %r11,STACK_FRAME_OVERHEAD(%r15)
        stmg    %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
        stmg    %r8,%r9,__PT_PSW(%r11)
@@ -526,7 +519,6 @@ io_work:
 #
 io_work_user:
        lg      %r1,__LC_KERNEL_STACK
-       aghi    %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        mvc     STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11)
        xc      __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1)
        la      %r11,STACK_FRAME_OVERHEAD(%r1)
@@ -688,7 +680,6 @@ mcck_skip:
        tm      __PT_PSW+1(%r11),0x01   # returning to user ?
        jno     mcck_return
        lg      %r1,__LC_KERNEL_STACK   # switch to kernel stack
-       aghi    %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
        mvc     STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11)
        xc      __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1)
        la      %r11,STACK_FRAME_OVERHEAD(%r1)
@@ -755,14 +746,12 @@ ENTRY(restart_int_handler)
  * Setup a pt_regs so that show_trace can provide a good call trace.
  */
 stack_overflow:
-       lg      %r11,__LC_PANIC_STACK   # change to panic stack
-       aghi    %r11,-__PT_SIZE         # create pt_regs
+       lg      %r15,__LC_PANIC_STACK   # change to panic stack
+       la      %r11,STACK_FRAME_OVERHEAD(%r15)
        stmg    %r0,%r7,__PT_R0(%r11)
        stmg    %r8,%r9,__PT_PSW(%r11)
        mvc     __PT_R8(64,%r11),0(%r14)
        stg     %r10,__PT_ORIG_GPR2(%r11) # store last break to orig_gpr2
-       lgr     %r15,%r11
-       aghi    %r15,-STACK_FRAME_OVERHEAD
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
        lgr     %r2,%r11                # pass pointer to pt_regs
        jg      kernel_stack_overflow
@@ -846,15 +835,14 @@ cleanup_system_call:
        mvc     __TI_last_break(8,%r12),16(%r11)
 0:     # set up saved register r11
        lg      %r15,__LC_KERNEL_STACK
-       aghi    %r15,-__PT_SIZE
-       stg     %r15,24(%r11)           # r11 pt_regs pointer
+       la      %r9,STACK_FRAME_OVERHEAD(%r15)
+       stg     %r9,24(%r11)            # r11 pt_regs pointer
        # fill pt_regs
-       mvc     __PT_R8(64,%r15),__LC_SAVE_AREA_SYNC
-       stmg    %r0,%r7,__PT_R0(%r15)
-       mvc     __PT_PSW(16,%r15),__LC_SVC_OLD_PSW
-       mvc     __PT_INT_CODE(4,%r15),__LC_SVC_ILC
+       mvc     __PT_R8(64,%r9),__LC_SAVE_AREA_SYNC
+       stmg    %r0,%r7,__PT_R0(%r9)
+       mvc     __PT_PSW(16,%r9),__LC_SVC_OLD_PSW
+       mvc     __PT_INT_CODE(4,%r9),__LC_SVC_ILC
        # setup saved register r15
-       aghi    %r15,-STACK_FRAME_OVERHEAD
        stg     %r15,56(%r11)           # r15 stack pointer
        # set new psw address and exit
        larl    %r9,sysc_do_svc
@@ -1011,6 +999,7 @@ sys_call_table:
 #ifdef CONFIG_COMPAT
 
 #define SYSCALL(esa,esame,emu) .long emu
+       .globl  sys_call_table_emu
 sys_call_table_emu:
 #include "syscalls.S"
 #undef SYSCALL
index b3de277..ac21781 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/reboot.h>
 #include <linux/ftrace.h>
 #include <linux/debug_locks.h>
+#include <linux/suspend.h>
 #include <asm/cio.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
@@ -67,6 +68,35 @@ void setup_regs(void)
        memcpy((void *) SAVE_AREA_BASE, (void *) sa, sizeof(struct save_area));
 }
 
+/*
+ * PM notifier callback for kdump
+ */
+static int machine_kdump_pm_cb(struct notifier_block *nb, unsigned long action,
+                              void *ptr)
+{
+       switch (action) {
+       case PM_SUSPEND_PREPARE:
+       case PM_HIBERNATION_PREPARE:
+               if (crashk_res.start)
+                       crash_map_reserved_pages();
+               break;
+       case PM_POST_SUSPEND:
+       case PM_POST_HIBERNATION:
+               if (crashk_res.start)
+                       crash_unmap_reserved_pages();
+               break;
+       default:
+               return NOTIFY_DONE;
+       }
+       return NOTIFY_OK;
+}
+
+static int __init machine_kdump_pm_init(void)
+{
+       pm_notifier(machine_kdump_pm_cb, 0);
+       return 0;
+}
+arch_initcall(machine_kdump_pm_init);
 #endif
 
 /*
index 2926885..0f419c5 100644 (file)
@@ -377,11 +377,14 @@ static void __init setup_lowcore(void)
                PSW_MASK_DAT | PSW_MASK_MCHECK;
        lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
        lc->clock_comparator = -1ULL;
-       lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
+       lc->kernel_stack = ((unsigned long) &init_thread_union)
+               + THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
        lc->async_stack = (unsigned long)
-               __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
+               __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0)
+               + ASYNC_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
        lc->panic_stack = (unsigned long)
-               __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
+               __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0)
+               + PAGE_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
        lc->current_task = (unsigned long) init_thread_union.thread_info.task;
        lc->thread_info = (unsigned long) &init_thread_union;
        lc->machine_flags = S390_lowcore.machine_flags;
index 549c9d1..8bde89e 100644 (file)
@@ -181,8 +181,10 @@ static int __cpuinit pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
        lc = pcpu->lowcore;
        memcpy(lc, &S390_lowcore, 512);
        memset((char *) lc + 512, 0, sizeof(*lc) - 512);
-       lc->async_stack = pcpu->async_stack + ASYNC_SIZE;
-       lc->panic_stack = pcpu->panic_stack + PAGE_SIZE;
+       lc->async_stack = pcpu->async_stack + ASYNC_SIZE
+               - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
+       lc->panic_stack = pcpu->panic_stack + PAGE_SIZE
+               - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
        lc->cpu_nr = cpu;
 #ifndef CONFIG_64BIT
        if (MACHINE_HAS_IEEE) {
@@ -253,7 +255,8 @@ static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
        struct _lowcore *lc = pcpu->lowcore;
        struct thread_info *ti = task_thread_info(tsk);
 
-       lc->kernel_stack = (unsigned long) task_stack_page(tsk) + THREAD_SIZE;
+       lc->kernel_stack = (unsigned long) task_stack_page(tsk)
+               + THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
        lc->thread_info = (unsigned long) task_thread_info(tsk);
        lc->current_task = (unsigned long) tsk;
        lc->user_timer = ti->user_timer;
@@ -810,8 +813,10 @@ void __init smp_prepare_boot_cpu(void)
        pcpu->state = CPU_STATE_CONFIGURED;
        pcpu->address = boot_cpu_address;
        pcpu->lowcore = (struct _lowcore *)(unsigned long) store_prefix();
-       pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE;
-       pcpu->panic_stack = S390_lowcore.panic_stack - PAGE_SIZE;
+       pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE
+               + STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
+       pcpu->panic_stack = S390_lowcore.panic_stack - PAGE_SIZE
+               + STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
        S390_lowcore.percpu_offset = __per_cpu_offset[0];
        smp_cpu_set_polarization(0, POLARIZATION_UNKNOWN);
        set_cpu_present(0, true);
index aa1494d..c479d2f 100644 (file)
@@ -41,6 +41,7 @@ struct page_key_data {
 static struct page_key_data *page_key_data;
 static struct page_key_data *page_key_rp, *page_key_wp;
 static unsigned long page_key_rx, page_key_wx;
+unsigned long suspend_zero_pages;
 
 /*
  * For each page in the hibernation image one additional byte is
@@ -149,6 +150,36 @@ int pfn_is_nosave(unsigned long pfn)
        return 0;
 }
 
+/*
+ * PM notifier callback for suspend
+ */
+static int suspend_pm_cb(struct notifier_block *nb, unsigned long action,
+                        void *ptr)
+{
+       switch (action) {
+       case PM_SUSPEND_PREPARE:
+       case PM_HIBERNATION_PREPARE:
+               suspend_zero_pages = __get_free_pages(GFP_KERNEL, LC_ORDER);
+               if (!suspend_zero_pages)
+                       return NOTIFY_BAD;
+               break;
+       case PM_POST_SUSPEND:
+       case PM_POST_HIBERNATION:
+               free_pages(suspend_zero_pages, LC_ORDER);
+               break;
+       default:
+               return NOTIFY_DONE;
+       }
+       return NOTIFY_OK;
+}
+
+static int __init suspend_pm_init(void)
+{
+       pm_notifier(suspend_pm_cb, 0);
+       return 0;
+}
+arch_initcall(suspend_pm_init);
+
 void save_processor_state(void)
 {
        /* swsusp_arch_suspend() actually saves all cpu register contents.
index d4ca4e0..c487be4 100644 (file)
@@ -36,8 +36,8 @@ ENTRY(swsusp_arch_suspend)
        /* Store prefix register on stack */
        stpx    __SF_EMPTY(%r15)
 
-       /* Save prefix register contents for lowcore */
-       llgf    %r4,__SF_EMPTY(%r15)
+       /* Save prefix register contents for lowcore copy */
+       llgf    %r10,__SF_EMPTY(%r15)
 
        /* Get pointer to save area */
        lghi    %r1,0x1000
@@ -91,7 +91,18 @@ ENTRY(swsusp_arch_suspend)
        xc      __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
        spx     __SF_EMPTY(%r15)
 
+       /* Save absolute zero pages */
+       larl    %r2,suspend_zero_pages
+       lg      %r2,0(%r2)
+       lghi    %r4,0
+       lghi    %r3,2*PAGE_SIZE
+       lghi    %r5,2*PAGE_SIZE
+1:     mvcle   %r2,%r4,0
+       jo      1b
+
+       /* Copy lowcore to absolute zero lowcore */
        lghi    %r2,0
+       lgr     %r4,%r10
        lghi    %r3,2*PAGE_SIZE
        lghi    %r5,2*PAGE_SIZE
 1:     mvcle   %r2,%r4,0
@@ -248,8 +259,20 @@ restore_registers:
        /* Load old stack */
        lg      %r15,0x2f8(%r13)
 
+       /* Save prefix register */
+       mvc __SF_EMPTY(4,%r15),0x318(%r13)
+
+       /* Restore absolute zero pages */
+       lghi    %r2,0
+       larl    %r4,suspend_zero_pages
+       lg      %r4,0(%r4)
+       lghi    %r3,2*PAGE_SIZE
+       lghi    %r5,2*PAGE_SIZE
+1:     mvcle   %r2,%r4,0
+       jo      1b
+
        /* Restore prefix register */
-       spx     0x318(%r13)
+       spx     __SF_EMPTY(%r15)
 
        /* Activate DAT */
        stosm   __SF_EMPTY(%r15),0x04
index 13dd63f..c576232 100644 (file)
  * 'Traps.c' handles hardware traps and faults after we have saved some
  * state in 'asm.s'.
  */
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
+#include <linux/kprobes.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
 #include <linux/ptrace.h>
-#include <linux/timer.h>
+#include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/seq_file.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/kdebug.h>
-#include <linux/kallsyms.h>
-#include <linux/reboot.h>
-#include <linux/kprobes.h>
-#include <linux/bug.h>
-#include <linux/utsname.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <linux/atomic.h>
-#include <asm/mathemu.h>
-#include <asm/cpcmd.h>
-#include <asm/lowcore.h>
-#include <asm/debug.h>
-#include <asm/ipl.h>
 #include "entry.h"
 
 int show_unhandled_signals = 1;
 
-#define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; })
-
-#ifndef CONFIG_64BIT
-#define LONG "%08lx "
-#define FOURLONG "%08lx %08lx %08lx %08lx\n"
-static int kstack_depth_to_print = 12;
-#else /* CONFIG_64BIT */
-#define LONG "%016lx "
-#define FOURLONG "%016lx %016lx %016lx %016lx\n"
-static int kstack_depth_to_print = 20;
-#endif /* CONFIG_64BIT */
-
 static inline void __user *get_trap_ip(struct pt_regs *regs)
 {
 #ifdef CONFIG_64BIT
@@ -72,215 +39,6 @@ static inline void __user *get_trap_ip(struct pt_regs *regs)
 #endif
 }
 
-/*
- * For show_trace we have tree different stack to consider:
- *   - the panic stack which is used if the kernel stack has overflown
- *   - the asynchronous interrupt stack (cpu related)
- *   - the synchronous kernel stack (process related)
- * The stack trace can start at any of the three stack and can potentially
- * touch all of them. The order is: panic stack, async stack, sync stack.
- */
-static unsigned long
-__show_trace(unsigned long sp, unsigned long low, unsigned long high)
-{
-       struct stack_frame *sf;
-       struct pt_regs *regs;
-
-       while (1) {
-               sp = sp & PSW_ADDR_INSN;
-               if (sp < low || sp > high - sizeof(*sf))
-                       return sp;
-               sf = (struct stack_frame *) sp;
-               printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
-               print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN);
-               /* Follow the backchain. */
-               while (1) {
-                       low = sp;
-                       sp = sf->back_chain & PSW_ADDR_INSN;
-                       if (!sp)
-                               break;
-                       if (sp <= low || sp > high - sizeof(*sf))
-                               return sp;
-                       sf = (struct stack_frame *) sp;
-                       printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
-                       print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN);
-               }
-               /* Zero backchain detected, check for interrupt frame. */
-               sp = (unsigned long) (sf + 1);
-               if (sp <= low || sp > high - sizeof(*regs))
-                       return sp;
-               regs = (struct pt_regs *) sp;
-               printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN);
-               print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN);
-               low = sp;
-               sp = regs->gprs[15];
-       }
-}
-
-static void show_trace(struct task_struct *task, unsigned long *stack)
-{
-       register unsigned long __r15 asm ("15");
-       unsigned long sp;
-
-       sp = (unsigned long) stack;
-       if (!sp)
-               sp = task ? task->thread.ksp : __r15;
-       printk("Call Trace:\n");
-#ifdef CONFIG_CHECK_STACK
-       sp = __show_trace(sp, S390_lowcore.panic_stack - 4096,
-                         S390_lowcore.panic_stack);
-#endif
-       sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE,
-                         S390_lowcore.async_stack);
-       if (task)
-               __show_trace(sp, (unsigned long) task_stack_page(task),
-                            (unsigned long) task_stack_page(task) + THREAD_SIZE);
-       else
-               __show_trace(sp, S390_lowcore.thread_info,
-                            S390_lowcore.thread_info + THREAD_SIZE);
-       if (!task)
-               task = current;
-       debug_show_held_locks(task);
-}
-
-void show_stack(struct task_struct *task, unsigned long *sp)
-{
-       register unsigned long * __r15 asm ("15");
-       unsigned long *stack;
-       int i;
-
-       if (!sp)
-               stack = task ? (unsigned long *) task->thread.ksp : __r15;
-       else
-               stack = sp;
-
-       for (i = 0; i < kstack_depth_to_print; i++) {
-               if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
-                       break;
-               if ((i * sizeof(long) % 32) == 0)
-                       printk("%s       ", i == 0 ? "" : "\n");
-               printk(LONG, *stack++);
-       }
-       printk("\n");
-       show_trace(task, sp);
-}
-
-static void show_last_breaking_event(struct pt_regs *regs)
-{
-#ifdef CONFIG_64BIT
-       printk("Last Breaking-Event-Address:\n");
-       printk(" [<%016lx>] ", regs->args[0] & PSW_ADDR_INSN);
-       print_symbol("%s\n", regs->args[0] & PSW_ADDR_INSN);
-#endif
-}
-
-/*
- * The architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
-       printk("CPU: %d %s %s %.*s\n",
-              task_thread_info(current)->cpu, print_tainted(),
-              init_utsname()->release,
-              (int)strcspn(init_utsname()->version, " "),
-              init_utsname()->version);
-       printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
-              current->comm, current->pid, current,
-              (void *) current->thread.ksp);
-       show_stack(NULL, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
-
-static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
-{
-       return (regs->psw.mask & bits) / ((~bits + 1) & bits);
-}
-
-void show_registers(struct pt_regs *regs)
-{
-       char *mode;
-
-       mode = user_mode(regs) ? "User" : "Krnl";
-       printk("%s PSW : %p %p",
-              mode, (void *) regs->psw.mask,
-              (void *) regs->psw.addr);
-       print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN);
-       printk("           R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
-              "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER),
-              mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO),
-              mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY),
-              mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT),
-              mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC),
-              mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM));
-#ifdef CONFIG_64BIT
-       printk(" EA:%x", mask_bits(regs, PSW_MASK_EA | PSW_MASK_BA));
-#endif
-       printk("\n%s GPRS: " FOURLONG, mode,
-              regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
-       printk("           " FOURLONG,
-              regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
-       printk("           " FOURLONG,
-              regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
-       printk("           " FOURLONG,
-              regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
-
-       show_code(regs);
-}      
-
-void show_regs(struct pt_regs *regs)
-{
-       printk("CPU: %d %s %s %.*s\n",
-              task_thread_info(current)->cpu, print_tainted(),
-              init_utsname()->release,
-              (int)strcspn(init_utsname()->version, " "),
-              init_utsname()->version);
-       printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
-              current->comm, current->pid, current,
-              (void *) current->thread.ksp);
-       show_registers(regs);
-       /* Show stack backtrace if pt_regs is from kernel mode */
-       if (!user_mode(regs))
-               show_trace(NULL, (unsigned long *) regs->gprs[15]);
-       show_last_breaking_event(regs);
-}
-
-static DEFINE_SPINLOCK(die_lock);
-
-void die(struct pt_regs *regs, const char *str)
-{
-       static int die_counter;
-
-       oops_enter();
-       lgr_info_log();
-       debug_stop_all();
-       console_verbose();
-       spin_lock_irq(&die_lock);
-       bust_spinlocks(1);
-       printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter);
-#ifdef CONFIG_PREEMPT
-       printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
-       printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
-       printk("DEBUG_PAGEALLOC");
-#endif
-       printk("\n");
-       notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV);
-       print_modules();
-       show_regs(regs);
-       bust_spinlocks(0);
-       add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
-       spin_unlock_irq(&die_lock);
-       if (in_interrupt())
-               panic("Fatal exception in interrupt");
-       if (panic_on_oops)
-               panic("Fatal exception: panic_on_oops");
-       oops_exit();
-       do_exit(SIGSEGV);
-}
-
 static inline void report_user_fault(struct pt_regs *regs, int signr)
 {
        if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
index 2b29e62..53252d2 100644 (file)
@@ -117,7 +117,7 @@ TRACE_EVENT(kvm_s390_intercept_instruction,
                           __entry->instruction,
                           insn_to_mnemonic((unsigned char *)
                                            &__entry->instruction,
-                                        __entry->insn) ?
+                                        __entry->insn, sizeof(__entry->insn)) ?
                           "unknown" : __entry->insn)
        );
 
index 479e942..9d84a1f 100644 (file)
@@ -458,12 +458,10 @@ static int __init cmm_init(void)
        if (rc)
                goto out_pm;
        cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
-       rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
-       if (rc)
-               goto out_kthread;
-       return 0;
+       if (!IS_ERR(cmm_thread_ptr))
+               return 0;
 
-out_kthread:
+       rc = PTR_ERR(cmm_thread_ptr);
        unregister_pm_notifier(&cmm_power_notifier);
 out_pm:
        unregister_oom_notifier(&cmm_oom_nb);
index 2fb9e63..047c3e4 100644 (file)
@@ -395,8 +395,13 @@ void __kprobes do_protection_exception(struct pt_regs *regs)
        int fault;
 
        trans_exc_code = regs->int_parm_long;
-       /* Protection exception is suppressing, decrement psw address. */
-       regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16);
+       /*
+        * Protection exceptions are suppressing, decrement psw address.
+        * The exception to this rule are aborted transactions, for these
+        * the PSW already points to the correct location.
+        */
+       if (!(regs->int_code & 0x200))
+               regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16);
        /*
         * Check for low-address protection.  This needs to be treated
         * as a special case because the translation exception code
index 49ce6bb..9f9c315 100644 (file)
@@ -63,10 +63,18 @@ static unsigned long __init setup_zero_pages(void)
                break;
        case 0x2097:    /* z10 */
        case 0x2098:    /* z10 */
-       default:
+       case 0x2817:    /* z196 */
+       case 0x2818:    /* z196 */
                order = 2;
                break;
+       case 0x2827:    /* zEC12 */
+       default:
+               order = 5;
+               break;
        }
+       /* Limit number of empty zero pages for small memory sizes */
+       if (order > 2 && totalram_pages <= 16384)
+               order = 2;
 
        empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
        if (!empty_zero_page)
index d21040e..80adfbf 100644 (file)
@@ -9,31 +9,25 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 
+static inline unsigned long sske_frame(unsigned long addr, unsigned char skey)
+{
+       asm volatile(".insn rrf,0xb22b0000,%[skey],%[addr],9,0"
+                    : [addr] "+a" (addr) : [skey] "d" (skey));
+       return addr;
+}
+
 void storage_key_init_range(unsigned long start, unsigned long end)
 {
-       unsigned long boundary, function, size;
+       unsigned long boundary, size;
 
        while (start < end) {
-               if (MACHINE_HAS_EDAT2) {
-                       /* set storage keys for a 2GB frame */
-                       function = 0x22000 | PAGE_DEFAULT_KEY;
-                       size = 1UL << 31;
-                       boundary = (start + size) & ~(size - 1);
-                       if (boundary <= end) {
-                               do {
-                                       start = pfmf(function, start);
-                               } while (start < boundary);
-                               continue;
-                       }
-               }
                if (MACHINE_HAS_EDAT1) {
                        /* set storage keys for a 1MB frame */
-                       function = 0x21000 | PAGE_DEFAULT_KEY;
                        size = 1UL << 20;
                        boundary = (start + size) & ~(size - 1);
                        if (boundary <= end) {
                                do {
-                                       start = pfmf(function, start);
+                                       start = sske_frame(start, PAGE_DEFAULT_KEY);
                                } while (start < boundary);
                                continue;
                        }
index ae44d2a..bd954e9 100644 (file)
@@ -379,75 +379,183 @@ out_unmap:
 }
 EXPORT_SYMBOL_GPL(gmap_map_segment);
 
-/*
- * this function is assumed to be called with mmap_sem held
- */
-unsigned long __gmap_fault(unsigned long address, struct gmap *gmap)
+static unsigned long *gmap_table_walk(unsigned long address, struct gmap *gmap)
 {
-       unsigned long *table, vmaddr, segment;
-       struct mm_struct *mm;
-       struct gmap_pgtable *mp;
-       struct gmap_rmap *rmap;
-       struct vm_area_struct *vma;
-       struct page *page;
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
+       unsigned long *table;
 
-       current->thread.gmap_addr = address;
-       mm = gmap->mm;
-       /* Walk the gmap address space page table */
        table = gmap->table + ((address >> 53) & 0x7ff);
        if (unlikely(*table & _REGION_ENTRY_INV))
-               return -EFAULT;
+               return ERR_PTR(-EFAULT);
        table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
        table = table + ((address >> 42) & 0x7ff);
        if (unlikely(*table & _REGION_ENTRY_INV))
-               return -EFAULT;
+               return ERR_PTR(-EFAULT);
        table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
        table = table + ((address >> 31) & 0x7ff);
        if (unlikely(*table & _REGION_ENTRY_INV))
-               return -EFAULT;
+               return ERR_PTR(-EFAULT);
        table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
        table = table + ((address >> 20) & 0x7ff);
+       return table;
+}
+
+/**
+ * __gmap_translate - translate a guest address to a user space address
+ * @address: guest address
+ * @gmap: pointer to guest mapping meta data structure
+ *
+ * Returns user space address which corresponds to the guest address or
+ * -EFAULT if no such mapping exists.
+ * This function does not establish potentially missing page table entries.
+ * The mmap_sem of the mm that belongs to the address space must be held
+ * when this function gets called.
+ */
+unsigned long __gmap_translate(unsigned long address, struct gmap *gmap)
+{
+       unsigned long *segment_ptr, vmaddr, segment;
+       struct gmap_pgtable *mp;
+       struct page *page;
 
+       current->thread.gmap_addr = address;
+       segment_ptr = gmap_table_walk(address, gmap);
+       if (IS_ERR(segment_ptr))
+               return PTR_ERR(segment_ptr);
        /* Convert the gmap address to an mm address. */
-       segment = *table;
-       if (likely(!(segment & _SEGMENT_ENTRY_INV))) {
+       segment = *segment_ptr;
+       if (!(segment & _SEGMENT_ENTRY_INV)) {
                page = pfn_to_page(segment >> PAGE_SHIFT);
                mp = (struct gmap_pgtable *) page->index;
                return mp->vmaddr | (address & ~PMD_MASK);
        } else if (segment & _SEGMENT_ENTRY_RO) {
                vmaddr = segment & _SEGMENT_ENTRY_ORIGIN;
-               vma = find_vma(mm, vmaddr);
-               if (!vma || vma->vm_start > vmaddr)
-                       return -EFAULT;
-
-               /* Walk the parent mm page table */
-               pgd = pgd_offset(mm, vmaddr);
-               pud = pud_alloc(mm, pgd, vmaddr);
-               if (!pud)
-                       return -ENOMEM;
-               pmd = pmd_alloc(mm, pud, vmaddr);
-               if (!pmd)
-                       return -ENOMEM;
-               if (!pmd_present(*pmd) &&
-                   __pte_alloc(mm, vma, pmd, vmaddr))
-                       return -ENOMEM;
-               /* pmd now points to a valid segment table entry. */
-               rmap = kmalloc(sizeof(*rmap), GFP_KERNEL|__GFP_REPEAT);
-               if (!rmap)
-                       return -ENOMEM;
-               /* Link gmap segment table entry location to page table. */
-               page = pmd_page(*pmd);
-               mp = (struct gmap_pgtable *) page->index;
-               rmap->entry = table;
-               spin_lock(&mm->page_table_lock);
+               return vmaddr | (address & ~PMD_MASK);
+       }
+       return -EFAULT;
+}
+EXPORT_SYMBOL_GPL(__gmap_translate);
+
+/**
+ * gmap_translate - translate a guest address to a user space address
+ * @address: guest address
+ * @gmap: pointer to guest mapping meta data structure
+ *
+ * Returns user space address which corresponds to the guest address or
+ * -EFAULT if no such mapping exists.
+ * This function does not establish potentially missing page table entries.
+ */
+unsigned long gmap_translate(unsigned long address, struct gmap *gmap)
+{
+       unsigned long rc;
+
+       down_read(&gmap->mm->mmap_sem);
+       rc = __gmap_translate(address, gmap);
+       up_read(&gmap->mm->mmap_sem);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(gmap_translate);
+
+static int gmap_connect_pgtable(unsigned long segment,
+                               unsigned long *segment_ptr,
+                               struct gmap *gmap)
+{
+       unsigned long vmaddr;
+       struct vm_area_struct *vma;
+       struct gmap_pgtable *mp;
+       struct gmap_rmap *rmap;
+       struct mm_struct *mm;
+       struct page *page;
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+
+       mm = gmap->mm;
+       vmaddr = segment & _SEGMENT_ENTRY_ORIGIN;
+       vma = find_vma(mm, vmaddr);
+       if (!vma || vma->vm_start > vmaddr)
+               return -EFAULT;
+       /* Walk the parent mm page table */
+       pgd = pgd_offset(mm, vmaddr);
+       pud = pud_alloc(mm, pgd, vmaddr);
+       if (!pud)
+               return -ENOMEM;
+       pmd = pmd_alloc(mm, pud, vmaddr);
+       if (!pmd)
+               return -ENOMEM;
+       if (!pmd_present(*pmd) &&
+           __pte_alloc(mm, vma, pmd, vmaddr))
+               return -ENOMEM;
+       /* pmd now points to a valid segment table entry. */
+       rmap = kmalloc(sizeof(*rmap), GFP_KERNEL|__GFP_REPEAT);
+       if (!rmap)
+               return -ENOMEM;
+       /* Link gmap segment table entry location to page table. */
+       page = pmd_page(*pmd);
+       mp = (struct gmap_pgtable *) page->index;
+       rmap->entry = segment_ptr;
+       spin_lock(&mm->page_table_lock);
+       if (*segment_ptr == segment) {
                list_add(&rmap->list, &mp->mapper);
-               spin_unlock(&mm->page_table_lock);
                /* Set gmap segment table entry to page table. */
-               *table = pmd_val(*pmd) & PAGE_MASK;
-               return vmaddr | (address & ~PMD_MASK);
+               *segment_ptr = pmd_val(*pmd) & PAGE_MASK;
+               rmap = NULL;
+       }
+       spin_unlock(&mm->page_table_lock);
+       kfree(rmap);
+       return 0;
+}
+
+static void gmap_disconnect_pgtable(struct mm_struct *mm, unsigned long *table)
+{
+       struct gmap_rmap *rmap, *next;
+       struct gmap_pgtable *mp;
+       struct page *page;
+       int flush;
+
+       flush = 0;
+       spin_lock(&mm->page_table_lock);
+       page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+       mp = (struct gmap_pgtable *) page->index;
+       list_for_each_entry_safe(rmap, next, &mp->mapper, list) {
+               *rmap->entry =
+                       _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | mp->vmaddr;
+               list_del(&rmap->list);
+               kfree(rmap);
+               flush = 1;
+       }
+       spin_unlock(&mm->page_table_lock);
+       if (flush)
+               __tlb_flush_global();
+}
+
+/*
+ * this function is assumed to be called with mmap_sem held
+ */
+unsigned long __gmap_fault(unsigned long address, struct gmap *gmap)
+{
+       unsigned long *segment_ptr, segment;
+       struct gmap_pgtable *mp;
+       struct page *page;
+       int rc;
+
+       current->thread.gmap_addr = address;
+       segment_ptr = gmap_table_walk(address, gmap);
+       if (IS_ERR(segment_ptr))
+               return -EFAULT;
+       /* Convert the gmap address to an mm address. */
+       while (1) {
+               segment = *segment_ptr;
+               if (!(segment & _SEGMENT_ENTRY_INV)) {
+                       /* Page table is present */
+                       page = pfn_to_page(segment >> PAGE_SHIFT);
+                       mp = (struct gmap_pgtable *) page->index;
+                       return mp->vmaddr | (address & ~PMD_MASK);
+               }
+               if (!(segment & _SEGMENT_ENTRY_RO))
+                       /* Nothing mapped in the gmap address space. */
+                       break;
+               rc = gmap_connect_pgtable(segment, segment_ptr, gmap);
+               if (rc)
+                       return rc;
        }
        return -EFAULT;
 }
@@ -511,29 +619,6 @@ void gmap_discard(unsigned long from, unsigned long to, struct gmap *gmap)
 }
 EXPORT_SYMBOL_GPL(gmap_discard);
 
-void gmap_unmap_notifier(struct mm_struct *mm, unsigned long *table)
-{
-       struct gmap_rmap *rmap, *next;
-       struct gmap_pgtable *mp;
-       struct page *page;
-       int flush;
-
-       flush = 0;
-       spin_lock(&mm->page_table_lock);
-       page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
-       mp = (struct gmap_pgtable *) page->index;
-       list_for_each_entry_safe(rmap, next, &mp->mapper, list) {
-               *rmap->entry =
-                       _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | mp->vmaddr;
-               list_del(&rmap->list);
-               kfree(rmap);
-               flush = 1;
-       }
-       spin_unlock(&mm->page_table_lock);
-       if (flush)
-               __tlb_flush_global();
-}
-
 static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
                                                    unsigned long vmaddr)
 {
@@ -586,8 +671,8 @@ static inline void page_table_free_pgste(unsigned long *table)
 {
 }
 
-static inline void gmap_unmap_notifier(struct mm_struct *mm,
-                                         unsigned long *table)
+static inline void gmap_disconnect_pgtable(struct mm_struct *mm,
+                                          unsigned long *table)
 {
 }
 
@@ -653,7 +738,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
        unsigned int bit, mask;
 
        if (mm_has_pgste(mm)) {
-               gmap_unmap_notifier(mm, table);
+               gmap_disconnect_pgtable(mm, table);
                return page_table_free_pgste(table);
        }
        /* Free 1K/2K page table fragment of a 4K page */
@@ -696,7 +781,7 @@ void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table)
 
        mm = tlb->mm;
        if (mm_has_pgste(mm)) {
-               gmap_unmap_notifier(mm, table);
+               gmap_disconnect_pgtable(mm, table);
                table = (unsigned long *) (__pa(table) | FRAG_MASK);
                tlb_remove_table(tlb, table);
                return;
index 0972e91..82f165f 100644 (file)
@@ -747,10 +747,9 @@ void bpf_jit_compile(struct sk_filter *fp)
 
        if (!bpf_jit_enable)
                return;
-       addrs = kmalloc(fp->len * sizeof(*addrs), GFP_KERNEL);
+       addrs = kcalloc(fp->len, sizeof(*addrs), GFP_KERNEL);
        if (addrs == NULL)
                return;
-       memset(addrs, 0, fp->len * sizeof(*addrs));
        memset(&jit, 0, sizeof(cjit));
        memset(&cjit, 0, sizeof(cjit));
 
index f0f426a..086a2e3 100644 (file)
@@ -2,5 +2,5 @@
 # Makefile for the s390 PCI subsystem.
 #
 
-obj-$(CONFIG_PCI)      += pci.o pci_dma.o pci_clp.o pci_msi.o \
-                          pci_sysfs.o pci_event.o pci_debug.o
+obj-$(CONFIG_PCI)      += pci.o pci_dma.o pci_clp.o pci_msi.o pci_sysfs.o \
+                          pci_event.o pci_debug.o pci_insn.o
index 27b4c17..e6f15b5 100644 (file)
@@ -99,9 +99,6 @@ static int __read_mostly aisb_max;
 static struct kmem_cache *zdev_irq_cache;
 static struct kmem_cache *zdev_fmb_cache;
 
-debug_info_t *pci_debug_msg_id;
-debug_info_t *pci_debug_err_id;
-
 static inline int irq_to_msi_nr(unsigned int irq)
 {
        return irq & ZPCI_MSI_MASK;
@@ -179,7 +176,7 @@ static int zpci_register_airq(struct zpci_dev *zdev, unsigned int aisb,
        fib->aisb = (u64) bucket->aisb + aisb / 8;
        fib->aisbo = aisb & ZPCI_MSI_MASK;
 
-       rc = mpcifc_instr(req, fib);
+       rc = s390pci_mod_fc(req, fib);
        pr_debug("%s mpcifc returned noi: %d\n", __func__, fib->noi);
 
        free_page((unsigned long) fib);
@@ -209,7 +206,7 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args
        fib->iota = args->iota;
        fib->fmb_addr = args->fmb_addr;
 
-       rc = mpcifc_instr(req, fib);
+       rc = s390pci_mod_fc(req, fib);
        free_page((unsigned long) fib);
        return rc;
 }
@@ -249,10 +246,9 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev)
        if (zdev->fmb)
                return -EINVAL;
 
-       zdev->fmb = kmem_cache_alloc(zdev_fmb_cache, GFP_KERNEL);
+       zdev->fmb = kmem_cache_zalloc(zdev_fmb_cache, GFP_KERNEL);
        if (!zdev->fmb)
                return -ENOMEM;
-       memset(zdev->fmb, 0, sizeof(*zdev->fmb));
        WARN_ON((u64) zdev->fmb & 0xf);
 
        args.fmb_addr = virt_to_phys(zdev->fmb);
@@ -284,12 +280,12 @@ static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len)
        u64 data;
        int rc;
 
-       rc = pcilg_instr(&data, req, offset);
-       data = data << ((8 - len) * 8);
-       data = le64_to_cpu(data);
-       if (!rc)
+       rc = s390pci_load(&data, req, offset);
+       if (!rc) {
+               data = data << ((8 - len) * 8);
+               data = le64_to_cpu(data);
                *val = (u32) data;
-       else
+       else
                *val = 0xffffffff;
        return rc;
 }
@@ -302,7 +298,7 @@ static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len)
 
        data = cpu_to_le64(data);
        data = data >> ((8 - len) * 8);
-       rc = pcistg_instr(data, req, offset);
+       rc = s390pci_store(data, req, offset);
        return rc;
 }
 
@@ -409,20 +405,28 @@ static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
                    int size, u32 *val)
 {
        struct zpci_dev *zdev = get_zdev_by_bus(bus);
+       int ret;
 
        if (!zdev || devfn != ZPCI_DEVFN)
-               return 0;
-       return zpci_cfg_load(zdev, where, val, size);
+               ret = -ENODEV;
+       else
+               ret = zpci_cfg_load(zdev, where, val, size);
+
+       return ret;
 }
 
 static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
                     int size, u32 val)
 {
        struct zpci_dev *zdev = get_zdev_by_bus(bus);
+       int ret;
 
        if (!zdev || devfn != ZPCI_DEVFN)
-               return 0;
-       return zpci_cfg_store(zdev, where, val, size);
+               ret = -ENODEV;
+       else
+               ret = zpci_cfg_store(zdev, where, val, size);
+
+       return ret;
 }
 
 static struct pci_ops pci_root_ops = {
@@ -474,7 +478,7 @@ scan:
        }
 
        /* enable interrupts again */
-       sic_instr(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+       set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
 
        /* check again to not lose initiative */
        rmb();
@@ -596,19 +600,6 @@ static void zpci_map_resources(struct zpci_dev *zdev)
        }
 };
 
-static void zpci_unmap_resources(struct pci_dev *pdev)
-{
-       resource_size_t len;
-       int i;
-
-       for (i = 0; i < PCI_BAR_COUNT; i++) {
-               len = pci_resource_len(pdev, i);
-               if (!len)
-                       continue;
-               pci_iounmap(pdev, (void *) pdev->resource[i].start);
-       }
-};
-
 struct zpci_dev *zpci_alloc_device(void)
 {
        struct zpci_dev *zdev;
@@ -636,32 +627,6 @@ void zpci_free_device(struct zpci_dev *zdev)
        kfree(zdev);
 }
 
-/* Called on removal of pci_dev, leaves zpci and bus device */
-static void zpci_remove_device(struct pci_dev *pdev)
-{
-       struct zpci_dev *zdev = get_zdev(pdev);
-
-       dev_info(&pdev->dev, "Removing device %u\n", zdev->domain);
-       zdev->state = ZPCI_FN_STATE_CONFIGURED;
-       zpci_dma_exit_device(zdev);
-       zpci_fmb_disable_device(zdev);
-       zpci_sysfs_remove_device(&pdev->dev);
-       zpci_unmap_resources(pdev);
-       list_del(&zdev->entry);         /* can be called from init */
-       zdev->pdev = NULL;
-}
-
-static void zpci_scan_devices(void)
-{
-       struct zpci_dev *zdev;
-
-       mutex_lock(&zpci_list_lock);
-       list_for_each_entry(zdev, &zpci_list, entry)
-               if (zdev->state == ZPCI_FN_STATE_CONFIGURED)
-                       zpci_scan_device(zdev);
-       mutex_unlock(&zpci_list_lock);
-}
-
 /*
  * Too late for any s390 specific setup, since interrupts must be set up
  * already which requires DMA setup too and the pci scan will access the
@@ -688,12 +653,6 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask)
        return 0;
 }
 
-void pcibios_disable_device(struct pci_dev *pdev)
-{
-       zpci_remove_device(pdev);
-       pdev->sysdata = NULL;
-}
-
 int pcibios_add_platform_entries(struct pci_dev *pdev)
 {
        return zpci_sysfs_add_device(&pdev->dev);
@@ -789,7 +748,7 @@ static int __init zpci_irq_init(void)
        spin_lock_init(&bucket->lock);
        /* set summary to 1 to be called every time for the ISC */
        *zpci_irq_si = 1;
-       sic_instr(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+       set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
        return 0;
 
 out_ai:
@@ -872,7 +831,19 @@ static void zpci_free_iomap(struct zpci_dev *zdev, int entry)
        spin_unlock(&zpci_iomap_lock);
 }
 
-static int zpci_create_device_bus(struct zpci_dev *zdev)
+int pcibios_add_device(struct pci_dev *pdev)
+{
+       struct zpci_dev *zdev = get_zdev(pdev);
+
+       zdev->pdev = pdev;
+       zpci_debug_init_device(zdev);
+       zpci_fmb_enable_device(zdev);
+       zpci_map_resources(zdev);
+
+       return 0;
+}
+
+static int zpci_scan_bus(struct zpci_dev *zdev)
 {
        struct resource *res;
        LIST_HEAD(resources);
@@ -909,8 +880,8 @@ static int zpci_create_device_bus(struct zpci_dev *zdev)
                pci_add_resource(&resources, res);
        }
 
-       zdev->bus = pci_create_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops,
-                                       zdev, &resources);
+       zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops,
+                                     zdev, &resources);
        if (!zdev->bus)
                return -EIO;
 
@@ -959,6 +930,13 @@ out:
 }
 EXPORT_SYMBOL_GPL(zpci_enable_device);
 
+int zpci_disable_device(struct zpci_dev *zdev)
+{
+       zpci_dma_exit_device(zdev);
+       return clp_disable_fh(zdev);
+}
+EXPORT_SYMBOL_GPL(zpci_disable_device);
+
 int zpci_create_device(struct zpci_dev *zdev)
 {
        int rc;
@@ -967,9 +945,16 @@ int zpci_create_device(struct zpci_dev *zdev)
        if (rc)
                goto out;
 
-       rc = zpci_create_device_bus(zdev);
+       if (zdev->state == ZPCI_FN_STATE_CONFIGURED) {
+               rc = zpci_enable_device(zdev);
+               if (rc)
+                       goto out_free;
+
+               zdev->state = ZPCI_FN_STATE_ONLINE;
+       }
+       rc = zpci_scan_bus(zdev);
        if (rc)
-               goto out_bus;
+               goto out_disable;
 
        mutex_lock(&zpci_list_lock);
        list_add_tail(&zdev->entry, &zpci_list);
@@ -977,21 +962,12 @@ int zpci_create_device(struct zpci_dev *zdev)
                hotplug_ops->create_slot(zdev);
        mutex_unlock(&zpci_list_lock);
 
-       if (zdev->state == ZPCI_FN_STATE_STANDBY)
-               return 0;
-
-       rc = zpci_enable_device(zdev);
-       if (rc)
-               goto out_start;
        return 0;
 
-out_start:
-       mutex_lock(&zpci_list_lock);
-       list_del(&zdev->entry);
-       if (hotplug_ops)
-               hotplug_ops->remove_slot(zdev);
-       mutex_unlock(&zpci_list_lock);
-out_bus:
+out_disable:
+       if (zdev->state == ZPCI_FN_STATE_ONLINE)
+               zpci_disable_device(zdev);
+out_free:
        zpci_free_domain(zdev);
 out:
        return rc;
@@ -1016,15 +992,9 @@ int zpci_scan_device(struct zpci_dev *zdev)
                goto out;
        }
 
-       zpci_debug_init_device(zdev);
-       zpci_fmb_enable_device(zdev);
-       zpci_map_resources(zdev);
        pci_bus_add_devices(zdev->bus);
 
-       /* now that pdev was added to the bus mark it as used */
-       zdev->state = ZPCI_FN_STATE_ONLINE;
        return 0;
-
 out:
        zpci_dma_exit_device(zdev);
        clp_disable_fh(zdev);
@@ -1087,13 +1057,13 @@ void zpci_deregister_hp_ops(void)
 }
 EXPORT_SYMBOL_GPL(zpci_deregister_hp_ops);
 
-unsigned int s390_pci_probe = 1;
+unsigned int s390_pci_probe;
 EXPORT_SYMBOL_GPL(s390_pci_probe);
 
 char * __init pcibios_setup(char *str)
 {
-       if (!strcmp(str, "off")) {
-               s390_pci_probe = 0;
+       if (!strcmp(str, "on")) {
+               s390_pci_probe = 1;
                return NULL;
        }
        return str;
@@ -1138,7 +1108,6 @@ static int __init pci_base_init(void)
        if (rc)
                goto out_find;
 
-       zpci_scan_devices();
        return 0;
 
 out_find:
index f339fe2..bd34359 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
+#include <asm/pci_debug.h>
 #include <asm/pci_clp.h>
 
 /*
@@ -144,6 +145,7 @@ int clp_add_pci_device(u32 fid, u32 fh, int configured)
        struct zpci_dev *zdev;
        int rc;
 
+       zpci_dbg(3, "add fid:%x, fh:%x, c:%d\n", fid, fh, configured);
        zdev = zpci_alloc_device();
        if (IS_ERR(zdev))
                return PTR_ERR(zdev);
@@ -204,8 +206,8 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
        if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)
                *fh = rrb->response.fh;
        else {
-               pr_err("Set PCI FN failed with response: %x  cc: %d\n",
-                       rrb->response.hdr.rsp, rc);
+               zpci_dbg(0, "SPF fh:%x, cc:%d, resp:%x\n", *fh, rc,
+                        rrb->response.hdr.rsp);
                rc = -EIO;
        }
        clp_free_block(rrb);
@@ -221,6 +223,8 @@ int clp_enable_fh(struct zpci_dev *zdev, u8 nr_dma_as)
        if (!rc)
                /* Success -> store enabled handle in zdev */
                zdev->fh = fh;
+
+       zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, zdev->fh, rc);
        return rc;
 }
 
@@ -237,9 +241,8 @@ int clp_disable_fh(struct zpci_dev *zdev)
        if (!rc)
                /* Success -> store disabled handle in zdev */
                zdev->fh = fh;
-       else
-               dev_err(&zdev->pdev->dev,
-                       "Failed to disable fn handle: 0x%x\n", fh);
+
+       zpci_dbg(3, "dis fid:%x, fh:%x, rc:%d\n", zdev->fid, zdev->fh, rc);
        return rc;
 }
 
index a5d07bc..771b823 100644 (file)
 #include <linux/kernel.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
+#include <linux/export.h>
 #include <linux/pci.h>
 #include <asm/debug.h>
 
 #include <asm/pci_dma.h>
 
 static struct dentry *debugfs_root;
+debug_info_t *pci_debug_msg_id;
+EXPORT_SYMBOL_GPL(pci_debug_msg_id);
+debug_info_t *pci_debug_err_id;
+EXPORT_SYMBOL_GPL(pci_debug_err_id);
 
 static char *pci_perf_names[] = {
        /* hardware counters */
@@ -168,7 +173,6 @@ int __init zpci_debug_init(void)
                return -EINVAL;
        debug_register_view(pci_debug_msg_id, &debug_sprintf_view);
        debug_set_level(pci_debug_msg_id, 3);
-       zpci_dbg("Debug view initialized\n");
 
        /* error log */
        pci_debug_err_id = debug_register("pci_error", 2, 1, 16);
@@ -176,7 +180,6 @@ int __init zpci_debug_init(void)
                return -EINVAL;
        debug_register_view(pci_debug_err_id, &debug_hex_ascii_view);
        debug_set_level(pci_debug_err_id, 6);
-       zpci_err("Debug view initialized\n");
 
        debugfs_root = debugfs_create_dir("pci", NULL);
        return 0;
index a547419..f8e69d5 100644 (file)
@@ -169,8 +169,9 @@ static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa,
                 * needs to be redone!
                 */
                goto no_refresh;
-       rc = rpcit_instr((u64) zdev->fh << 32, start_dma_addr,
-                         nr_pages * PAGE_SIZE);
+
+       rc = s390pci_refresh_trans((u64) zdev->fh << 32, start_dma_addr,
+                                  nr_pages * PAGE_SIZE);
 
 no_refresh:
        spin_unlock_irqrestore(&zdev->dma_table_lock, irq_flags);
@@ -268,8 +269,6 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
        int flags = ZPCI_PTE_VALID;
        dma_addr_t dma_addr;
 
-       WARN_ON_ONCE(offset > PAGE_SIZE);
-
        /* This rounds up number of pages based on size and offset */
        nr_pages = iommu_num_pages(pa, size, PAGE_SIZE);
        iommu_page_index = dma_alloc_iommu(zdev, nr_pages);
@@ -291,7 +290,7 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
 
        if (!dma_update_trans(zdev, pa, dma_addr, size, flags)) {
                atomic64_add(nr_pages, (atomic64_t *) &zdev->fmb->mapped_pages);
-               return dma_addr + offset;
+               return dma_addr + (offset & ~PAGE_MASK);
        }
 
 out_free:
diff --git a/arch/s390/pci/pci_insn.c b/arch/s390/pci/pci_insn.c
new file mode 100644 (file)
index 0000000..22eeb9d
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * s390 specific pci instructions
+ *
+ * Copyright IBM Corp. 2013
+ */
+
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <asm/pci_insn.h>
+#include <asm/processor.h>
+
+#define ZPCI_INSN_BUSY_DELAY   1       /* 1 microsecond */
+
+/* Modify PCI Function Controls */
+static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
+{
+       u8 cc;
+
+       asm volatile (
+               "       .insn   rxy,0xe300000000d0,%[req],%[fib]\n"
+               "       ipm     %[cc]\n"
+               "       srl     %[cc],28\n"
+               : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
+               : : "cc");
+       *status = req >> 24 & 0xff;
+       return cc;
+}
+
+int s390pci_mod_fc(u64 req, struct zpci_fib *fib)
+{
+       u8 cc, status;
+
+       do {
+               cc = __mpcifc(req, fib, &status);
+               if (cc == 2)
+                       msleep(ZPCI_INSN_BUSY_DELAY);
+       } while (cc == 2);
+
+       if (cc)
+               printk_once(KERN_ERR "%s: error cc: %d  status: %d\n",
+                            __func__, cc, status);
+       return (cc) ? -EIO : 0;
+}
+
+/* Refresh PCI Translations */
+static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
+{
+       register u64 __addr asm("2") = addr;
+       register u64 __range asm("3") = range;
+       u8 cc;
+
+       asm volatile (
+               "       .insn   rre,0xb9d30000,%[fn],%[addr]\n"
+               "       ipm     %[cc]\n"
+               "       srl     %[cc],28\n"
+               : [cc] "=d" (cc), [fn] "+d" (fn)
+               : [addr] "d" (__addr), "d" (__range)
+               : "cc");
+       *status = fn >> 24 & 0xff;
+       return cc;
+}
+
+int s390pci_refresh_trans(u64 fn, u64 addr, u64 range)
+{
+       u8 cc, status;
+
+       do {
+               cc = __rpcit(fn, addr, range, &status);
+               if (cc == 2)
+                       udelay(ZPCI_INSN_BUSY_DELAY);
+       } while (cc == 2);
+
+       if (cc)
+               printk_once(KERN_ERR "%s: error cc: %d  status: %d  dma_addr: %Lx  size: %Lx\n",
+                           __func__, cc, status, addr, range);
+       return (cc) ? -EIO : 0;
+}
+
+/* Set Interruption Controls */
+void set_irq_ctrl(u16 ctl, char *unused, u8 isc)
+{
+       asm volatile (
+               "       .insn   rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
+               : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused));
+}
+
+/* PCI Load */
+static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
+{
+       register u64 __req asm("2") = req;
+       register u64 __offset asm("3") = offset;
+       int cc = -ENXIO;
+       u64 __data;
+
+       asm volatile (
+               "       .insn   rre,0xb9d20000,%[data],%[req]\n"
+               "0:     ipm     %[cc]\n"
+               "       srl     %[cc],28\n"
+               "1:\n"
+               EX_TABLE(0b, 1b)
+               : [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req)
+               :  "d" (__offset)
+               : "cc");
+       *status = __req >> 24 & 0xff;
+       if (!cc)
+               *data = __data;
+
+       return cc;
+}
+
+int s390pci_load(u64 *data, u64 req, u64 offset)
+{
+       u8 status;
+       int cc;
+
+       do {
+               cc = __pcilg(data, req, offset, &status);
+               if (cc == 2)
+                       udelay(ZPCI_INSN_BUSY_DELAY);
+       } while (cc == 2);
+
+       if (cc)
+               printk_once(KERN_ERR "%s: error cc: %d  status: %d  req: %Lx  offset: %Lx\n",
+                           __func__, cc, status, req, offset);
+       return (cc > 0) ? -EIO : cc;
+}
+EXPORT_SYMBOL_GPL(s390pci_load);
+
+/* PCI Store */
+static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
+{
+       register u64 __req asm("2") = req;
+       register u64 __offset asm("3") = offset;
+       int cc = -ENXIO;
+
+       asm volatile (
+               "       .insn   rre,0xb9d00000,%[data],%[req]\n"
+               "0:     ipm     %[cc]\n"
+               "       srl     %[cc],28\n"
+               "1:\n"
+               EX_TABLE(0b, 1b)
+               : [cc] "+d" (cc), [req] "+d" (__req)
+               : "d" (__offset), [data] "d" (data)
+               : "cc");
+       *status = __req >> 24 & 0xff;
+       return cc;
+}
+
+int s390pci_store(u64 data, u64 req, u64 offset)
+{
+       u8 status;
+       int cc;
+
+       do {
+               cc = __pcistg(data, req, offset, &status);
+               if (cc == 2)
+                       udelay(ZPCI_INSN_BUSY_DELAY);
+       } while (cc == 2);
+
+       if (cc)
+               printk_once(KERN_ERR "%s: error cc: %d  status: %d  req: %Lx  offset: %Lx\n",
+                       __func__, cc, status, req, offset);
+       return (cc > 0) ? -EIO : cc;
+}
+EXPORT_SYMBOL_GPL(s390pci_store);
+
+/* PCI Store Block */
+static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
+{
+       int cc = -ENXIO;
+
+       asm volatile (
+               "       .insn   rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
+               "0:     ipm     %[cc]\n"
+               "       srl     %[cc],28\n"
+               "1:\n"
+               EX_TABLE(0b, 1b)
+               : [cc] "+d" (cc), [req] "+d" (req)
+               : [offset] "d" (offset), [data] "Q" (*data)
+               : "cc");
+       *status = req >> 24 & 0xff;
+       return cc;
+}
+
+int s390pci_store_block(const u64 *data, u64 req, u64 offset)
+{
+       u8 status;
+       int cc;
+
+       do {
+               cc = __pcistb(data, req, offset, &status);
+               if (cc == 2)
+                       udelay(ZPCI_INSN_BUSY_DELAY);
+       } while (cc == 2);
+
+       if (cc)
+               printk_once(KERN_ERR "%s: error cc: %d  status: %d  req: %Lx  offset: %Lx\n",
+                           __func__, cc, status, req, offset);
+       return (cc > 0) ? -EIO : cc;
+}
+EXPORT_SYMBOL_GPL(s390pci_store_block);
index 0297931..b097aed 100644 (file)
@@ -18,8 +18,9 @@
 
 /* mapping of irq numbers to msi_desc */
 static struct hlist_head *msi_hash;
-static unsigned int msihash_shift = 6;
-#define msi_hashfn(nr) hash_long(nr, msihash_shift)
+static const unsigned int msi_hash_bits = 8;
+#define MSI_HASH_BUCKETS (1U << msi_hash_bits)
+#define msi_hashfn(nr) hash_long(nr, msi_hash_bits)
 
 static DEFINE_SPINLOCK(msi_map_lock);
 
@@ -74,6 +75,7 @@ int zpci_setup_msi_irq(struct zpci_dev *zdev, struct msi_desc *msi,
        map->irq = nr;
        map->msi = msi;
        zdev->msi_map[nr & ZPCI_MSI_MASK] = map;
+       INIT_HLIST_NODE(&map->msi_chain);
 
        pr_debug("%s hashing irq: %u  to bucket nr: %llu\n",
                __func__, nr, msi_hashfn(nr));
@@ -125,11 +127,11 @@ int __init zpci_msihash_init(void)
 {
        unsigned int i;
 
-       msi_hash = kmalloc(256 * sizeof(*msi_hash), GFP_KERNEL);
+       msi_hash = kmalloc(MSI_HASH_BUCKETS * sizeof(*msi_hash), GFP_KERNEL);
        if (!msi_hash)
                return -ENOMEM;
 
-       for (i = 0; i < (1U << msihash_shift); i++)
+       for (i = 0; i < MSI_HASH_BUCKETS; i++)
                INIT_HLIST_HEAD(&msi_hash[i]);
        return 0;
 }
index e26d430..ff18e3c 100644 (file)
@@ -2,11 +2,16 @@
 
 
 generic-y += clkdev.h
+generic-y += cputime.h
 generic-y += div64.h
+generic-y += emergency-restart.h
 generic-y += exec.h
 generic-y += local64.h
+generic-y += mutex.h
 generic-y += irq_regs.h
 generic-y += local.h
 generic-y += module.h
+generic-y += serial.h
 generic-y += trace_clock.h
+generic-y += types.h
 generic-y += word-at-a-time.h
diff --git a/arch/sparc/include/asm/cputime.h b/arch/sparc/include/asm/cputime.h
deleted file mode 100644 (file)
index 1a642b8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __SPARC_CPUTIME_H
-#define __SPARC_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __SPARC_CPUTIME_H */
diff --git a/arch/sparc/include/asm/emergency-restart.h b/arch/sparc/include/asm/emergency-restart.h
deleted file mode 100644 (file)
index 108d8c4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_EMERGENCY_RESTART_H
-#define _ASM_EMERGENCY_RESTART_H
-
-#include <asm-generic/emergency-restart.h>
-
-#endif /* _ASM_EMERGENCY_RESTART_H */
diff --git a/arch/sparc/include/asm/mutex.h b/arch/sparc/include/asm/mutex.h
deleted file mode 100644 (file)
index 458c1f7..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Pull in the generic implementation for the mutex fastpath.
- *
- * TODO: implement optimized primitives instead, or leave the generic
- * implementation in place, or pick the atomic_xchg() based generic
- * implementation. (see asm-generic/mutex-xchg.h for details)
- */
-
-#include <asm-generic/mutex-dec.h>
index 08fcce9..7619f2f 100644 (file)
@@ -915,6 +915,7 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
        return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
 }
 
+#include <asm/tlbflush.h>
 #include <asm-generic/pgtable.h>
 
 /* We provide our own get_unmapped_area to cope with VA holes and
diff --git a/arch/sparc/include/asm/serial.h b/arch/sparc/include/asm/serial.h
deleted file mode 100644 (file)
index f90d61c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __SPARC_SERIAL_H
-#define __SPARC_SERIAL_H
-
-#define BASE_BAUD ( 1843200 / 16 )
-
-#endif /* __SPARC_SERIAL_H */
index b73da3c..3c8917f 100644 (file)
@@ -36,7 +36,6 @@ typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,
                       unsigned long, unsigned long);
 
 void cpu_panic(void);
-extern void smp4m_irq_rotate(int cpu);
 
 /*
  *     General functions that each host system must provide.
@@ -46,7 +45,6 @@ void sun4m_init_smp(void);
 void sun4d_init_smp(void);
 
 void smp_callin(void);
-void smp_boot_cpus(void);
 void smp_store_cpu_info(int);
 
 void smp_resched_interrupt(void);
@@ -107,9 +105,6 @@ extern int hard_smp_processor_id(void);
 
 #define raw_smp_processor_id()         (current_thread_info()->cpu)
 
-#define prof_multiplier(__cpu)         cpu_data(__cpu).multiplier
-#define prof_counter(__cpu)            cpu_data(__cpu).counter
-
 void smp_setup_cpu_possible_map(void);
 
 #endif /* !(__ASSEMBLY__) */
index cad36f5..c7de332 100644 (file)
@@ -18,8 +18,7 @@ do {                                          \
         * and 2 stores in this critical code path.  -DaveM
         */
 #define switch_to(prev, next, last)                                    \
-do {   flush_tlb_pending();                                            \
-       save_and_clear_fpu();                                           \
+do {   save_and_clear_fpu();                                           \
        /* If you are tempted to conditionalize the following */        \
        /* so that ASI is only written if it changes, think again. */   \
        __asm__ __volatile__("wr %%g0, %0, %%asi"                       \
index 2ef4634..f0d6a97 100644 (file)
 struct tlb_batch {
        struct mm_struct *mm;
        unsigned long tlb_nr;
+       unsigned long active;
        unsigned long vaddrs[TLB_BATCH_NR];
 };
 
 extern void flush_tsb_kernel_range(unsigned long start, unsigned long end);
 extern void flush_tsb_user(struct tlb_batch *tb);
+extern void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr);
 
 /* TLB flush operations. */
 
-extern void flush_tlb_pending(void);
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+                                 unsigned long vmaddr)
+{
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+                                  unsigned long start, unsigned long end)
+{
+}
+
+#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE
 
-#define flush_tlb_range(vma,start,end) \
-       do { (void)(start); flush_tlb_pending(); } while (0)
-#define flush_tlb_page(vma,addr)       flush_tlb_pending()
-#define flush_tlb_mm(mm)               flush_tlb_pending()
+extern void flush_tlb_pending(void);
+extern void arch_enter_lazy_mmu_mode(void);
+extern void arch_leave_lazy_mmu_mode(void);
+#define arch_flush_lazy_mmu_mode()      do {} while (0)
 
 /* Local cpu only.  */
 extern void __flush_tlb_all(void);
-
+extern void __flush_tlb_page(unsigned long context, unsigned long vaddr);
 extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
 #ifndef CONFIG_SMP
@@ -38,15 +54,24 @@ do {        flush_tsb_kernel_range(start,end); \
        __flush_tlb_kernel_range(start,end); \
 } while (0)
 
+static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr)
+{
+       __flush_tlb_page(CTX_HWBITS(mm->context), vaddr);
+}
+
 #else /* CONFIG_SMP */
 
 extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end);
+extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr);
 
 #define flush_tlb_kernel_range(start, end) \
 do {   flush_tsb_kernel_range(start,end); \
        smp_flush_tlb_kernel_range(start, end); \
 } while (0)
 
+#define global_flush_tlb_page(mm, vaddr) \
+       smp_flush_tlb_page(mm, vaddr)
+
 #endif /* ! CONFIG_SMP */
 
 #endif /* _SPARC64_TLBFLUSH_H */
index ce175af..b5843ee 100644 (file)
@@ -44,7 +44,6 @@ header-y += swab.h
 header-y += termbits.h
 header-y += termios.h
 header-y += traps.h
-header-y += types.h
 header-y += uctx.h
 header-y += unistd.h
 header-y += utrap.h
diff --git a/arch/sparc/include/uapi/asm/types.h b/arch/sparc/include/uapi/asm/types.h
deleted file mode 100644 (file)
index 383d156..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _SPARC_TYPES_H
-#define _SPARC_TYPES_H
-/*
- * This file is never included by application software unless
- * explicitly requested (e.g., via linux/types.h) in which case the
- * application is Linux specific so (user-) name space pollution is
- * not a major issue.  However, for interoperability, libraries still
- * need to be careful to avoid a name clashes.
- */
-
-#if defined(__sparc__)
-
-#include <asm-generic/int-ll64.h>
-
-#endif /* defined(__sparc__) */
-
-#endif /* defined(_SPARC_TYPES_H) */
index 537eb66..ca64d2a 100644 (file)
@@ -849,7 +849,7 @@ void smp_tsb_sync(struct mm_struct *mm)
 }
 
 extern unsigned long xcall_flush_tlb_mm;
-extern unsigned long xcall_flush_tlb_pending;
+extern unsigned long xcall_flush_tlb_page;
 extern unsigned long xcall_flush_tlb_kernel_range;
 extern unsigned long xcall_fetch_glob_regs;
 extern unsigned long xcall_fetch_glob_pmu;
@@ -1074,23 +1074,56 @@ local_flush_and_out:
        put_cpu();
 }
 
+struct tlb_pending_info {
+       unsigned long ctx;
+       unsigned long nr;
+       unsigned long *vaddrs;
+};
+
+static void tlb_pending_func(void *info)
+{
+       struct tlb_pending_info *t = info;
+
+       __flush_tlb_pending(t->ctx, t->nr, t->vaddrs);
+}
+
 void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long *vaddrs)
 {
        u32 ctx = CTX_HWBITS(mm->context);
+       struct tlb_pending_info info;
        int cpu = get_cpu();
 
+       info.ctx = ctx;
+       info.nr = nr;
+       info.vaddrs = vaddrs;
+
        if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
                cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
        else
-               smp_cross_call_masked(&xcall_flush_tlb_pending,
-                                     ctx, nr, (unsigned long) vaddrs,
-                                     mm_cpumask(mm));
+               smp_call_function_many(mm_cpumask(mm), tlb_pending_func,
+                                      &info, 1);
 
        __flush_tlb_pending(ctx, nr, vaddrs);
 
        put_cpu();
 }
 
+void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr)
+{
+       unsigned long context = CTX_HWBITS(mm->context);
+       int cpu = get_cpu();
+
+       if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
+               cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
+       else
+               smp_cross_call_masked(&xcall_flush_tlb_page,
+                                     context, vaddr, 0,
+                                     mm_cpumask(mm));
+       __flush_tlb_page(context, vaddr);
+
+       put_cpu();
+}
+
 void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
        start &= PAGE_MASK;
index 48d00e7..8ec4e9c 100644 (file)
@@ -119,11 +119,7 @@ void bit_map_clear(struct bit_map *t, int offset, int len)
 
 void bit_map_init(struct bit_map *t, unsigned long *map, int size)
 {
-
-       if ((size & 07) != 0)
-               BUG();
-       memset(map, 0, size>>3);
-
+       bitmap_zero(map, size);
        memset(t, 0, sizeof *t);
        spin_lock_init(&t->lock);
        t->map = map;
index 0f4f719..28f96f2 100644 (file)
@@ -34,7 +34,7 @@
 #define IOMMU_RNGE     IOMMU_RNGE_256MB
 #define IOMMU_START    0xF0000000
 #define IOMMU_WINSIZE  (256*1024*1024U)
-#define IOMMU_NPTES    (IOMMU_WINSIZE/PAGE_SIZE)       /* 64K PTEs, 265KB */
+#define IOMMU_NPTES    (IOMMU_WINSIZE/PAGE_SIZE)       /* 64K PTEs, 256KB */
 #define IOMMU_ORDER    6                               /* 4096 * (1<<6) */
 
 /* srmmu.c */
index c38bb72..036c279 100644 (file)
@@ -280,7 +280,9 @@ static void __init srmmu_nocache_init(void)
                SRMMU_NOCACHE_ALIGN_MAX, 0UL);
        memset(srmmu_nocache_pool, 0, srmmu_nocache_size);
 
-       srmmu_nocache_bitmap = __alloc_bootmem(bitmap_bits >> 3, SMP_CACHE_BYTES, 0UL);
+       srmmu_nocache_bitmap =
+               __alloc_bootmem(BITS_TO_LONGS(bitmap_bits) * sizeof(long),
+                               SMP_CACHE_BYTES, 0UL);
        bit_map_init(&srmmu_nocache_map, srmmu_nocache_bitmap, bitmap_bits);
 
        srmmu_swapper_pg_dir = __srmmu_get_nocache(SRMMU_PGD_TABLE_SIZE, SRMMU_PGD_TABLE_SIZE);
index ba6ae7f..83d89bc 100644 (file)
@@ -24,11 +24,17 @@ static DEFINE_PER_CPU(struct tlb_batch, tlb_batch);
 void flush_tlb_pending(void)
 {
        struct tlb_batch *tb = &get_cpu_var(tlb_batch);
+       struct mm_struct *mm = tb->mm;
 
-       if (tb->tlb_nr) {
-               flush_tsb_user(tb);
+       if (!tb->tlb_nr)
+               goto out;
 
-               if (CTX_VALID(tb->mm->context)) {
+       flush_tsb_user(tb);
+
+       if (CTX_VALID(mm->context)) {
+               if (tb->tlb_nr == 1) {
+                       global_flush_tlb_page(mm, tb->vaddrs[0]);
+               } else {
 #ifdef CONFIG_SMP
                        smp_flush_tlb_pending(tb->mm, tb->tlb_nr,
                                              &tb->vaddrs[0]);
@@ -37,12 +43,30 @@ void flush_tlb_pending(void)
                                            tb->tlb_nr, &tb->vaddrs[0]);
 #endif
                }
-               tb->tlb_nr = 0;
        }
 
+       tb->tlb_nr = 0;
+
+out:
        put_cpu_var(tlb_batch);
 }
 
+void arch_enter_lazy_mmu_mode(void)
+{
+       struct tlb_batch *tb = &__get_cpu_var(tlb_batch);
+
+       tb->active = 1;
+}
+
+void arch_leave_lazy_mmu_mode(void)
+{
+       struct tlb_batch *tb = &__get_cpu_var(tlb_batch);
+
+       if (tb->tlb_nr)
+               flush_tlb_pending();
+       tb->active = 0;
+}
+
 static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr,
                              bool exec)
 {
@@ -60,6 +84,12 @@ static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr,
                nr = 0;
        }
 
+       if (!tb->active) {
+               global_flush_tlb_page(mm, vaddr);
+               flush_tsb_user_page(mm, vaddr);
+               goto out;
+       }
+
        if (nr == 0)
                tb->mm = mm;
 
@@ -68,6 +98,7 @@ static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr,
        if (nr >= TLB_BATCH_NR)
                flush_tlb_pending();
 
+out:
        put_cpu_var(tlb_batch);
 }
 
index 428982b..2cc3bce 100644 (file)
@@ -7,11 +7,10 @@
 #include <linux/preempt.h>
 #include <linux/slab.h>
 #include <asm/page.h>
-#include <asm/tlbflush.h>
-#include <asm/tlb.h>
-#include <asm/mmu_context.h>
 #include <asm/pgtable.h>
+#include <asm/mmu_context.h>
 #include <asm/tsb.h>
+#include <asm/tlb.h>
 #include <asm/oplib.h>
 
 extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
@@ -46,23 +45,27 @@ void flush_tsb_kernel_range(unsigned long start, unsigned long end)
        }
 }
 
-static void __flush_tsb_one(struct tlb_batch *tb, unsigned long hash_shift,
-                           unsigned long tsb, unsigned long nentries)
+static void __flush_tsb_one_entry(unsigned long tsb, unsigned long v,
+                                 unsigned long hash_shift,
+                                 unsigned long nentries)
 {
-       unsigned long i;
+       unsigned long tag, ent, hash;
 
-       for (i = 0; i < tb->tlb_nr; i++) {
-               unsigned long v = tb->vaddrs[i];
-               unsigned long tag, ent, hash;
+       v &= ~0x1UL;
+       hash = tsb_hash(v, hash_shift, nentries);
+       ent = tsb + (hash * sizeof(struct tsb));
+       tag = (v >> 22UL);
 
-               v &= ~0x1UL;
+       tsb_flush(ent, tag);
+}
 
-               hash = tsb_hash(v, hash_shift, nentries);
-               ent = tsb + (hash * sizeof(struct tsb));
-               tag = (v >> 22UL);
+static void __flush_tsb_one(struct tlb_batch *tb, unsigned long hash_shift,
+                           unsigned long tsb, unsigned long nentries)
+{
+       unsigned long i;
 
-               tsb_flush(ent, tag);
-       }
+       for (i = 0; i < tb->tlb_nr; i++)
+               __flush_tsb_one_entry(tsb, tb->vaddrs[i], hash_shift, nentries);
 }
 
 void flush_tsb_user(struct tlb_batch *tb)
@@ -90,6 +93,30 @@ void flush_tsb_user(struct tlb_batch *tb)
        spin_unlock_irqrestore(&mm->context.lock, flags);
 }
 
+void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr)
+{
+       unsigned long nentries, base, flags;
+
+       spin_lock_irqsave(&mm->context.lock, flags);
+
+       base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb;
+       nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries;
+       if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+               base = __pa(base);
+       __flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, nentries);
+
+#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
+       if (mm->context.tsb_block[MM_TSB_HUGE].tsb) {
+               base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb;
+               nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries;
+               if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+                       base = __pa(base);
+               __flush_tsb_one_entry(base, vaddr, HPAGE_SHIFT, nentries);
+       }
+#endif
+       spin_unlock_irqrestore(&mm->context.lock, flags);
+}
+
 #define HV_PGSZ_IDX_BASE       HV_PGSZ_IDX_8K
 #define HV_PGSZ_MASK_BASE      HV_PGSZ_MASK_8K
 
index f8e13d4..432aa0c 100644 (file)
@@ -53,6 +53,33 @@ __flush_tlb_mm:              /* 18 insns */
        nop
 
        .align          32
+       .globl          __flush_tlb_page
+__flush_tlb_page:      /* 22 insns */
+       /* %o0 = context, %o1 = vaddr */
+       rdpr            %pstate, %g7
+       andn            %g7, PSTATE_IE, %g2
+       wrpr            %g2, %pstate
+       mov             SECONDARY_CONTEXT, %o4
+       ldxa            [%o4] ASI_DMMU, %g2
+       stxa            %o0, [%o4] ASI_DMMU
+       andcc           %o1, 1, %g0
+       andn            %o1, 1, %o3
+       be,pn           %icc, 1f
+        or             %o3, 0x10, %o3
+       stxa            %g0, [%o3] ASI_IMMU_DEMAP
+1:     stxa            %g0, [%o3] ASI_DMMU_DEMAP
+       membar          #Sync
+       stxa            %g2, [%o4] ASI_DMMU
+       sethi           %hi(KERNBASE), %o4
+       flush           %o4
+       retl
+        wrpr           %g7, 0x0, %pstate
+       nop
+       nop
+       nop
+       nop
+
+       .align          32
        .globl          __flush_tlb_pending
 __flush_tlb_pending:   /* 26 insns */
        /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
@@ -203,6 +230,31 @@ __cheetah_flush_tlb_mm: /* 19 insns */
        retl
         wrpr           %g7, 0x0, %pstate
 
+__cheetah_flush_tlb_page:      /* 22 insns */
+       /* %o0 = context, %o1 = vaddr */
+       rdpr            %pstate, %g7
+       andn            %g7, PSTATE_IE, %g2
+       wrpr            %g2, 0x0, %pstate
+       wrpr            %g0, 1, %tl
+       mov             PRIMARY_CONTEXT, %o4
+       ldxa            [%o4] ASI_DMMU, %g2
+       srlx            %g2, CTX_PGSZ1_NUC_SHIFT, %o3
+       sllx            %o3, CTX_PGSZ1_NUC_SHIFT, %o3
+       or              %o0, %o3, %o0   /* Preserve nucleus page size fields */
+       stxa            %o0, [%o4] ASI_DMMU
+       andcc           %o1, 1, %g0
+       be,pn           %icc, 1f
+        andn           %o1, 1, %o3
+       stxa            %g0, [%o3] ASI_IMMU_DEMAP
+1:     stxa            %g0, [%o3] ASI_DMMU_DEMAP       
+       membar          #Sync
+       stxa            %g2, [%o4] ASI_DMMU
+       sethi           %hi(KERNBASE), %o4
+       flush           %o4
+       wrpr            %g0, 0, %tl
+       retl
+        wrpr           %g7, 0x0, %pstate
+
 __cheetah_flush_tlb_pending:   /* 27 insns */
        /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
        rdpr            %pstate, %g7
@@ -269,6 +321,20 @@ __hypervisor_flush_tlb_mm: /* 10 insns */
        retl
         nop
 
+__hypervisor_flush_tlb_page: /* 11 insns */
+       /* %o0 = context, %o1 = vaddr */
+       mov             %o0, %g2
+       mov             %o1, %o0              /* ARG0: vaddr + IMMU-bit */
+       mov             %g2, %o1              /* ARG1: mmu context */
+       mov             HV_MMU_ALL, %o2       /* ARG2: flags */
+       srlx            %o0, PAGE_SHIFT, %o0
+       sllx            %o0, PAGE_SHIFT, %o0
+       ta              HV_MMU_UNMAP_ADDR_TRAP
+       brnz,pn         %o0, __hypervisor_tlb_tl0_error
+        mov            HV_MMU_UNMAP_ADDR_TRAP, %o1
+       retl
+        nop
+
 __hypervisor_flush_tlb_pending: /* 16 insns */
        /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
        sllx            %o1, 3, %g1
@@ -339,6 +405,13 @@ cheetah_patch_cachetlbops:
        call            tlb_patch_one
         mov            19, %o2
 
+       sethi           %hi(__flush_tlb_page), %o0
+       or              %o0, %lo(__flush_tlb_page), %o0
+       sethi           %hi(__cheetah_flush_tlb_page), %o1
+       or              %o1, %lo(__cheetah_flush_tlb_page), %o1
+       call            tlb_patch_one
+        mov            22, %o2
+
        sethi           %hi(__flush_tlb_pending), %o0
        or              %o0, %lo(__flush_tlb_pending), %o0
        sethi           %hi(__cheetah_flush_tlb_pending), %o1
@@ -397,10 +470,9 @@ xcall_flush_tlb_mm:        /* 21 insns */
        nop
        nop
 
-       .globl          xcall_flush_tlb_pending
-xcall_flush_tlb_pending:       /* 21 insns */
-       /* %g5=context, %g1=nr, %g7=vaddrs[] */
-       sllx            %g1, 3, %g1
+       .globl          xcall_flush_tlb_page
+xcall_flush_tlb_page:  /* 17 insns */
+       /* %g5=context, %g1=vaddr */
        mov             PRIMARY_CONTEXT, %g4
        ldxa            [%g4] ASI_DMMU, %g2
        srlx            %g2, CTX_PGSZ1_NUC_SHIFT, %g4
@@ -408,20 +480,16 @@ xcall_flush_tlb_pending:  /* 21 insns */
        or              %g5, %g4, %g5
        mov             PRIMARY_CONTEXT, %g4
        stxa            %g5, [%g4] ASI_DMMU
-1:     sub             %g1, (1 << 3), %g1
-       ldx             [%g7 + %g1], %g5
-       andcc           %g5, 0x1, %g0
+       andcc           %g1, 0x1, %g0
        be,pn           %icc, 2f
-
-        andn           %g5, 0x1, %g5
+        andn           %g1, 0x1, %g5
        stxa            %g0, [%g5] ASI_IMMU_DEMAP
 2:     stxa            %g0, [%g5] ASI_DMMU_DEMAP
        membar          #Sync
-       brnz,pt         %g1, 1b
-        nop
        stxa            %g2, [%g4] ASI_DMMU
        retry
        nop
+       nop
 
        .globl          xcall_flush_tlb_kernel_range
 xcall_flush_tlb_kernel_range:  /* 25 insns */
@@ -656,15 +724,13 @@ __hypervisor_xcall_flush_tlb_mm: /* 21 insns */
        membar          #Sync
        retry
 
-       .globl          __hypervisor_xcall_flush_tlb_pending
-__hypervisor_xcall_flush_tlb_pending: /* 21 insns */
-       /* %g5=ctx, %g1=nr, %g7=vaddrs[], %g2,%g3,%g4,g6=scratch */
-       sllx            %g1, 3, %g1
+       .globl          __hypervisor_xcall_flush_tlb_page
+__hypervisor_xcall_flush_tlb_page: /* 17 insns */
+       /* %g5=ctx, %g1=vaddr */
        mov             %o0, %g2
        mov             %o1, %g3
        mov             %o2, %g4
-1:     sub             %g1, (1 << 3), %g1
-       ldx             [%g7 + %g1], %o0        /* ARG0: virtual address */
+       mov             %g1, %o0                /* ARG0: virtual address */
        mov             %g5, %o1                /* ARG1: mmu context */
        mov             HV_MMU_ALL, %o2         /* ARG2: flags */
        srlx            %o0, PAGE_SHIFT, %o0
@@ -673,8 +739,6 @@ __hypervisor_xcall_flush_tlb_pending: /* 21 insns */
        mov             HV_MMU_UNMAP_ADDR_TRAP, %g6
        brnz,a,pn       %o0, __hypervisor_tlb_xcall_error
         mov            %o0, %g5
-       brnz,pt         %g1, 1b
-        nop
        mov             %g2, %o0
        mov             %g3, %o1
        mov             %g4, %o2
@@ -757,6 +821,13 @@ hypervisor_patch_cachetlbops:
        call            tlb_patch_one
         mov            10, %o2
 
+       sethi           %hi(__flush_tlb_page), %o0
+       or              %o0, %lo(__flush_tlb_page), %o0
+       sethi           %hi(__hypervisor_flush_tlb_page), %o1
+       or              %o1, %lo(__hypervisor_flush_tlb_page), %o1
+       call            tlb_patch_one
+        mov            11, %o2
+
        sethi           %hi(__flush_tlb_pending), %o0
        or              %o0, %lo(__flush_tlb_pending), %o0
        sethi           %hi(__hypervisor_flush_tlb_pending), %o1
@@ -788,12 +859,12 @@ hypervisor_patch_cachetlbops:
        call            tlb_patch_one
         mov            21, %o2
 
-       sethi           %hi(xcall_flush_tlb_pending), %o0
-       or              %o0, %lo(xcall_flush_tlb_pending), %o0
-       sethi           %hi(__hypervisor_xcall_flush_tlb_pending), %o1
-       or              %o1, %lo(__hypervisor_xcall_flush_tlb_pending), %o1
+       sethi           %hi(xcall_flush_tlb_page), %o0
+       or              %o0, %lo(xcall_flush_tlb_page), %o0
+       sethi           %hi(__hypervisor_xcall_flush_tlb_page), %o1
+       or              %o1, %lo(__hypervisor_xcall_flush_tlb_page), %o1
        call            tlb_patch_one
-        mov            21, %o2
+        mov            17, %o2
 
        sethi           %hi(xcall_flush_tlb_kernel_range), %o0
        or              %o0, %lo(xcall_flush_tlb_kernel_range), %o0
index 70c0f3d..15b5cef 100644 (file)
@@ -1549,6 +1549,7 @@ config X86_SMAP
 config EFI
        bool "EFI runtime service support"
        depends on ACPI
+       select UCS2_STRING
        ---help---
          This enables the kernel to use EFI runtime services that are
          available (such as the EFI variable services).
index c205035..35ee62f 100644 (file)
@@ -251,6 +251,51 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size)
        *size = len;
 }
 
+static efi_status_t setup_efi_vars(struct boot_params *params)
+{
+       struct setup_data *data;
+       struct efi_var_bootdata *efidata;
+       u64 store_size, remaining_size, var_size;
+       efi_status_t status;
+
+       if (sys_table->runtime->hdr.revision < EFI_2_00_SYSTEM_TABLE_REVISION)
+               return EFI_UNSUPPORTED;
+
+       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+
+       while (data && data->next)
+               data = (struct setup_data *)(unsigned long)data->next;
+
+       status = efi_call_phys4((void *)sys_table->runtime->query_variable_info,
+                               EFI_VARIABLE_NON_VOLATILE |
+                               EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                               EFI_VARIABLE_RUNTIME_ACCESS, &store_size,
+                               &remaining_size, &var_size);
+
+       if (status != EFI_SUCCESS)
+               return status;
+
+       status = efi_call_phys3(sys_table->boottime->allocate_pool,
+                               EFI_LOADER_DATA, sizeof(*efidata), &efidata);
+
+       if (status != EFI_SUCCESS)
+               return status;
+
+       efidata->data.type = SETUP_EFI_VARS;
+       efidata->data.len = sizeof(struct efi_var_bootdata) -
+               sizeof(struct setup_data);
+       efidata->data.next = 0;
+       efidata->store_size = store_size;
+       efidata->remaining_size = remaining_size;
+       efidata->max_var_size = var_size;
+
+       if (data)
+               data->next = (unsigned long)efidata;
+       else
+               params->hdr.setup_data = (unsigned long)efidata;
+
+}
+
 static efi_status_t setup_efi_pci(struct boot_params *params)
 {
        efi_pci_io_protocol *pci;
@@ -1157,6 +1202,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
 
        setup_graphics(boot_params);
 
+       setup_efi_vars(boot_params);
+
        setup_efi_pci(boot_params);
 
        status = efi_call_phys3(sys_table->boottime->allocate_pool,
index 60c89f3..2fb5d58 100644 (file)
@@ -102,6 +102,13 @@ extern void efi_call_phys_epilog(void);
 extern void efi_unmap_memmap(void);
 extern void efi_memory_uc(u64 addr, unsigned long size);
 
+struct efi_var_bootdata {
+       struct setup_data data;
+       u64 store_size;
+       u64 remaining_size;
+       u64 max_var_size;
+};
+
 #ifdef CONFIG_EFI
 
 static inline bool efi_is_native(void)
index c15ddaf..0874424 100644 (file)
@@ -6,6 +6,7 @@
 #define SETUP_E820_EXT                 1
 #define SETUP_DTB                      2
 #define SETUP_PCI                      3
+#define SETUP_EFI_VARS                 4
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK       0x07FF
index a7d26d8..8f4be53 100644 (file)
@@ -35,13 +35,6 @@ static bool __init ms_hyperv_platform(void)
        if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))
                return false;
 
-       /*
-        * Xen emulates Hyper-V to support enlightened Windows.
-        * Check to see first if we are on a Xen Hypervisor.
-        */
-       if (xen_cpuid_base())
-               return false;
-
        cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
              &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
 
@@ -82,12 +75,6 @@ static void __init ms_hyperv_init_platform(void)
 
        if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
                clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
-#if IS_ENABLED(CONFIG_HYPERV)
-       /*
-        * Setup the IDT for hypervisor callback.
-        */
-       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
-#endif
 }
 
 const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
@@ -103,6 +90,11 @@ static irq_handler_t vmbus_isr;
 
 void hv_register_vmbus_handler(int irq, irq_handler_t handler)
 {
+       /*
+        * Setup the IDT for hypervisor callback.
+        */
+       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
+
        vmbus_irq = irq;
        vmbus_isr = handler;
 }
index dab7580..cc45deb 100644 (file)
@@ -153,8 +153,14 @@ static struct event_constraint intel_gen_event_constraints[] __read_mostly =
 };
 
 static struct extra_reg intel_snb_extra_regs[] __read_mostly = {
-       INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0x3fffffffffull, RSP_0),
-       INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0x3fffffffffull, RSP_1),
+       INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0x3f807f8fffull, RSP_0),
+       INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0x3f807f8fffull, RSP_1),
+       EVENT_EXTRA_END
+};
+
+static struct extra_reg intel_snbep_extra_regs[] __read_mostly = {
+       INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0x3fffff8fffull, RSP_0),
+       INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0x3fffff8fffull, RSP_1),
        EVENT_EXTRA_END
 };
 
@@ -2097,7 +2103,10 @@ __init int intel_pmu_init(void)
                x86_pmu.event_constraints = intel_snb_event_constraints;
                x86_pmu.pebs_constraints = intel_snb_pebs_event_constraints;
                x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
-               x86_pmu.extra_regs = intel_snb_extra_regs;
+               if (boot_cpu_data.x86_model == 45)
+                       x86_pmu.extra_regs = intel_snbep_extra_regs;
+               else
+                       x86_pmu.extra_regs = intel_snb_extra_regs;
                /* all extra regs are per-cpu when HT is on */
                x86_pmu.er_flags |= ERF_HAS_RSP_1;
                x86_pmu.er_flags |= ERF_NO_HT_SHARING;
@@ -2123,7 +2132,10 @@ __init int intel_pmu_init(void)
                x86_pmu.event_constraints = intel_ivb_event_constraints;
                x86_pmu.pebs_constraints = intel_ivb_pebs_event_constraints;
                x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
-               x86_pmu.extra_regs = intel_snb_extra_regs;
+               if (boot_cpu_data.x86_model == 62)
+                       x86_pmu.extra_regs = intel_snbep_extra_regs;
+               else
+                       x86_pmu.extra_regs = intel_snb_extra_regs;
                /* all extra regs are per-cpu when HT is on */
                x86_pmu.er_flags |= ERF_HAS_RSP_1;
                x86_pmu.er_flags |= ERF_NO_HT_SHARING;
index 577db84..833d51d 100644 (file)
@@ -45,9 +45,6 @@ static int __cpuinit x86_vendor(void)
        u32 eax = 0x00000000;
        u32 ebx, ecx = 0, edx;
 
-       if (!have_cpuid_p())
-               return X86_VENDOR_UNKNOWN;
-
        native_cpuid(&eax, &ebx, &ecx, &edx);
 
        if (CPUID_IS(CPUID_INTEL1, CPUID_INTEL2, CPUID_INTEL3, ebx, ecx, edx))
@@ -59,18 +56,45 @@ static int __cpuinit x86_vendor(void)
        return X86_VENDOR_UNKNOWN;
 }
 
+static int __cpuinit x86_family(void)
+{
+       u32 eax = 0x00000001;
+       u32 ebx, ecx = 0, edx;
+       int x86;
+
+       native_cpuid(&eax, &ebx, &ecx, &edx);
+
+       x86 = (eax >> 8) & 0xf;
+       if (x86 == 15)
+               x86 += (eax >> 20) & 0xff;
+
+       return x86;
+}
+
 void __init load_ucode_bsp(void)
 {
-       int vendor = x86_vendor();
+       int vendor, x86;
+
+       if (!have_cpuid_p())
+               return;
 
-       if (vendor == X86_VENDOR_INTEL)
+       vendor = x86_vendor();
+       x86 = x86_family();
+
+       if (vendor == X86_VENDOR_INTEL && x86 >= 6)
                load_ucode_intel_bsp();
 }
 
 void __cpuinit load_ucode_ap(void)
 {
-       int vendor = x86_vendor();
+       int vendor, x86;
+
+       if (!have_cpuid_p())
+               return;
+
+       vendor = x86_vendor();
+       x86 = x86_family();
 
-       if (vendor == X86_VENDOR_INTEL)
+       if (vendor == X86_VENDOR_INTEL && x86 >= 6)
                load_ucode_intel_ap();
 }
index 90d8cc9..fae9134 100644 (file)
@@ -507,11 +507,14 @@ static void __init memblock_x86_reserve_range_setup_data(void)
 /*
  * Keep the crash kernel below this limit.  On 32 bits earlier kernels
  * would limit the kernel to the low 512 MiB due to mapping restrictions.
+ * On 64bit, old kexec-tools need to under 896MiB.
  */
 #ifdef CONFIG_X86_32
-# define CRASH_KERNEL_ADDR_MAX (512 << 20)
+# define CRASH_KERNEL_ADDR_LOW_MAX     (512 << 20)
+# define CRASH_KERNEL_ADDR_HIGH_MAX    (512 << 20)
 #else
-# define CRASH_KERNEL_ADDR_MAX MAXMEM
+# define CRASH_KERNEL_ADDR_LOW_MAX     (896UL<<20)
+# define CRASH_KERNEL_ADDR_HIGH_MAX    MAXMEM
 #endif
 
 static void __init reserve_crashkernel_low(void)
@@ -521,19 +524,35 @@ static void __init reserve_crashkernel_low(void)
        unsigned long long low_base = 0, low_size = 0;
        unsigned long total_low_mem;
        unsigned long long base;
+       bool auto_set = false;
        int ret;
 
        total_low_mem = memblock_mem_size(1UL<<(32-PAGE_SHIFT));
+       /* crashkernel=Y,low */
        ret = parse_crashkernel_low(boot_command_line, total_low_mem,
                                                &low_size, &base);
-       if (ret != 0 || low_size <= 0)
-               return;
+       if (ret != 0) {
+               /*
+                * two parts from lib/swiotlb.c:
+                *      swiotlb size: user specified with swiotlb= or default.
+                *      swiotlb overflow buffer: now is hardcoded to 32k.
+                *              We round it to 8M for other buffers that
+                *              may need to stay low too.
+                */
+               low_size = swiotlb_size_or_default() + (8UL<<20);
+               auto_set = true;
+       } else {
+               /* passed with crashkernel=0,low ? */
+               if (!low_size)
+                       return;
+       }
 
        low_base = memblock_find_in_range(low_size, (1ULL<<32),
                                        low_size, alignment);
 
        if (!low_base) {
-               pr_info("crashkernel low reservation failed - No suitable area found.\n");
+               if (!auto_set)
+                       pr_info("crashkernel low reservation failed - No suitable area found.\n");
 
                return;
        }
@@ -554,14 +573,22 @@ static void __init reserve_crashkernel(void)
        const unsigned long long alignment = 16<<20;    /* 16M */
        unsigned long long total_mem;
        unsigned long long crash_size, crash_base;
+       bool high = false;
        int ret;
 
        total_mem = memblock_phys_mem_size();
 
+       /* crashkernel=XM */
        ret = parse_crashkernel(boot_command_line, total_mem,
                        &crash_size, &crash_base);
-       if (ret != 0 || crash_size <= 0)
-               return;
+       if (ret != 0 || crash_size <= 0) {
+               /* crashkernel=X,high */
+               ret = parse_crashkernel_high(boot_command_line, total_mem,
+                               &crash_size, &crash_base);
+               if (ret != 0 || crash_size <= 0)
+                       return;
+               high = true;
+       }
 
        /* 0 means: find the address automatically */
        if (crash_base <= 0) {
@@ -569,7 +596,9 @@ static void __init reserve_crashkernel(void)
                 *  kexec want bzImage is below CRASH_KERNEL_ADDR_MAX
                 */
                crash_base = memblock_find_in_range(alignment,
-                              CRASH_KERNEL_ADDR_MAX, crash_size, alignment);
+                                       high ? CRASH_KERNEL_ADDR_HIGH_MAX :
+                                              CRASH_KERNEL_ADDR_LOW_MAX,
+                                       crash_size, alignment);
 
                if (!crash_base) {
                        pr_info("crashkernel reservation failed - No suitable area found.\n");
index 901177d..305c68b 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/sched.h>
 #include <linux/pci.h>
+#include <linux/pci-acpi.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/dmi.h>
@@ -170,6 +171,16 @@ void pcibios_fixup_bus(struct pci_bus *b)
                pcibios_fixup_device_resources(dev);
 }
 
+void pcibios_add_bus(struct pci_bus *bus)
+{
+       acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+       acpi_pci_remove_bus(bus);
+}
+
 /*
  * Only use DMI information to set this if nothing was passed
  * on the kernel command line (which was parsed earlier).
index 94e7662..4a9be6d 100644 (file)
@@ -177,7 +177,7 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                goto error;
        i = 0;
        list_for_each_entry(msidesc, &dev->msi_list, list) {
-               irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0,
+               irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i],
                                               (type == PCI_CAP_ID_MSIX) ?
                                               "pcifront-msi-x" :
                                               "pcifront-msi",
@@ -244,7 +244,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                        dev_dbg(&dev->dev,
                                "xen: msi already bound to pirq=%d\n", pirq);
                }
-               irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0,
+               irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq,
                                               (type == PCI_CAP_ID_MSIX) ?
                                               "msi-x" : "msi",
                                               DOMID_SELF);
@@ -326,7 +326,7 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                }
 
                ret = xen_bind_pirq_msi_to_irq(dev, msidesc,
-                                              map_irq.pirq, map_irq.index,
+                                              map_irq.pirq,
                                               (type == PCI_CAP_ID_MSIX) ?
                                               "msi-x" : "msi",
                                                domid);
index 5f2ecaf..e4a86a6 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/io.h>
 #include <linux/reboot.h>
 #include <linux/bcd.h>
+#include <linux/ucs2_string.h>
 
 #include <asm/setup.h>
 #include <asm/efi.h>
 
 #define EFI_DEBUG      1
 
+/*
+ * There's some additional metadata associated with each
+ * variable. Intel's reference implementation is 60 bytes - bump that
+ * to account for potential alignment constraints
+ */
+#define VAR_METADATA_SIZE 64
+
 struct efi __read_mostly efi = {
        .mps        = EFI_INVALID_TABLE_ADDR,
        .acpi       = EFI_INVALID_TABLE_ADDR,
@@ -69,6 +77,13 @@ struct efi_memory_map memmap;
 static struct efi efi_phys __initdata;
 static efi_system_table_t efi_systab __initdata;
 
+static u64 efi_var_store_size;
+static u64 efi_var_remaining_size;
+static u64 efi_var_max_var_size;
+static u64 boot_used_size;
+static u64 boot_var_size;
+static u64 active_size;
+
 unsigned long x86_efi_facility;
 
 /*
@@ -98,6 +113,15 @@ static int __init setup_add_efi_memmap(char *arg)
 }
 early_param("add_efi_memmap", setup_add_efi_memmap);
 
+static bool efi_no_storage_paranoia;
+
+static int __init setup_storage_paranoia(char *arg)
+{
+       efi_no_storage_paranoia = true;
+       return 0;
+}
+early_param("efi_no_storage_paranoia", setup_storage_paranoia);
+
 
 static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
 {
@@ -162,8 +186,53 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
                                               efi_char16_t *name,
                                               efi_guid_t *vendor)
 {
-       return efi_call_virt3(get_next_variable,
-                             name_size, name, vendor);
+       efi_status_t status;
+       static bool finished = false;
+       static u64 var_size;
+
+       status = efi_call_virt3(get_next_variable,
+                               name_size, name, vendor);
+
+       if (status == EFI_NOT_FOUND) {
+               finished = true;
+               if (var_size < boot_used_size) {
+                       boot_var_size = boot_used_size - var_size;
+                       active_size += boot_var_size;
+               } else {
+                       printk(KERN_WARNING FW_BUG  "efi: Inconsistent initial sizes\n");
+               }
+       }
+
+       if (boot_used_size && !finished) {
+               unsigned long size;
+               u32 attr;
+               efi_status_t s;
+               void *tmp;
+
+               s = virt_efi_get_variable(name, vendor, &attr, &size, NULL);
+
+               if (s != EFI_BUFFER_TOO_SMALL || !size)
+                       return status;
+
+               tmp = kmalloc(size, GFP_ATOMIC);
+
+               if (!tmp)
+                       return status;
+
+               s = virt_efi_get_variable(name, vendor, &attr, &size, tmp);
+
+               if (s == EFI_SUCCESS && (attr & EFI_VARIABLE_NON_VOLATILE)) {
+                       var_size += size;
+                       var_size += ucs2_strsize(name, 1024);
+                       active_size += size;
+                       active_size += VAR_METADATA_SIZE;
+                       active_size += ucs2_strsize(name, 1024);
+               }
+
+               kfree(tmp);
+       }
+
+       return status;
 }
 
 static efi_status_t virt_efi_set_variable(efi_char16_t *name,
@@ -172,9 +241,34 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
                                          unsigned long data_size,
                                          void *data)
 {
-       return efi_call_virt5(set_variable,
-                             name, vendor, attr,
-                             data_size, data);
+       efi_status_t status;
+       u32 orig_attr = 0;
+       unsigned long orig_size = 0;
+
+       status = virt_efi_get_variable(name, vendor, &orig_attr, &orig_size,
+                                      NULL);
+
+       if (status != EFI_BUFFER_TOO_SMALL)
+               orig_size = 0;
+
+       status = efi_call_virt5(set_variable,
+                               name, vendor, attr,
+                               data_size, data);
+
+       if (status == EFI_SUCCESS) {
+               if (orig_size) {
+                       active_size -= orig_size;
+                       active_size -= ucs2_strsize(name, 1024);
+                       active_size -= VAR_METADATA_SIZE;
+               }
+               if (data_size) {
+                       active_size += data_size;
+                       active_size += ucs2_strsize(name, 1024);
+                       active_size += VAR_METADATA_SIZE;
+               }
+       }
+
+       return status;
 }
 
 static efi_status_t virt_efi_query_variable_info(u32 attr,
@@ -682,6 +776,9 @@ void __init efi_init(void)
        char vendor[100] = "unknown";
        int i = 0;
        void *tmp;
+       struct setup_data *data;
+       struct efi_var_bootdata *efi_var_data;
+       u64 pa_data;
 
 #ifdef CONFIG_X86_32
        if (boot_params.efi_info.efi_systab_hi ||
@@ -699,6 +796,22 @@ void __init efi_init(void)
        if (efi_systab_init(efi_phys.systab))
                return;
 
+       pa_data = boot_params.hdr.setup_data;
+       while (pa_data) {
+               data = early_ioremap(pa_data, sizeof(*efi_var_data));
+               if (data->type == SETUP_EFI_VARS) {
+                       efi_var_data = (struct efi_var_bootdata *)data;
+
+                       efi_var_store_size = efi_var_data->store_size;
+                       efi_var_remaining_size = efi_var_data->remaining_size;
+                       efi_var_max_var_size = efi_var_data->max_var_size;
+               }
+               pa_data = data->next;
+               early_iounmap(data, sizeof(*efi_var_data));
+       }
+
+       boot_used_size = efi_var_store_size - efi_var_remaining_size;
+
        set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
 
        /*
@@ -999,3 +1112,48 @@ u64 efi_mem_attributes(unsigned long phys_addr)
        }
        return 0;
 }
+
+/*
+ * Some firmware has serious problems when using more than 50% of the EFI
+ * variable store, i.e. it triggers bugs that can brick machines. Ensure that
+ * we never use more than this safe limit.
+ *
+ * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
+ * store.
+ */
+efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
+{
+       efi_status_t status;
+       u64 storage_size, remaining_size, max_size;
+
+       status = efi.query_variable_info(attributes, &storage_size,
+                                        &remaining_size, &max_size);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       if (!max_size && remaining_size > size)
+               printk_once(KERN_ERR FW_BUG "Broken EFI implementation"
+                           " is returning MaxVariableSize=0\n");
+       /*
+        * Some firmware implementations refuse to boot if there's insufficient
+        * space in the variable store. We account for that by refusing the
+        * write if permitting it would reduce the available space to under
+        * 50%. However, some firmware won't reclaim variable space until
+        * after the used (not merely the actively used) space drops below
+        * a threshold. We can approximate that case with the value calculated
+        * above. If both the firmware and our calculations indicate that the
+        * available space would drop below 50%, refuse the write.
+        */
+
+       if (!storage_size || size > remaining_size ||
+           (max_size && size > max_size))
+               return EFI_OUT_OF_RESOURCES;
+
+       if (!efi_no_storage_paranoia &&
+           ((active_size + size + VAR_METADATA_SIZE > storage_size / 2) &&
+            (remaining_size - size < storage_size / 2)))
+               return EFI_OUT_OF_RESOURCES;
+
+       return EFI_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(efi_query_variable_store);
index c8e1c7b..ddbd54a 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/pci.h>
 #include <linux/gfp.h>
 #include <linux/memblock.h>
+#include <linux/edd.h>
 
 #include <xen/xen.h>
 #include <xen/events.h>
@@ -1306,6 +1307,55 @@ static const struct machine_ops xen_machine_ops __initconst = {
        .emergency_restart = xen_emergency_restart,
 };
 
+static void __init xen_boot_params_init_edd(void)
+{
+#if IS_ENABLED(CONFIG_EDD)
+       struct xen_platform_op op;
+       struct edd_info *edd_info;
+       u32 *mbr_signature;
+       unsigned nr;
+       int ret;
+
+       edd_info = boot_params.eddbuf;
+       mbr_signature = boot_params.edd_mbr_sig_buffer;
+
+       op.cmd = XENPF_firmware_info;
+
+       op.u.firmware_info.type = XEN_FW_DISK_INFO;
+       for (nr = 0; nr < EDDMAXNR; nr++) {
+               struct edd_info *info = edd_info + nr;
+
+               op.u.firmware_info.index = nr;
+               info->params.length = sizeof(info->params);
+               set_xen_guest_handle(op.u.firmware_info.u.disk_info.edd_params,
+                                    &info->params);
+               ret = HYPERVISOR_dom0_op(&op);
+               if (ret)
+                       break;
+
+#define C(x) info->x = op.u.firmware_info.u.disk_info.x
+               C(device);
+               C(version);
+               C(interface_support);
+               C(legacy_max_cylinder);
+               C(legacy_max_head);
+               C(legacy_sectors_per_track);
+#undef C
+       }
+       boot_params.eddbuf_entries = nr;
+
+       op.u.firmware_info.type = XEN_FW_DISK_MBR_SIGNATURE;
+       for (nr = 0; nr < EDD_MBR_SIG_MAX; nr++) {
+               op.u.firmware_info.index = nr;
+               ret = HYPERVISOR_dom0_op(&op);
+               if (ret)
+                       break;
+               mbr_signature[nr] = op.u.firmware_info.u.disk_mbr_signature.mbr_signature;
+       }
+       boot_params.edd_mbr_sig_buf_entries = nr;
+#endif
+}
+
 /*
  * Set up the GDT and segment registers for -fstack-protector.  Until
  * we do this, we have to be careful not to call any stack-protected
@@ -1508,6 +1558,8 @@ asmlinkage void __init xen_start_kernel(void)
                /* Avoid searching for BIOS MP tables */
                x86_init.mpparse.find_smp_config = x86_init_noop;
                x86_init.mpparse.get_smp_config = x86_init_uint_noop;
+
+               xen_boot_params_init_edd();
        }
 #ifdef CONFIG_PCI
        /* PCI BIOS service won't work from a PV guest. */
@@ -1589,8 +1641,11 @@ static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self,
        switch (action) {
        case CPU_UP_PREPARE:
                xen_vcpu_setup(cpu);
-               if (xen_have_vector_callback)
+               if (xen_have_vector_callback) {
                        xen_init_lock_cpu(cpu);
+                       if (xen_feature(XENFEAT_hvm_safe_pvclock))
+                               xen_setup_timer(cpu);
+               }
                break;
        default:
                break;
index 09ea61d..0d466d7 100644 (file)
@@ -144,6 +144,13 @@ static int xen_smp_intr_init(unsigned int cpu)
                goto fail;
        per_cpu(xen_callfuncsingle_irq, cpu) = rc;
 
+       /*
+        * The IRQ worker on PVHVM goes through the native path and uses the
+        * IPI mechanism.
+        */
+       if (xen_hvm_domain())
+               return 0;
+
        callfunc_name = kasprintf(GFP_KERNEL, "irqwork%d", cpu);
        rc = bind_ipi_to_irqhandler(XEN_IRQ_WORK_VECTOR,
                                    cpu,
@@ -167,6 +174,9 @@ static int xen_smp_intr_init(unsigned int cpu)
        if (per_cpu(xen_callfuncsingle_irq, cpu) >= 0)
                unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu),
                                       NULL);
+       if (xen_hvm_domain())
+               return rc;
+
        if (per_cpu(xen_irq_work, cpu) >= 0)
                unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
 
@@ -418,7 +428,7 @@ static int xen_cpu_disable(void)
 
 static void xen_cpu_die(unsigned int cpu)
 {
-       while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
+       while (xen_pv_domain() && HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
                current->state = TASK_UNINTERRUPTIBLE;
                schedule_timeout(HZ/10);
        }
@@ -426,7 +436,8 @@ static void xen_cpu_die(unsigned int cpu)
        unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
        unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
        unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL);
-       unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
+       if (!xen_hvm_domain())
+               unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
        xen_uninit_lock_cpu(cpu);
        xen_teardown_timer(cpu);
 }
@@ -657,11 +668,7 @@ static int __cpuinit xen_hvm_cpu_up(unsigned int cpu, struct task_struct *tidle)
 
 static void xen_hvm_cpu_die(unsigned int cpu)
 {
-       unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu), NULL);
-       unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
-       unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
-       unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL);
-       unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
+       xen_cpu_die(cpu);
        native_cpu_die(cpu);
 }
 
index f7a080e..8b54603 100644 (file)
@@ -364,6 +364,16 @@ void __cpuinit xen_init_lock_cpu(int cpu)
        int irq;
        const char *name;
 
+       WARN(per_cpu(lock_kicker_irq, cpu) > 0, "spinlock on CPU%d exists on IRQ%d!\n",
+            cpu, per_cpu(lock_kicker_irq, cpu));
+
+       /*
+        * See git commit f10cd522c5fbfec9ae3cc01967868c9c2401ed23
+        * (xen: disable PV spinlocks on HVM)
+        */
+       if (xen_hvm_domain())
+               return;
+
        name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
        irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
                                     cpu,
@@ -382,11 +392,26 @@ void __cpuinit xen_init_lock_cpu(int cpu)
 
 void xen_uninit_lock_cpu(int cpu)
 {
+       /*
+        * See git commit f10cd522c5fbfec9ae3cc01967868c9c2401ed23
+        * (xen: disable PV spinlocks on HVM)
+        */
+       if (xen_hvm_domain())
+               return;
+
        unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
+       per_cpu(lock_kicker_irq, cpu) = -1;
 }
 
 void __init xen_init_spinlocks(void)
 {
+       /*
+        * See git commit f10cd522c5fbfec9ae3cc01967868c9c2401ed23
+        * (xen: disable PV spinlocks on HVM)
+        */
+       if (xen_hvm_domain())
+               return;
+
        BUILD_BUG_ON(sizeof(struct xen_spinlock) > sizeof(arch_spinlock_t));
 
        pv_lock_ops.spin_is_locked = xen_spin_is_locked;
index 0296a95..3d88bfd 100644 (file)
@@ -377,7 +377,7 @@ static const struct clock_event_device xen_vcpuop_clockevent = {
 
 static const struct clock_event_device *xen_clockevent =
        &xen_timerop_clockevent;
-static DEFINE_PER_CPU(struct clock_event_device, xen_clock_events);
+static DEFINE_PER_CPU(struct clock_event_device, xen_clock_events) = { .irq = -1 };
 
 static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
 {
@@ -401,6 +401,9 @@ void xen_setup_timer(int cpu)
        struct clock_event_device *evt;
        int irq;
 
+       evt = &per_cpu(xen_clock_events, cpu);
+       WARN(evt->irq >= 0, "IRQ%d for CPU%d is already allocated\n", evt->irq, cpu);
+
        printk(KERN_INFO "installing Xen timer for CPU %d\n", cpu);
 
        name = kasprintf(GFP_KERNEL, "timer%d", cpu);
@@ -413,7 +416,6 @@ void xen_setup_timer(int cpu)
                                      IRQF_FORCE_RESUME,
                                      name, NULL);
 
-       evt = &per_cpu(xen_clock_events, cpu);
        memcpy(evt, xen_clockevent, sizeof(*evt));
 
        evt->cpumask = cpumask_of(cpu);
@@ -426,6 +428,7 @@ void xen_teardown_timer(int cpu)
        BUG_ON(cpu == 0);
        evt = &per_cpu(xen_clock_events, cpu);
        unbind_from_irqhandler(evt->irq, NULL);
+       evt->irq = -1;
 }
 
 void xen_setup_cpu_clockevents(void)
@@ -497,7 +500,11 @@ static void xen_hvm_setup_cpu_clockevents(void)
 {
        int cpu = smp_processor_id();
        xen_setup_runstate_info(cpu);
-       xen_setup_timer(cpu);
+       /*
+        * xen_setup_timer(cpu) - snprintf is bad in atomic context. Hence
+        * doing it xen_hvm_cpu_notify (which gets called by smp_init during
+        * early bootup and also during CPU hotplug events).
+        */
        xen_setup_cpu_clockevents();
 }
 
index 074b758..7c28835 100644 (file)
@@ -39,6 +39,7 @@
 
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap);
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap);
+EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete);
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_unplug);
 
 DEFINE_IDA(blk_queue_ida);
index ef5356c..0262210 100644 (file)
@@ -161,6 +161,8 @@ static int hash_recvmsg(struct kiocb *unused, struct socket *sock,
        else if (len < ds)
                msg->msg_flags |= MSG_TRUNC;
 
+       msg->msg_namelen = 0;
+
        lock_sock(sk);
        if (ctx->more) {
                ctx->more = 0;
index 6a6dfc0..a1c4f0a 100644 (file)
@@ -432,6 +432,7 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock,
        long copied = 0;
 
        lock_sock(sk);
+       msg->msg_namelen = 0;
        for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0;
             iovlen--, iov++) {
                unsigned long seglen = iov->iov_len;
index 202fa6d..78a956e 100644 (file)
@@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
 
 source "drivers/spi/Kconfig"
 
+source "drivers/ssbi/Kconfig"
+
 source "drivers/hsi/Kconfig"
 
 source "drivers/pps/Kconfig"
index dce39a9..4865ed2 100644 (file)
@@ -114,6 +114,7 @@ obj-y                               += firmware/
 obj-$(CONFIG_CRYPTO)           += crypto/
 obj-$(CONFIG_SUPERH)           += sh/
 obj-$(CONFIG_ARCH_SHMOBILE)    += sh/
+obj-$(CONFIG_SSBI)             += ssbi/
 ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
 obj-y                          += clocksource/
 endif
index 6ae5e44..ac8688b 100644 (file)
@@ -65,44 +65,12 @@ static struct acpi_scan_handler pci_root_handler = {
        .detach = acpi_pci_root_remove,
 };
 
-/* Lock to protect both acpi_pci_roots and acpi_pci_drivers lists */
+/* Lock to protect both acpi_pci_roots lists */
 static DEFINE_MUTEX(acpi_pci_root_lock);
 static LIST_HEAD(acpi_pci_roots);
-static LIST_HEAD(acpi_pci_drivers);
 
 static DEFINE_MUTEX(osc_lock);
 
-int acpi_pci_register_driver(struct acpi_pci_driver *driver)
-{
-       int n = 0;
-       struct acpi_pci_root *root;
-
-       mutex_lock(&acpi_pci_root_lock);
-       list_add_tail(&driver->node, &acpi_pci_drivers);
-       if (driver->add)
-               list_for_each_entry(root, &acpi_pci_roots, node) {
-                       driver->add(root);
-                       n++;
-               }
-       mutex_unlock(&acpi_pci_root_lock);
-
-       return n;
-}
-EXPORT_SYMBOL(acpi_pci_register_driver);
-
-void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
-{
-       struct acpi_pci_root *root;
-
-       mutex_lock(&acpi_pci_root_lock);
-       list_del(&driver->node);
-       if (driver->remove)
-               list_for_each_entry(root, &acpi_pci_roots, node)
-                       driver->remove(root);
-       mutex_unlock(&acpi_pci_root_lock);
-}
-EXPORT_SYMBOL(acpi_pci_unregister_driver);
-
 /**
  * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge
  * @handle - the ACPI CA node in question.
@@ -413,7 +381,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
        acpi_status status;
        int result;
        struct acpi_pci_root *root;
-       struct acpi_pci_driver *driver;
        u32 flags, base_flags;
 
        root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
@@ -571,12 +538,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
                pci_assign_unassigned_bus_resources(root->bus);
        }
 
-       mutex_lock(&acpi_pci_root_lock);
-       list_for_each_entry(driver, &acpi_pci_drivers, node)
-               if (driver->add)
-                       driver->add(root);
-       mutex_unlock(&acpi_pci_root_lock);
-
        /* need to after hot-added ioapic is registered */
        if (system_state != SYSTEM_BOOTING)
                pci_enable_bridges(root->bus);
@@ -597,16 +558,9 @@ end:
 static void acpi_pci_root_remove(struct acpi_device *device)
 {
        struct acpi_pci_root *root = acpi_driver_data(device);
-       struct acpi_pci_driver *driver;
 
        pci_stop_root_bus(root->bus);
 
-       mutex_lock(&acpi_pci_root_lock);
-       list_for_each_entry_reverse(driver, &acpi_pci_drivers, node)
-               if (driver->remove)
-                       driver->remove(root);
-       mutex_unlock(&acpi_pci_root_lock);
-
        device_set_run_wake(root->bus->bridge, false);
        pci_acpi_remove_bus_pm_notifier(device);
 
index cd1434e..033d117 100644 (file)
@@ -9,6 +9,9 @@
  *  Copyright (C) 2007-2008 Hewlett-Packard Development Company, L.P.
  *     Alex Chiang <achiang@hp.com>
  *
+ *  Copyright (C) 2013 Huawei Tech. Co., Ltd.
+ *     Jiang Liu <jiang.liu@huawei.com>
+ *
  *  This program is free software; you can redistribute it and/or modify it
  *  under the terms and conditions of the GNU General Public License,
  *  version 2, as published by the Free Software Foundation.
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/list.h>
 #include <linux/pci.h>
 #include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
 #include <linux/dmi.h>
 
 static bool debug;
@@ -61,20 +63,12 @@ ACPI_MODULE_NAME("pci_slot");
 #define SLOT_NAME_SIZE 21              /* Inspired by #define in acpiphp.h */
 
 struct acpi_pci_slot {
-       acpi_handle root_handle;        /* handle of the root bridge */
        struct pci_slot *pci_slot;      /* corresponding pci_slot */
        struct list_head list;          /* node in the list of slots */
 };
 
-static int acpi_pci_slot_add(struct acpi_pci_root *root);
-static void acpi_pci_slot_remove(struct acpi_pci_root *root);
-
 static LIST_HEAD(slot_list);
 static DEFINE_MUTEX(slot_list_lock);
-static struct acpi_pci_driver acpi_pci_slot_driver = {
-       .add = acpi_pci_slot_add,
-       .remove = acpi_pci_slot_remove,
-};
 
 static int
 check_slot(acpi_handle handle, unsigned long long *sun)
@@ -113,21 +107,8 @@ out:
        return device;
 }
 
-struct callback_args {
-       acpi_walk_callback      user_function;  /* only for walk_p2p_bridge */
-       struct pci_bus          *pci_bus;
-       acpi_handle             root_handle;
-};
-
 /*
- * register_slot
- *
- * Called once for each SxFy object in the namespace. Don't worry about
- * calling pci_create_slot multiple times for the same pci_bus:device,
- * since each subsequent call simply bumps the refcount on the pci_slot.
- *
- * The number of calls to pci_destroy_slot from unregister_slot is
- * symmetrical.
+ * Check whether handle has an associated slot and create PCI slot if it has.
  */
 static acpi_status
 register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
@@ -137,13 +118,22 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        char name[SLOT_NAME_SIZE];
        struct acpi_pci_slot *slot;
        struct pci_slot *pci_slot;
-       struct callback_args *parent_context = context;
-       struct pci_bus *pci_bus = parent_context->pci_bus;
+       struct pci_bus *pci_bus = context;
 
        device = check_slot(handle, &sun);
        if (device < 0)
                return AE_OK;
 
+       /*
+        * There may be multiple PCI functions associated with the same slot.
+        * Check whether PCI slot has already been created for this PCI device.
+        */
+       list_for_each_entry(slot, &slot_list, list) {
+               pci_slot = slot->pci_slot;
+               if (pci_slot->bus == pci_bus && pci_slot->number == device)
+                       return AE_OK;
+       }
+
        slot = kmalloc(sizeof(*slot), GFP_KERNEL);
        if (!slot) {
                err("%s: cannot allocate memory\n", __func__);
@@ -158,12 +148,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
                return AE_OK;
        }
 
-       slot->root_handle = parent_context->root_handle;
        slot->pci_slot = pci_slot;
-       INIT_LIST_HEAD(&slot->list);
-       mutex_lock(&slot_list_lock);
        list_add(&slot->list, &slot_list);
-       mutex_unlock(&slot_list_lock);
 
        get_device(&pci_bus->dev);
 
@@ -173,131 +159,24 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        return AE_OK;
 }
 
-/*
- * walk_p2p_bridge - discover and walk p2p bridges
- * @handle: points to an acpi_pci_root
- * @context: p2p_bridge_context pointer
- *
- * Note that when we call ourselves recursively, we pass a different
- * value of pci_bus in the child_context.
- */
-static acpi_status
-walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-       int device, function;
-       unsigned long long adr;
-       acpi_status status;
-       acpi_handle dummy_handle;
-       acpi_walk_callback user_function;
-
-       struct pci_dev *dev;
-       struct pci_bus *pci_bus;
-       struct callback_args child_context;
-       struct callback_args *parent_context = context;
-
-       pci_bus = parent_context->pci_bus;
-       user_function = parent_context->user_function;
-
-       status = acpi_get_handle(handle, "_ADR", &dummy_handle);
-       if (ACPI_FAILURE(status))
-               return AE_OK;
-
-       status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
-       if (ACPI_FAILURE(status))
-               return AE_OK;
-
-       device = (adr >> 16) & 0xffff;
-       function = adr & 0xffff;
-
-       dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function));
-       if (!dev || !dev->subordinate)
-               goto out;
-
-       child_context.pci_bus = dev->subordinate;
-       child_context.user_function = user_function;
-       child_context.root_handle = parent_context->root_handle;
-
-       dbg("p2p bridge walk, pci_bus = %x\n", dev->subordinate->number);
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    user_function, NULL, &child_context, NULL);
-       if (ACPI_FAILURE(status))
-               goto out;
-
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    walk_p2p_bridge, NULL, &child_context, NULL);
-out:
-       pci_dev_put(dev);
-       return AE_OK;
-}
-
-/*
- * walk_root_bridge - generic root bridge walker
- * @root: poiner of an acpi_pci_root
- * @user_function: user callback for slot objects
- *
- * Call user_function for all objects underneath this root bridge.
- * Walk p2p bridges underneath us and call user_function on those too.
- */
-static int
-walk_root_bridge(struct acpi_pci_root *root, acpi_walk_callback user_function)
-{
-       acpi_status status;
-       acpi_handle handle = root->device->handle;
-       struct pci_bus *pci_bus = root->bus;
-       struct callback_args context;
-
-       context.pci_bus = pci_bus;
-       context.user_function = user_function;
-       context.root_handle = handle;
-
-       dbg("root bridge walk, pci_bus = %x\n", pci_bus->number);
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    user_function, NULL, &context, NULL);
-       if (ACPI_FAILURE(status))
-               return status;
-
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    walk_p2p_bridge, NULL, &context, NULL);
-       if (ACPI_FAILURE(status))
-               err("%s: walk_p2p_bridge failure - %d\n", __func__, status);
-
-       return status;
-}
-
-/*
- * acpi_pci_slot_add
- * @handle: points to an acpi_pci_root
- */
-static int
-acpi_pci_slot_add(struct acpi_pci_root *root)
+void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle)
 {
-       acpi_status status;
-
-       status = walk_root_bridge(root, register_slot);
-       if (ACPI_FAILURE(status))
-               err("%s: register_slot failure - %d\n", __func__, status);
-
-       return status;
+       mutex_lock(&slot_list_lock);
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+                           register_slot, NULL, bus, NULL);
+       mutex_unlock(&slot_list_lock);
 }
 
-/*
- * acpi_pci_slot_remove
- * @handle: points to an acpi_pci_root
- */
-static void
-acpi_pci_slot_remove(struct acpi_pci_root *root)
+void acpi_pci_slot_remove(struct pci_bus *bus)
 {
        struct acpi_pci_slot *slot, *tmp;
-       struct pci_bus *pbus;
-       acpi_handle handle = root->device->handle;
 
        mutex_lock(&slot_list_lock);
        list_for_each_entry_safe(slot, tmp, &slot_list, list) {
-               if (slot->root_handle == handle) {
+               if (slot->pci_slot->bus == bus) {
                        list_del(&slot->list);
-                       pbus = slot->pci_slot->bus;
                        pci_destroy_slot(slot->pci_slot);
-                       put_device(&pbus->dev);
+                       put_device(&bus->dev);
                        kfree(slot);
                }
        }
@@ -332,5 +211,4 @@ static struct dmi_system_id acpi_pci_slot_dmi_table[] __initdata = {
 void __init acpi_pci_slot_init(void)
 {
        dmi_check_system(acpi_pci_slot_dmi_table);
-       acpi_pci_register_driver(&acpi_pci_slot_driver);
 }
index 5e7e991..f54d198 100644 (file)
@@ -1790,7 +1790,6 @@ int __init acpi_scan_init(void)
        acpi_platform_init();
        acpi_csrt_init();
        acpi_container_init();
-       acpi_pci_slot_init();
 
        mutex_lock(&acpi_scan_lock);
        /*
index 6a67b07..251e57d 100644 (file)
@@ -415,17 +415,17 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        /* Marvell */
        { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },        /* 6145 */
        { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },        /* 6121 */
-       { PCI_DEVICE(0x1b4b, 0x9123),
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9123),
          .class = PCI_CLASS_STORAGE_SATA_AHCI,
          .class_mask = 0xffffff,
          .driver_data = board_ahci_yes_fbs },                  /* 88se9128 */
-       { PCI_DEVICE(0x1b4b, 0x9125),
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125),
          .driver_data = board_ahci_yes_fbs },                  /* 88se9125 */
-       { PCI_DEVICE(0x1b4b, 0x917a),
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
          .driver_data = board_ahci_yes_fbs },                  /* 88se9172 */
-       { PCI_DEVICE(0x1b4b, 0x9192),
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192),
          .driver_data = board_ahci_yes_fbs },                  /* 88se9172 on some Gigabyte */
-       { PCI_DEVICE(0x1b4b, 0x91a3),
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
          .driver_data = board_ahci_yes_fbs },
 
        /* Promise */
index 958238d..40254f4 100644 (file)
@@ -387,21 +387,9 @@ static struct pcmcia_driver pcmcia_driver = {
        .probe          = pcmcia_init_one,
        .remove         = pcmcia_remove_one,
 };
-
-static int __init pcmcia_init(void)
-{
-       return pcmcia_register_driver(&pcmcia_driver);
-}
-
-static void __exit pcmcia_exit(void)
-{
-       pcmcia_unregister_driver(&pcmcia_driver);
-}
+module_pcmcia_driver(pcmcia_driver);
 
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for PCMCIA ATA");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(pcmcia_init);
-module_exit(pcmcia_exit);
index f556f8a..b7b7a88 100644 (file)
@@ -1742,9 +1742,10 @@ static int rbd_img_request_submit(struct rbd_img_request *img_request)
        struct rbd_device *rbd_dev = img_request->rbd_dev;
        struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
        struct rbd_obj_request *obj_request;
+       struct rbd_obj_request *next_obj_request;
 
        dout("%s: img %p\n", __func__, img_request);
-       for_each_obj_request(img_request, obj_request) {
+       for_each_obj_request_safe(img_request, obj_request, next_obj_request) {
                int ret;
 
                obj_request->callback = rbd_img_obj_callback;
index 0d26851..6c3e3d4 100644 (file)
@@ -934,17 +934,4 @@ static struct pcmcia_driver bluecard_driver = {
        .remove         = bluecard_detach,
        .id_table       = bluecard_ids,
 };
-
-static int __init init_bluecard_cs(void)
-{
-       return pcmcia_register_driver(&bluecard_driver);
-}
-
-
-static void __exit exit_bluecard_cs(void)
-{
-       pcmcia_unregister_driver(&bluecard_driver);
-}
-
-module_init(init_bluecard_cs);
-module_exit(exit_bluecard_cs);
+module_pcmcia_driver(bluecard_driver);
index 7ffd3f4..a1aaa3b 100644 (file)
@@ -760,17 +760,4 @@ static struct pcmcia_driver bt3c_driver = {
        .remove         = bt3c_detach,
        .id_table       = bt3c_ids,
 };
-
-static int __init init_bt3c_cs(void)
-{
-       return pcmcia_register_driver(&bt3c_driver);
-}
-
-
-static void __exit exit_bt3c_cs(void)
-{
-       pcmcia_unregister_driver(&bt3c_driver);
-}
-
-module_init(init_bt3c_cs);
-module_exit(exit_bt3c_cs);
+module_pcmcia_driver(bt3c_driver);
index 35a553a..beb262f 100644 (file)
@@ -688,17 +688,4 @@ static struct pcmcia_driver btuart_driver = {
        .remove         = btuart_detach,
        .id_table       = btuart_ids,
 };
-
-static int __init init_btuart_cs(void)
-{
-       return pcmcia_register_driver(&btuart_driver);
-}
-
-
-static void __exit exit_btuart_cs(void)
-{
-       pcmcia_unregister_driver(&btuart_driver);
-}
-
-module_init(init_btuart_cs);
-module_exit(exit_btuart_cs);
+module_pcmcia_driver(btuart_driver);
index 036cb36..33f3a69 100644 (file)
@@ -628,17 +628,4 @@ static struct pcmcia_driver dtl1_driver = {
        .remove         = dtl1_detach,
        .id_table       = dtl1_ids,
 };
-
-static int __init init_dtl1_cs(void)
-{
-       return pcmcia_register_driver(&dtl1_driver);
-}
-
-
-static void __exit exit_dtl1_cs(void)
-{
-       pcmcia_unregister_driver(&dtl1_driver);
-}
-
-module_init(init_dtl1_cs);
-module_exit(exit_dtl1_cs);
+module_pcmcia_driver(dtl1_driver);
index 25373df..974321a 100644 (file)
@@ -804,8 +804,8 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                        printk(KERN_INFO "Prom version board %d ....... V%d.%d %s",
                               i+1,
-                              (int)(readb(apbs[IndexCard].RamIO + VERS) >> 4),
-                              (int)(readb(apbs[IndexCard].RamIO + VERS) & 0xF),
+                              (int)(readb(apbs[i].RamIO + VERS) >> 4),
+                              (int)(readb(apbs[i].RamIO + VERS) & 0xF),
                               boardname);
 
 
index e3f9a99..d784650 100644 (file)
@@ -373,26 +373,14 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
        struct hpet_dev *devp;
        unsigned long addr;
 
-       if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
-               return -EINVAL;
-
        devp = file->private_data;
        addr = devp->hd_hpets->hp_hpet_phys;
 
        if (addr & (PAGE_SIZE - 1))
                return -ENOSYS;
 
-       vma->vm_flags |= VM_IO;
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
-       if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
-                                       PAGE_SIZE, vma->vm_page_prot)) {
-               printk(KERN_ERR "%s: io_remap_pfn_range failed\n",
-                       __func__);
-               return -EAGAIN;
-       }
-
-       return 0;
+       return vm_iomap_memory(vma, addr, PAGE_SIZE);
 #else
        return -ENOSYS;
 #endif
index f05d857..895d0b8 100644 (file)
@@ -228,18 +228,7 @@ static struct platform_driver mxc_rnga_driver = {
        .remove = __exit_p(mxc_rnga_remove),
 };
 
-static int __init mod_init(void)
-{
-       return platform_driver_probe(&mxc_rnga_driver, mxc_rnga_probe);
-}
-
-static void __exit mod_exit(void)
-{
-       platform_driver_unregister(&mxc_rnga_driver);
-}
-
-module_init(mod_init);
-module_exit(mod_exit);
+module_platform_driver_probe(mxc_rnga_driver, mxc_rnga_probe);
 
 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
 MODULE_DESCRIPTION("H/W RNGA driver for i.MX");
index 3099198..d34a24a 100644 (file)
@@ -166,18 +166,7 @@ static struct platform_driver tx4939_rng_driver = {
        .remove = tx4939_rng_remove,
 };
 
-static int __init tx4939rng_init(void)
-{
-       return platform_driver_probe(&tx4939_rng_driver, tx4939_rng_probe);
-}
-
-static void __exit tx4939rng_exit(void)
-{
-       platform_driver_unregister(&tx4939_rng_driver);
-}
-
-module_init(tx4939rng_init);
-module_exit(tx4939rng_exit);
+module_platform_driver_probe(tx4939_rng_driver, tx4939_rng_probe);
 
 MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for TX4939");
 MODULE_LICENSE("GPL");
index 3b22a60..2e2036e 100644 (file)
@@ -371,7 +371,7 @@ static int srom_setup_minor(struct srom_dev *srom, int index)
 
        dev = device_create(srom_class, &platform_bus,
                            MKDEV(srom_major, index), srom, "%d", index);
-       return IS_ERR(dev) ? PTR_ERR(dev) : 0;
+       return PTR_RET(dev);
 }
 
 /** srom_init() - Initialize the driver's module. */
index 6e13f26..88cfc61 100644 (file)
@@ -310,8 +310,6 @@ static void atc_complete_all(struct at_dma_chan *atchan)
 
        dev_vdbg(chan2dev(&atchan->chan_common), "complete all\n");
 
-       BUG_ON(atc_chan_is_enabled(atchan));
-
        /*
         * Submit queued descriptors ASAP, i.e. before we go through
         * the completed ones.
@@ -368,6 +366,9 @@ static void atc_advance_work(struct at_dma_chan *atchan)
 {
        dev_vdbg(chan2dev(&atchan->chan_common), "advance_work\n");
 
+       if (atc_chan_is_enabled(atchan))
+               return;
+
        if (list_empty(&atchan->active_list) ||
            list_is_singular(&atchan->active_list)) {
                atc_complete_all(atchan);
@@ -1078,9 +1079,7 @@ static void atc_issue_pending(struct dma_chan *chan)
                return;
 
        spin_lock_irqsave(&atchan->lock, flags);
-       if (!atc_chan_is_enabled(atchan)) {
-               atc_advance_work(atchan);
-       }
+       atc_advance_work(atchan);
        spin_unlock_irqrestore(&atchan->lock, flags);
 }
 
index 806c77b..272a3ec 100644 (file)
@@ -275,19 +275,18 @@ static int __init eisa_request_resources(struct eisa_root_device *root,
                }
                
                if (slot) {
-                       edev->res[i].name  = NULL;
                        edev->res[i].start = SLOT_ADDRESS(root, slot)
                                             + (i * 0x400);
                        edev->res[i].end   = edev->res[i].start + 0xff;
                        edev->res[i].flags = IORESOURCE_IO;
                } else {
-                       edev->res[i].name  = NULL;
                        edev->res[i].start = SLOT_ADDRESS(root, slot)
                                             + EISA_VENDOR_ID_OFFSET;
                        edev->res[i].end   = edev->res[i].start + 3;
-                       edev->res[i].flags = IORESOURCE_BUSY;
+                       edev->res[i].flags = IORESOURCE_IO | IORESOURCE_BUSY;
                }
 
+               dev_printk(KERN_DEBUG, &edev->dev, "%pR\n", &edev->res[i]);
                if (request_resource(root->res, &edev->res[i]))
                        goto failed;
        }
@@ -314,41 +313,40 @@ static int __init eisa_probe(struct eisa_root_device *root)
 {
         int i, c;
        struct eisa_device *edev;
+       char *enabled_str;
 
-       printk(KERN_INFO "EISA: Probing bus %d at %s\n",
-              root->bus_nr, dev_name(root->dev));
+       dev_info(root->dev, "Probing EISA bus %d\n", root->bus_nr);
 
        /* First try to get hold of slot 0. If there is no device
         * here, simply fail, unless root->force_probe is set. */
        
        edev = kzalloc(sizeof(*edev), GFP_KERNEL);
        if (!edev) {
-               printk(KERN_ERR "EISA: Couldn't allocate mainboard slot\n");
+               dev_err(root->dev, "EISA: Couldn't allocate mainboard slot\n");
                return -ENOMEM;
        }
                
-       if (eisa_request_resources(root, edev, 0)) {
-               printk(KERN_WARNING \
-                      "EISA: Cannot allocate resource for mainboard\n");
+       if (eisa_init_device(root, edev, 0)) {
                kfree(edev);
                if (!root->force_probe)
-                       return -EBUSY;
+                       return -ENODEV;
                goto force_probe;
        }
 
-       if (eisa_init_device(root, edev, 0)) {
-               eisa_release_resources(edev);
+       if (eisa_request_resources(root, edev, 0)) {
+               dev_warn(root->dev,
+                        "EISA: Cannot allocate resource for mainboard\n");
                kfree(edev);
                if (!root->force_probe)
-                       return -ENODEV;
+                       return -EBUSY;
                goto force_probe;
        }
 
-       printk(KERN_INFO "EISA: Mainboard %s detected.\n", edev->id.sig);
+       dev_info(&edev->dev, "EISA: Mainboard %s detected\n", edev->id.sig);
 
        if (eisa_register_device(edev)) {
-               printk(KERN_ERR "EISA: Failed to register %s\n",
-                      edev->id.sig);
+               dev_err(&edev->dev, "EISA: Failed to register %s\n",
+                       edev->id.sig);
                eisa_release_resources(edev);
                kfree(edev);
        }
@@ -358,55 +356,47 @@ static int __init eisa_probe(struct eisa_root_device *root)
         for (c = 0, i = 1; i <= root->slots; i++) {
                edev = kzalloc(sizeof(*edev), GFP_KERNEL);
                if (!edev) {
-                       printk(KERN_ERR "EISA: Out of memory for slot %d\n", i);
+                       dev_err(root->dev, "EISA: Out of memory for slot %d\n",
+                               i);
                        continue;
                }
 
-               if (eisa_request_resources(root, edev, i)) {
-                       printk(KERN_WARNING \
-                              "Cannot allocate resource for EISA slot %d\n",
-                              i);
+               if (eisa_init_device(root, edev, i)) {
                        kfree(edev);
                        continue;
                }
 
-               if (eisa_init_device(root, edev, i)) {
-                       eisa_release_resources(edev);
+               if (eisa_request_resources(root, edev, i)) {
+                       dev_warn(root->dev,
+                                "Cannot allocate resource for EISA slot %d\n",
+                                i);
                        kfree(edev);
                        continue;
                }
-               
-               printk(KERN_INFO "EISA: slot %d : %s detected",
-                      i, edev->id.sig);
-                       
-               switch (edev->state) {
-               case EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED:
-                       printk(" (forced enabled)");
-                       break;
-
-               case EISA_CONFIG_FORCED:
-                       printk(" (forced disabled)");
-                       break;
-
-               case 0:
-                       printk(" (disabled)");
-                       break;
-               }
-                       
-               printk (".\n");
+
+               if (edev->state == (EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED))
+                       enabled_str = " (forced enabled)";
+               else if (edev->state == EISA_CONFIG_FORCED)
+                       enabled_str = " (forced disabled)";
+               else if (edev->state == 0)
+                       enabled_str = " (disabled)";
+               else
+                       enabled_str = "";
+
+               dev_info(&edev->dev, "EISA: slot %d: %s detected%s\n", i,
+                        edev->id.sig, enabled_str);
 
                c++;
 
                if (eisa_register_device(edev)) {
-                       printk(KERN_ERR "EISA: Failed to register %s\n",
-                              edev->id.sig);
+                       dev_err(&edev->dev, "EISA: Failed to register %s\n",
+                               edev->id.sig);
                        eisa_release_resources(edev);
                        kfree(edev);
                }
         }
 
-       printk(KERN_INFO "EISA: Detected %d card%s.\n", c, c == 1 ? "" : "s");
-
+       dev_info(root->dev, "EISA: Detected %d card%s\n", c, c == 1 ? "" : "s");
        return 0;
 }
 
index 6c3fca9..a333bf3 100644 (file)
@@ -25,8 +25,7 @@ static int __init pci_eisa_init(struct pci_dev *pdev)
        struct resource *res, *bus_res = NULL;
 
        if ((rc = pci_enable_device (pdev))) {
-               printk (KERN_ERR "pci_eisa : Could not enable device %s\n",
-                       pci_name(pdev));
+               dev_err(&pdev->dev, "Could not enable device\n");
                return rc;
        }
 
@@ -59,7 +58,7 @@ static int __init pci_eisa_init(struct pci_dev *pdev)
        dev_set_drvdata(pci_eisa_root.dev, &pci_eisa_root);
 
        if (eisa_root_register (&pci_eisa_root)) {
-               printk (KERN_ERR "pci_eisa : Could not register EISA root\n");
+               dev_err(&pdev->dev, "Could not register EISA root\n");
                return -1;
        }
 
index dc357a4..7a1b4a7 100644 (file)
 #include <linux/mfd/arizona/pdata.h>
 #include <linux/mfd/arizona/registers.h>
 
-#define ARIZONA_NUM_BUTTONS 6
+#define ARIZONA_MAX_MICD_RANGE 8
 
 #define ARIZONA_ACCDET_MODE_MIC 0
 #define ARIZONA_ACCDET_MODE_HPL 1
 #define ARIZONA_ACCDET_MODE_HPR 2
 
+#define ARIZONA_HPDET_MAX 10000
+
+#define HPDET_DEBOUNCE 500
+#define DEFAULT_MICD_TIMEOUT 2000
+
 struct arizona_extcon_info {
        struct device *dev;
        struct arizona *arizona;
@@ -46,17 +51,27 @@ struct arizona_extcon_info {
        struct regulator *micvdd;
        struct input_dev *input;
 
+       u16 last_jackdet;
+
        int micd_mode;
        const struct arizona_micd_config *micd_modes;
        int micd_num_modes;
 
+       const struct arizona_micd_range *micd_ranges;
+       int num_micd_ranges;
+
+       int micd_timeout;
+
        bool micd_reva;
        bool micd_clamp;
 
        struct delayed_work hpdet_work;
+       struct delayed_work micd_detect_work;
+       struct delayed_work micd_timeout_work;
 
        bool hpdet_active;
        bool hpdet_done;
+       bool hpdet_retried;
 
        int num_hpdet_res;
        unsigned int hpdet_res[3];
@@ -71,20 +86,25 @@ struct arizona_extcon_info {
 };
 
 static const struct arizona_micd_config micd_default_modes[] = {
-       { 0,                  2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
        { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
+       { 0,                  2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
 };
 
-static struct {
-       u16 status;
-       int report;
-} arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = {
-       {  0x1, BTN_0 },
-       {  0x2, BTN_1 },
-       {  0x4, BTN_2 },
-       {  0x8, BTN_3 },
-       { 0x10, BTN_4 },
-       { 0x20, BTN_5 },
+static const struct arizona_micd_range micd_default_ranges[] = {
+       { .max =  11, .key = BTN_0 },
+       { .max =  28, .key = BTN_1 },
+       { .max =  54, .key = BTN_2 },
+       { .max = 100, .key = BTN_3 },
+       { .max = 186, .key = BTN_4 },
+       { .max = 430, .key = BTN_5 },
+};
+
+static const int arizona_micd_levels[] = {
+       3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
+       49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
+       105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
+       270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
+       1257,
 };
 
 #define ARIZONA_CABLE_MECHANICAL 0
@@ -100,10 +120,63 @@ static const char *arizona_cable[] = {
        NULL,
 };
 
+static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
+
+static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
+                                   unsigned int magic)
+{
+       struct arizona *arizona = info->arizona;
+       int ret;
+
+       mutex_lock(&arizona->dapm->card->dapm_mutex);
+
+       arizona->hpdet_magic = magic;
+
+       /* Keep the HP output stages disabled while doing the magic */
+       if (magic) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_OUTPUT_ENABLES_1,
+                                        ARIZONA_OUT1L_ENA |
+                                        ARIZONA_OUT1R_ENA, 0);
+               if (ret != 0)
+                       dev_warn(arizona->dev,
+                               "Failed to disable headphone outputs: %d\n",
+                                ret);
+       }
+
+       ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
+                                magic);
+       if (ret != 0)
+               dev_warn(arizona->dev, "Failed to do magic: %d\n",
+                                ret);
+
+       ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
+                                magic);
+       if (ret != 0)
+               dev_warn(arizona->dev, "Failed to do magic: %d\n",
+                        ret);
+
+       /* Restore the desired state while not doing the magic */
+       if (!magic) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_OUTPUT_ENABLES_1,
+                                        ARIZONA_OUT1L_ENA |
+                                        ARIZONA_OUT1R_ENA, arizona->hp_ena);
+               if (ret != 0)
+                       dev_warn(arizona->dev,
+                                "Failed to restore headphone outputs: %d\n",
+                                ret);
+       }
+
+       mutex_unlock(&arizona->dapm->card->dapm_mutex);
+}
+
 static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
 {
        struct arizona *arizona = info->arizona;
 
+       mode %= info->micd_num_modes;
+
        if (arizona->pdata.micd_pol_gpio > 0)
                gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
                                        info->micd_modes[mode].gpio);
@@ -330,7 +403,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
                /* If we go out of range report top of range */
                if (val < 100 || val > 0x3fb) {
                        dev_dbg(arizona->dev, "Measurement out of range\n");
-                       return 10000;
+                       return ARIZONA_HPDET_MAX;
                }
 
                dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
@@ -391,7 +464,8 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
        return val;
 }
 
-static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
+static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
+                              bool *mic)
 {
        struct arizona *arizona = info->arizona;
        int id_gpio = arizona->pdata.hpdet_id_gpio;
@@ -403,32 +477,8 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
        if (arizona->pdata.hpdet_acc_id) {
                info->hpdet_res[info->num_hpdet_res++] = *reading;
 
-               /*
-                * If the impedence is too high don't measure the
-                * second ground.
-                */
-               if (info->num_hpdet_res == 1 && *reading >= 45) {
-                       dev_dbg(arizona->dev, "Skipping ground flip\n");
-                       info->hpdet_res[info->num_hpdet_res++] = *reading;
-               }
-
-               if (info->num_hpdet_res == 1) {
-                       dev_dbg(arizona->dev, "Flipping ground\n");
-
-                       regmap_update_bits(arizona->regmap,
-                                          ARIZONA_ACCESSORY_DETECT_MODE_1,
-                                          ARIZONA_ACCDET_SRC,
-                                          ~info->micd_modes[0].src);
-
-                       regmap_update_bits(arizona->regmap,
-                                          ARIZONA_HEADPHONE_DETECT_1,
-                                          ARIZONA_HP_POLL, ARIZONA_HP_POLL);
-                       return -EAGAIN;
-               }
-
                /* Only check the mic directly if we didn't already ID it */
-               if (id_gpio && info->num_hpdet_res == 2 &&
-                   !((info->hpdet_res[0] > info->hpdet_res[1] * 2))) {
+               if (id_gpio && info->num_hpdet_res == 1) {
                        dev_dbg(arizona->dev, "Measuring mic\n");
 
                        regmap_update_bits(arizona->regmap,
@@ -447,22 +497,28 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
                }
 
                /* OK, got both.  Now, compare... */
-               dev_dbg(arizona->dev, "HPDET measured %d %d %d\n",
-                       info->hpdet_res[0], info->hpdet_res[1],
-                       info->hpdet_res[2]);
-
+               dev_dbg(arizona->dev, "HPDET measured %d %d\n",
+                       info->hpdet_res[0], info->hpdet_res[1]);
 
                /* Take the headphone impedance for the main report */
                *reading = info->hpdet_res[0];
 
+               /* Sometimes we get false readings due to slow insert */
+               if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
+                       dev_dbg(arizona->dev, "Retrying high impedance\n");
+                       info->num_hpdet_res = 0;
+                       info->hpdet_retried = true;
+                       arizona_start_hpdet_acc_id(info);
+                       pm_runtime_put(info->dev);
+                       return -EAGAIN;
+               }
+
                /*
-                * Either the two grounds measure differently or we
-                * measure the mic as high impedance.
+                * If we measure the mic as 
                 */
-               if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) ||
-                   (id_gpio && info->hpdet_res[2] > 10)) {
+               if (!id_gpio || info->hpdet_res[1] > 50) {
                        dev_dbg(arizona->dev, "Detected mic\n");
-                       info->mic = true;
+                       *mic = true;
                        info->detecting = true;
                } else {
                        dev_dbg(arizona->dev, "Detected headphone\n");
@@ -484,8 +540,8 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
        struct arizona *arizona = info->arizona;
        int id_gpio = arizona->pdata.hpdet_id_gpio;
        int report = ARIZONA_CABLE_HEADPHONE;
-       unsigned int val;
        int ret, reading;
+       bool mic = false;
 
        mutex_lock(&info->lock);
 
@@ -521,7 +577,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
                           ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
                           0);
 
-       ret = arizona_hpdet_do_id(info, &reading);
+       ret = arizona_hpdet_do_id(info, &reading, &mic);
        if (ret == -EAGAIN) {
                goto out;
        } else if (ret < 0) {
@@ -539,28 +595,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
                dev_err(arizona->dev, "Failed to report HP/line: %d\n",
                        ret);
 
-       mutex_lock(&arizona->dapm->card->dapm_mutex);
-
-       ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to read output enables: %d\n",
-                       ret);
-               val = 0;
-       }
-
-       if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
-               ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to undo magic: %d\n",
-                                ret);
-
-               ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to undo magic: %d\n",
-                                ret);
-       }
-
-       mutex_unlock(&arizona->dapm->card->dapm_mutex);
+       arizona_extcon_do_magic(info, 0);
 
 done:
        if (id_gpio)
@@ -572,7 +607,7 @@ done:
                           ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
 
        /* If we have a mic then reenable MICDET */
-       if (info->mic)
+       if (mic || info->mic)
                arizona_start_mic(info);
 
        if (info->hpdet_active) {
@@ -606,13 +641,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
        if (info->mic)
                arizona_stop_mic(info);
 
-       ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000);
-       if (ret != 0)
-               dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
-
-       ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000);
-       if (ret != 0)
-               dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
+       arizona_extcon_do_magic(info, 0x4000);
 
        ret = regmap_update_bits(arizona->regmap,
                                 ARIZONA_ACCESSORY_DETECT_MODE_1,
@@ -653,7 +682,8 @@ err:
 static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
 {
        struct arizona *arizona = info->arizona;
-       unsigned int val;
+       int hp_reading = 32;
+       bool mic;
        int ret;
 
        dev_dbg(arizona->dev, "Starting identification via HPDET\n");
@@ -663,32 +693,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
 
        info->hpdet_active = true;
 
-       arizona_extcon_pulse_micbias(info);
-
-       mutex_lock(&arizona->dapm->card->dapm_mutex);
-
-       ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to read output enables: %d\n",
-                       ret);
-               val = 0;
-       }
-
-       if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
-               ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
-                                        0x4000);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to do magic: %d\n",
-                                ret);
-
-               ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
-                                        0x4000);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to do magic: %d\n",
-                                ret);
-       }
-
-       mutex_unlock(&arizona->dapm->card->dapm_mutex);
+       arizona_extcon_do_magic(info, 0x4000);
 
        ret = regmap_update_bits(arizona->regmap,
                                 ARIZONA_ACCESSORY_DETECT_MODE_1,
@@ -700,12 +705,18 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
                goto err;
        }
 
-       ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
-                                ARIZONA_HP_POLL, ARIZONA_HP_POLL);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
-                       ret);
-               goto err;
+       if (arizona->pdata.hpdet_acc_id_line) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_HEADPHONE_DETECT_1,
+                                        ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+               if (ret != 0) {
+                       dev_err(arizona->dev,
+                               "Can't start HPDETL measurement: %d\n",
+                               ret);
+                       goto err;
+               }
+       } else {
+               arizona_hpdet_do_id(info, &hp_reading, &mic);
        }
 
        return;
@@ -724,28 +735,58 @@ err:
        info->hpdet_active = false;
 }
 
-static irqreturn_t arizona_micdet(int irq, void *data)
+static void arizona_micd_timeout_work(struct work_struct *work)
 {
-       struct arizona_extcon_info *info = data;
+       struct arizona_extcon_info *info = container_of(work,
+                                                       struct arizona_extcon_info,
+                                                       micd_timeout_work.work);
+
+       mutex_lock(&info->lock);
+
+       dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
+       arizona_identify_headphone(info);
+
+       info->detecting = false;
+
+       arizona_stop_mic(info);
+
+       mutex_unlock(&info->lock);
+}
+
+static void arizona_micd_detect(struct work_struct *work)
+{
+       struct arizona_extcon_info *info = container_of(work,
+                                                       struct arizona_extcon_info,
+                                                       micd_detect_work.work);
        struct arizona *arizona = info->arizona;
-       unsigned int val, lvl;
-       int ret, i;
+       unsigned int val = 0, lvl;
+       int ret, i, key;
+
+       cancel_delayed_work_sync(&info->micd_timeout_work);
 
        mutex_lock(&info->lock);
 
-       ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
-               mutex_unlock(&info->lock);
-               return IRQ_NONE;
-       }
+       for (i = 0; i < 10 && !(val & 0x7fc); i++) {
+               ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
+                       mutex_unlock(&info->lock);
+                       return;
+               }
 
-       dev_dbg(arizona->dev, "MICDET: %x\n", val);
+               dev_dbg(arizona->dev, "MICDET: %x\n", val);
+
+               if (!(val & ARIZONA_MICD_VALID)) {
+                       dev_warn(arizona->dev, "Microphone detection state invalid\n");
+                       mutex_unlock(&info->lock);
+                       return;
+               }
+       }
 
-       if (!(val & ARIZONA_MICD_VALID)) {
-               dev_warn(arizona->dev, "Microphone detection state invalid\n");
+       if (i == 10 && !(val & 0x7fc)) {
+               dev_err(arizona->dev, "Failed to get valid MICDET value\n");
                mutex_unlock(&info->lock);
-               return IRQ_NONE;
+               return;
        }
 
        /* Due to jack detect this should never happen */
@@ -786,7 +827,7 @@ static irqreturn_t arizona_micdet(int irq, void *data)
         * impedence then give up and report headphones.
         */
        if (info->detecting && (val & 0x3f8)) {
-               if (info->jack_flips >= info->micd_num_modes) {
+               if (info->jack_flips >= info->micd_num_modes * 10) {
                        dev_dbg(arizona->dev, "Detected HP/line\n");
                        arizona_identify_headphone(info);
 
@@ -816,12 +857,17 @@ static irqreturn_t arizona_micdet(int irq, void *data)
                        lvl = val & ARIZONA_MICD_LVL_MASK;
                        lvl >>= ARIZONA_MICD_LVL_SHIFT;
 
-                       for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
-                               if (lvl & arizona_lvl_to_key[i].status)
-                                       input_report_key(info->input,
-                                                        arizona_lvl_to_key[i].report,
-                                                        1);
-                       input_sync(info->input);
+                       for (i = 0; i < info->num_micd_ranges; i++)
+                               input_report_key(info->input,
+                                                info->micd_ranges[i].key, 0);
+
+                       WARN_ON(!lvl);
+                       WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
+                       if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
+                               key = info->micd_ranges[ffs(lvl) - 1].key;
+                               input_report_key(info->input, key, 1);
+                               input_sync(info->input);
+                       }
 
                } else if (info->detecting) {
                        dev_dbg(arizona->dev, "Headphone detected\n");
@@ -835,16 +881,41 @@ static irqreturn_t arizona_micdet(int irq, void *data)
                }
        } else {
                dev_dbg(arizona->dev, "Mic button released\n");
-               for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+               for (i = 0; i < info->num_micd_ranges; i++)
                        input_report_key(info->input,
-                                        arizona_lvl_to_key[i].report, 0);
+                                        info->micd_ranges[i].key, 0);
                input_sync(info->input);
                arizona_extcon_pulse_micbias(info);
        }
 
 handled:
+       if (info->detecting)
+               schedule_delayed_work(&info->micd_timeout_work,
+                                     msecs_to_jiffies(info->micd_timeout));
+
        pm_runtime_mark_last_busy(info->dev);
        mutex_unlock(&info->lock);
+}
+
+static irqreturn_t arizona_micdet(int irq, void *data)
+{
+       struct arizona_extcon_info *info = data;
+       struct arizona *arizona = info->arizona;
+       int debounce = arizona->pdata.micd_detect_debounce;
+
+       cancel_delayed_work_sync(&info->micd_detect_work);
+       cancel_delayed_work_sync(&info->micd_timeout_work);
+
+       mutex_lock(&info->lock);
+       if (!info->detecting)
+               debounce = 0;
+       mutex_unlock(&info->lock);
+
+       if (debounce)
+               schedule_delayed_work(&info->micd_detect_work,
+                                     msecs_to_jiffies(debounce));
+       else
+               arizona_micd_detect(&info->micd_detect_work.work);
 
        return IRQ_HANDLED;
 }
@@ -865,11 +936,13 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
        struct arizona_extcon_info *info = data;
        struct arizona *arizona = info->arizona;
        unsigned int val, present, mask;
+       bool cancelled_hp, cancelled_mic;
        int ret, i;
 
-       pm_runtime_get_sync(info->dev);
+       cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
+       cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
 
-       cancel_delayed_work_sync(&info->hpdet_work);
+       pm_runtime_get_sync(info->dev);
 
        mutex_lock(&info->lock);
 
@@ -890,7 +963,22 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
                return IRQ_NONE;
        }
 
-       if ((val & mask) == present) {
+       val &= mask;
+       if (val == info->last_jackdet) {
+               dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
+               if (cancelled_hp)
+                       schedule_delayed_work(&info->hpdet_work,
+                                             msecs_to_jiffies(HPDET_DEBOUNCE));
+
+               if (cancelled_mic)
+                       schedule_delayed_work(&info->micd_timeout_work,
+                                             msecs_to_jiffies(info->micd_timeout));
+
+               goto out;
+       }
+       info->last_jackdet = val;
+
+       if (info->last_jackdet == present) {
                dev_dbg(arizona->dev, "Detected jack\n");
                ret = extcon_set_cable_state_(&info->edev,
                                              ARIZONA_CABLE_MECHANICAL, true);
@@ -907,7 +995,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
                        arizona_start_mic(info);
                } else {
                        schedule_delayed_work(&info->hpdet_work,
-                                             msecs_to_jiffies(250));
+                                             msecs_to_jiffies(HPDET_DEBOUNCE));
                }
 
                regmap_update_bits(arizona->regmap,
@@ -923,10 +1011,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
                        info->hpdet_res[i] = 0;
                info->mic = false;
                info->hpdet_done = false;
+               info->hpdet_retried = false;
 
-               for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+               for (i = 0; i < info->num_micd_ranges; i++)
                        input_report_key(info->input,
-                                        arizona_lvl_to_key[i].report, 0);
+                                        info->micd_ranges[i].key, 0);
                input_sync(info->input);
 
                ret = extcon_update_state(&info->edev, 0xffffffff, 0);
@@ -940,6 +1029,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
                                   ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
        }
 
+       if (arizona->pdata.micd_timeout)
+               info->micd_timeout = arizona->pdata.micd_timeout;
+       else
+               info->micd_timeout = DEFAULT_MICD_TIMEOUT;
+
        /* Clear trig_sts to make sure DCVDD is not forced up */
        regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
                     ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
@@ -947,6 +1041,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
                     ARIZONA_JD1_FALL_TRIG_STS |
                     ARIZONA_JD1_RISE_TRIG_STS);
 
+out:
        mutex_unlock(&info->lock);
 
        pm_runtime_mark_last_busy(info->dev);
@@ -955,13 +1050,34 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+/* Map a level onto a slot in the register bank */
+static void arizona_micd_set_level(struct arizona *arizona, int index,
+                                  unsigned int level)
+{
+       int reg;
+       unsigned int mask;
+
+       reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
+
+       if (!(index % 2)) {
+               mask = 0x3f00;
+               level <<= 8;
+       } else {
+               mask = 0x3f;
+       }
+
+       /* Program the level itself */
+       regmap_update_bits(arizona->regmap, reg, mask, level);
+}
+
 static int arizona_extcon_probe(struct platform_device *pdev)
 {
        struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
        struct arizona_pdata *pdata;
        struct arizona_extcon_info *info;
+       unsigned int val;
        int jack_irq_fall, jack_irq_rise;
-       int ret, mode, i;
+       int ret, mode, i, j;
 
        if (!arizona->dapm || !arizona->dapm->card)
                return -EPROBE_DEFER;
@@ -985,7 +1101,10 @@ static int arizona_extcon_probe(struct platform_device *pdev)
        mutex_init(&info->lock);
        info->arizona = arizona;
        info->dev = &pdev->dev;
+       info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
        INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
+       INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
+       INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
        platform_set_drvdata(pdev, info);
 
        switch (arizona->type) {
@@ -1014,6 +1133,17 @@ static int arizona_extcon_probe(struct platform_device *pdev)
                goto err;
        }
 
+       info->input = devm_input_allocate_device(&pdev->dev);
+       if (!info->input) {
+               dev_err(arizona->dev, "Can't allocate input dev\n");
+               ret = -ENOMEM;
+               goto err_register;
+       }
+
+       info->input->name = "Headset";
+       info->input->phys = "arizona/extcon";
+       info->input->dev.parent = &pdev->dev;
+
        if (pdata->num_micd_configs) {
                info->micd_modes = pdata->micd_configs;
                info->micd_num_modes = pdata->num_micd_configs;
@@ -1069,15 +1199,79 @@ static int arizona_extcon_probe(struct platform_device *pdev)
                                   arizona->pdata.micd_dbtime
                                   << ARIZONA_MICD_DBTIME_SHIFT);
 
+       BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
+
+       if (arizona->pdata.num_micd_ranges) {
+               info->micd_ranges = pdata->micd_ranges;
+               info->num_micd_ranges = pdata->num_micd_ranges;
+       } else {
+               info->micd_ranges = micd_default_ranges;
+               info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
+       }
+
+       if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
+               dev_err(arizona->dev, "Too many MICD ranges: %d\n",
+                       arizona->pdata.num_micd_ranges);
+       }
+
+       if (info->num_micd_ranges > 1) {
+               for (i = 1; i < info->num_micd_ranges; i++) {
+                       if (info->micd_ranges[i - 1].max >
+                           info->micd_ranges[i].max) {
+                               dev_err(arizona->dev,
+                                       "MICD ranges must be sorted\n");
+                               ret = -EINVAL;
+                               goto err_input;
+                       }
+               }
+       }
+
+       /* Disable all buttons by default */
+       regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
+                          ARIZONA_MICD_LVL_SEL_MASK, 0x81);
+
+       /* Set up all the buttons the user specified */
+       for (i = 0; i < info->num_micd_ranges; i++) {
+               for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
+                       if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
+                               break;
+
+               if (j == ARRAY_SIZE(arizona_micd_levels)) {
+                       dev_err(arizona->dev, "Unsupported MICD level %d\n",
+                               info->micd_ranges[i].max);
+                       ret = -EINVAL;
+                       goto err_input;
+               }
+
+               dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
+                       arizona_micd_levels[j], i);
+
+               arizona_micd_set_level(arizona, i, j);
+               input_set_capability(info->input, EV_KEY,
+                                    info->micd_ranges[i].key);
+
+               /* Enable reporting of that range */
+               regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
+                                  1 << i, 1 << i);
+       }
+
+       /* Set all the remaining keys to a maximum */
+       for (; i < ARIZONA_MAX_MICD_RANGE; i++)
+               arizona_micd_set_level(arizona, i, 0x3f);
+
        /*
         * If we have a clamp use it, activating in conjunction with
         * GPIO5 if that is connected for jack detect operation.
         */
        if (info->micd_clamp) {
                if (arizona->pdata.jd_gpio5) {
-                       /* Put the GPIO into input mode */
+                       /* Put the GPIO into input mode with optional pull */
+                       val = 0xc101;
+                       if (arizona->pdata.jd_gpio5_nopull)
+                               val &= ~ARIZONA_GPN_PU;
+
                        regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
-                                    0xc101);
+                                    val);
 
                        regmap_update_bits(arizona->regmap,
                                           ARIZONA_MICD_CLAMP_CONTROL,
@@ -1096,20 +1290,6 @@ static int arizona_extcon_probe(struct platform_device *pdev)
 
        arizona_extcon_set_mode(info, 0);
 
-       info->input = devm_input_allocate_device(&pdev->dev);
-       if (!info->input) {
-               dev_err(arizona->dev, "Can't allocate input dev\n");
-               ret = -ENOMEM;
-               goto err_register;
-       }
-
-       for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
-               input_set_capability(info->input, EV_KEY,
-                                    arizona_lvl_to_key[i].report);
-       info->input->name = "Headset";
-       info->input->phys = "arizona/extcon";
-       info->input->dev.parent = &pdev->dev;
-
        pm_runtime_enable(&pdev->dev);
        pm_runtime_idle(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
index 8f3c947..b56bdaa 100644 (file)
@@ -38,7 +38,7 @@
  * extcon-max77693 driver use 'default_init_data' to bring up base operation
  * of MAX77693 MUIC device.
  */
-struct max77693_reg_data default_init_data[] = {
+static struct max77693_reg_data default_init_data[] = {
        {
                /* STATUS2 - [3]ChgDetRun */
                .addr = MAX77693_MUIC_REG_STATUS2,
@@ -258,7 +258,7 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info,
                                          CONTROL3_ADCDBSET_MASK);
                if (ret) {
                        dev_err(info->dev, "failed to set ADC debounce time\n");
-                       return -EAGAIN;
+                       return ret;
                }
                break;
        default:
@@ -294,7 +294,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info,
                        MAX77693_MUIC_REG_CTRL1, ctrl1, COMP_SW_MASK);
        if (ret < 0) {
                dev_err(info->dev, "failed to update MUIC register\n");
-               return -EAGAIN;
+               return ret;
        }
 
        if (attached)
@@ -307,7 +307,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info,
                        CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK);
        if (ret < 0) {
                dev_err(info->dev, "failed to update MUIC register\n");
-               return -EAGAIN;
+               return ret;
        }
 
        dev_info(info->dev,
@@ -1035,7 +1035,7 @@ static int max77693_muic_detect_accessory(struct max77693_muic_info *info)
        if (ret) {
                dev_err(info->dev, "failed to read MUIC register\n");
                mutex_unlock(&info->mutex);
-               return -EINVAL;
+               return ret;
        }
 
        adc = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_ADC,
index 69641bc..67d6738 100644 (file)
@@ -196,7 +196,7 @@ static int max8997_muic_set_debounce_time(struct max8997_muic_info *info,
                                          CONTROL3_ADCDBSET_MASK);
                if (ret) {
                        dev_err(info->dev, "failed to set ADC debounce time\n");
-                       return -EAGAIN;
+                       return ret;
                }
                break;
        default:
@@ -232,7 +232,7 @@ static int max8997_muic_set_path(struct max8997_muic_info *info,
                        MAX8997_MUIC_REG_CONTROL1, ctrl1, COMP_SW_MASK);
        if (ret < 0) {
                dev_err(info->dev, "failed to update MUIC register\n");
-               return -EAGAIN;
+               return ret;
        }
 
        if (attached)
@@ -245,7 +245,7 @@ static int max8997_muic_set_path(struct max8997_muic_info *info,
                        CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK);
        if (ret < 0) {
                dev_err(info->dev, "failed to update MUIC register\n");
-               return -EAGAIN;
+               return ret;
        }
 
        dev_info(info->dev,
@@ -397,7 +397,7 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
        ret = max8997_muic_set_path(info, info->path_uart, attached);
        if (ret) {
                dev_err(info->dev, "failed to update muic register\n");
-               return -EINVAL;
+               return ret;
        }
 
        extcon_set_cable_state(info->edev, "JIG", attached);
@@ -608,7 +608,7 @@ static int max8997_muic_detect_dev(struct max8997_muic_info *info)
        if (ret) {
                dev_err(info->dev, "failed to read MUIC register\n");
                mutex_unlock(&info->mutex);
-               return -EINVAL;
+               return ret;
        }
 
        adc = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_ADC,
@@ -646,7 +646,7 @@ static void max8997_muic_detect_cable_wq(struct work_struct *work)
 
        ret = max8997_muic_detect_dev(info);
        if (ret < 0)
-               pr_err("failed to detect cable type\n");
+               dev_err(info->dev, "failed to detect cable type\n");
 }
 
 static int max8997_muic_probe(struct platform_device *pdev)
index 42c759a..3e53200 100644 (file)
@@ -39,6 +39,7 @@ config FIRMWARE_MEMMAP
 config EFI_VARS
        tristate "EFI Variable Support via sysfs"
        depends on EFI
+       select UCS2_STRING
        default n
        help
          If you say Y here, you are able to get EFI (Extensible Firmware
index 7acafb8..f4baa11 100644 (file)
@@ -80,6 +80,7 @@
 #include <linux/slab.h>
 #include <linux/pstore.h>
 #include <linux/ctype.h>
+#include <linux/ucs2_string.h>
 
 #include <linux/fs.h>
 #include <linux/ramfs.h>
@@ -172,51 +173,6 @@ static void efivar_update_sysfs_entries(struct work_struct *);
 static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
 static bool efivar_wq_enabled = true;
 
-/* Return the number of unicode characters in data */
-static unsigned long
-utf16_strnlen(efi_char16_t *s, size_t maxlength)
-{
-       unsigned long length = 0;
-
-       while (*s++ != 0 && length < maxlength)
-               length++;
-       return length;
-}
-
-static inline unsigned long
-utf16_strlen(efi_char16_t *s)
-{
-       return utf16_strnlen(s, ~0UL);
-}
-
-/*
- * Return the number of bytes is the length of this string
- * Note: this is NOT the same as the number of unicode characters
- */
-static inline unsigned long
-utf16_strsize(efi_char16_t *data, unsigned long maxlength)
-{
-       return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t);
-}
-
-static inline int
-utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len)
-{
-       while (1) {
-               if (len == 0)
-                       return 0;
-               if (*a < *b)
-                       return -1;
-               if (*a > *b)
-                       return 1;
-               if (*a == 0) /* implies *b == 0 */
-                       return 0;
-               a++;
-               b++;
-               len--;
-       }
-}
-
 static bool
 validate_device_path(struct efi_variable *var, int match, u8 *buffer,
                     unsigned long len)
@@ -268,7 +224,7 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer,
        u16 filepathlength;
        int i, desclength = 0, namelen;
 
-       namelen = utf16_strnlen(var->VariableName, sizeof(var->VariableName));
+       namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName));
 
        /* Either "Boot" or "Driver" followed by four digits of hex */
        for (i = match; i < match+4; i++) {
@@ -291,7 +247,7 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer,
         * There's no stored length for the description, so it has to be
         * found by hand
         */
-       desclength = utf16_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2;
+       desclength = ucs2_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2;
 
        /* Each boot entry must have a descriptor */
        if (!desclength)
@@ -436,24 +392,12 @@ static efi_status_t
 check_var_size_locked(struct efivars *efivars, u32 attributes,
                        unsigned long size)
 {
-       u64 storage_size, remaining_size, max_size;
-       efi_status_t status;
        const struct efivar_operations *fops = efivars->ops;
 
-       if (!efivars->ops->query_variable_info)
+       if (!efivars->ops->query_variable_store)
                return EFI_UNSUPPORTED;
 
-       status = fops->query_variable_info(attributes, &storage_size,
-                                          &remaining_size, &max_size);
-
-       if (status != EFI_SUCCESS)
-               return status;
-
-       if (!storage_size || size > remaining_size || size > max_size ||
-           (remaining_size - size) < (storage_size / 2))
-               return EFI_OUT_OF_RESOURCES;
-
-       return status;
+       return fops->query_variable_store(attributes, size);
 }
 
 
@@ -593,7 +537,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
        spin_lock_irq(&efivars->lock);
 
        status = check_var_size_locked(efivars, new_var->Attributes,
-              new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
+              new_var->DataSize + ucs2_strsize(new_var->VariableName, 1024));
 
        if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED)
                status = efivars->ops->set_variable(new_var->VariableName,
@@ -771,7 +715,7 @@ static ssize_t efivarfs_file_write(struct file *file,
         * QueryVariableInfo() isn't supported by the firmware.
         */
 
-       varsize = datasize + utf16_strsize(var->var.VariableName, 1024);
+       varsize = datasize + ucs2_strsize(var->var.VariableName, 1024);
        status = check_var_size(efivars, attributes, varsize);
 
        if (status != EFI_SUCCESS) {
@@ -1223,7 +1167,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
 
                inode = NULL;
 
-               len = utf16_strlen(entry->var.VariableName);
+               len = ucs2_strlen(entry->var.VariableName);
 
                /* name, plus '-', plus GUID, plus NUL*/
                name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC);
@@ -1481,8 +1425,8 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
 
                if (efi_guidcmp(entry->var.VendorGuid, vendor))
                        continue;
-               if (utf16_strncmp(entry->var.VariableName, efi_name,
-                                 utf16_strlen(efi_name))) {
+               if (ucs2_strncmp(entry->var.VariableName, efi_name,
+                                 ucs2_strlen(efi_name))) {
                        /*
                         * Check if an old format,
                         * which doesn't support holding
@@ -1494,8 +1438,8 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
                        for (i = 0; i < DUMP_NAME_LEN; i++)
                                efi_name_old[i] = name_old[i];
 
-                       if (utf16_strncmp(entry->var.VariableName, efi_name_old,
-                                         utf16_strlen(efi_name_old)))
+                       if (ucs2_strncmp(entry->var.VariableName, efi_name_old,
+                                         ucs2_strlen(efi_name_old)))
                                continue;
                }
 
@@ -1573,8 +1517,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
         * Does this variable already exist?
         */
        list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
-               strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024);
-               strsize2 = utf16_strsize(new_var->VariableName, 1024);
+               strsize1 = ucs2_strsize(search_efivar->var.VariableName, 1024);
+               strsize2 = ucs2_strsize(new_var->VariableName, 1024);
                if (strsize1 == strsize2 &&
                        !memcmp(&(search_efivar->var.VariableName),
                                new_var->VariableName, strsize1) &&
@@ -1590,7 +1534,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
        }
 
        status = check_var_size_locked(efivars, new_var->Attributes,
-              new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
+              new_var->DataSize + ucs2_strsize(new_var->VariableName, 1024));
 
        if (status && status != EFI_UNSUPPORTED) {
                spin_unlock_irq(&efivars->lock);
@@ -1614,7 +1558,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
 
        /* Create the entry in sysfs.  Locking is not required here */
        status = efivar_create_sysfs_entry(efivars,
-                                          utf16_strsize(new_var->VariableName,
+                                          ucs2_strsize(new_var->VariableName,
                                                         1024),
                                           new_var->VariableName,
                                           &new_var->VendorGuid);
@@ -1644,8 +1588,8 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
         * Does this variable already exist?
         */
        list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
-               strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024);
-               strsize2 = utf16_strsize(del_var->VariableName, 1024);
+               strsize1 = ucs2_strsize(search_efivar->var.VariableName, 1024);
+               strsize2 = ucs2_strsize(del_var->VariableName, 1024);
                if (strsize1 == strsize2 &&
                        !memcmp(&(search_efivar->var.VariableName),
                                del_var->VariableName, strsize1) &&
@@ -1684,16 +1628,17 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
        return count;
 }
 
-static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor)
+static bool variable_is_present(struct efivars *efivars,
+                               efi_char16_t *variable_name,
+                               efi_guid_t *vendor)
 {
        struct efivar_entry *entry, *n;
-       struct efivars *efivars = &__efivars;
        unsigned long strsize1, strsize2;
        bool found = false;
 
-       strsize1 = utf16_strsize(variable_name, 1024);
+       strsize1 = ucs2_strsize(variable_name, 1024);
        list_for_each_entry_safe(entry, n, &efivars->list, list) {
-               strsize2 = utf16_strsize(entry->var.VariableName, 1024);
+               strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
                if (strsize1 == strsize2 &&
                        !memcmp(variable_name, &(entry->var.VariableName),
                                strsize2) &&
@@ -1759,8 +1704,8 @@ static void efivar_update_sysfs_entries(struct work_struct *work)
                        if (status != EFI_SUCCESS) {
                                break;
                        } else {
-                               if (!variable_is_present(variable_name,
-                                   &vendor)) {
+                               if (!variable_is_present(efivars,
+                                   variable_name, &vendor)) {
                                        found = true;
                                        break;
                                }
@@ -2064,7 +2009,8 @@ int register_efivars(struct efivars *efivars,
                         * we'll ever see a different variable name,
                         * and may end up looping here forever.
                         */
-                       if (variable_is_present(variable_name, &vendor_guid)) {
+                       if (variable_is_present(efivars, variable_name,
+                                               &vendor_guid)) {
                                dup_variable_bug(variable_name, &vendor_guid,
                                                 variable_name_size);
                                status = EFI_NOT_FOUND;
@@ -2131,7 +2077,7 @@ efivars_init(void)
        ops.get_variable = efi.get_variable;
        ops.set_variable = efi.set_variable;
        ops.get_next_variable = efi.get_next_variable;
-       ops.query_variable_info = efi.query_variable_info;
+       ops.query_variable_store = efi_query_variable_store;
 
        error = register_efivars(&__efivars, &ops, efi_kobj);
        if (error)
index b820869..d7008df 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/bitops.h>
 #include <linux/workqueue.h>
 #include <linux/gpio.h>
@@ -22,6 +23,7 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/pl061.h>
 #include <linux/slab.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/pm.h>
 #include <asm/mach/irq.h>
 
@@ -51,8 +53,7 @@ struct pl061_gpio {
        spinlock_t              lock;
 
        void __iomem            *base;
-       int                     irq_base;
-       struct irq_chip_generic *irq_gc;
+       struct irq_domain       *domain;
        struct gpio_chip        gc;
 
 #ifdef CONFIG_PM
@@ -60,6 +61,24 @@ struct pl061_gpio {
 #endif
 };
 
+static int pl061_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       /*
+        * Map back to global GPIO space and request muxing, the direction
+        * parameter does not matter for this controller.
+        */
+       int gpio = chip->base + offset;
+
+       return pinctrl_request_gpio(gpio);
+}
+
+static void pl061_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       int gpio = chip->base + offset;
+
+       pinctrl_free_gpio(gpio);
+}
+
 static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
 {
        struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
@@ -122,24 +141,20 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
 {
        struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
 
-       if (chip->irq_base <= 0)
-               return -EINVAL;
-
-       return chip->irq_base + offset;
+       return irq_create_mapping(chip->domain, offset);
 }
 
 static int pl061_irq_type(struct irq_data *d, unsigned trigger)
 {
-       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-       struct pl061_gpio *chip = gc->private;
-       int offset = d->irq - chip->irq_base;
+       struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+       int offset = irqd_to_hwirq(d);
        unsigned long flags;
        u8 gpiois, gpioibe, gpioiev;
 
        if (offset < 0 || offset >= PL061_GPIO_NR)
                return -EINVAL;
 
-       raw_spin_lock_irqsave(&gc->lock, flags);
+       spin_lock_irqsave(&chip->lock, flags);
 
        gpioiev = readb(chip->base + GPIOIEV);
 
@@ -168,7 +183,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
 
        writeb(gpioiev, chip->base + GPIOIEV);
 
-       raw_spin_unlock_irqrestore(&gc->lock, flags);
+       spin_unlock_irqrestore(&chip->lock, flags);
 
        return 0;
 }
@@ -192,31 +207,61 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
        chained_irq_exit(irqchip, desc);
 }
 
-static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base)
+static void pl061_irq_mask(struct irq_data *d)
+{
+       struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+       u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
+       u8 gpioie;
+
+       spin_lock(&chip->lock);
+       gpioie = readb(chip->base + GPIOIE) & ~mask;
+       writeb(gpioie, chip->base + GPIOIE);
+       spin_unlock(&chip->lock);
+}
+
+static void pl061_irq_unmask(struct irq_data *d)
 {
-       struct irq_chip_type *ct;
+       struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+       u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
+       u8 gpioie;
+
+       spin_lock(&chip->lock);
+       gpioie = readb(chip->base + GPIOIE) | mask;
+       writeb(gpioie, chip->base + GPIOIE);
+       spin_unlock(&chip->lock);
+}
+
+static struct irq_chip pl061_irqchip = {
+       .name           = "pl061 gpio",
+       .irq_mask       = pl061_irq_mask,
+       .irq_unmask     = pl061_irq_unmask,
+       .irq_set_type   = pl061_irq_type,
+};
 
-       chip->irq_gc = irq_alloc_generic_chip("gpio-pl061", 1, irq_base,
-                                             chip->base, handle_simple_irq);
-       chip->irq_gc->private = chip;
+static int pl061_irq_map(struct irq_domain *d, unsigned int virq,
+                        irq_hw_number_t hw)
+{
+       struct pl061_gpio *chip = d->host_data;
 
-       ct = chip->irq_gc->chip_types;
-       ct->chip.irq_mask = irq_gc_mask_clr_bit;
-       ct->chip.irq_unmask = irq_gc_mask_set_bit;
-       ct->chip.irq_set_type = pl061_irq_type;
-       ct->chip.irq_set_wake = irq_gc_set_wake;
-       ct->regs.mask = GPIOIE;
+       irq_set_chip_and_handler_name(virq, &pl061_irqchip, handle_simple_irq,
+                                     "pl061");
+       irq_set_chip_data(virq, chip);
+       irq_set_irq_type(virq, IRQ_TYPE_NONE);
 
-       irq_setup_generic_chip(chip->irq_gc, IRQ_MSK(PL061_GPIO_NR),
-                              IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
+       return 0;
 }
 
+static const struct irq_domain_ops pl061_domain_ops = {
+       .map    = pl061_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
 static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 {
        struct device *dev = &adev->dev;
        struct pl061_platform_data *pdata = dev->platform_data;
        struct pl061_gpio *chip;
-       int ret, irq, i;
+       int ret, irq, i, irq_base;
 
        chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
        if (chip == NULL)
@@ -224,24 +269,32 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 
        if (pdata) {
                chip->gc.base = pdata->gpio_base;
-               chip->irq_base = pdata->irq_base;
-       } else if (adev->dev.of_node) {
+               irq_base = pdata->irq_base;
+               if (irq_base <= 0)
+                       return -ENODEV;
+       } else {
                chip->gc.base = -1;
-               chip->irq_base = 0;
-       } else
-               return -ENODEV;
+               irq_base = 0;
+       }
 
        if (!devm_request_mem_region(dev, adev->res.start,
-                               resource_size(&adev->res), "pl061"))
+                                    resource_size(&adev->res), "pl061"))
                return -EBUSY;
 
        chip->base = devm_ioremap(dev, adev->res.start,
-                               resource_size(&adev->res));
-       if (chip->base == NULL)
+                                 resource_size(&adev->res));
+       if (!chip->base)
                return -ENOMEM;
 
+       chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR,
+                                            irq_base, &pl061_domain_ops, chip);
+       if (!chip->domain)
+               return -ENODEV;
+
        spin_lock_init(&chip->lock);
 
+       chip->gc.request = pl061_gpio_request;
+       chip->gc.free = pl061_gpio_free;
        chip->gc.direction_input = pl061_direction_input;
        chip->gc.direction_output = pl061_direction_output;
        chip->gc.get = pl061_get_value;
@@ -259,12 +312,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
        /*
         * irq_chip support
         */
-
-       if (chip->irq_base <= 0)
-               return 0;
-
-       pl061_init_gc(chip, chip->irq_base);
-
        writeb(0, chip->base + GPIOIE); /* disable irqs */
        irq = adev->irq[0];
        if (irq < 0)
index 9cc108d..8325f58 100644 (file)
@@ -642,7 +642,12 @@ static struct platform_driver pxa_gpio_driver = {
                .of_match_table = of_match_ptr(pxa_gpio_dt_ids),
        },
 };
-module_platform_driver(pxa_gpio_driver);
+
+static int __init pxa_gpio_init(void)
+{
+       return platform_driver_register(&pxa_gpio_driver);
+}
+postcore_initcall(pxa_gpio_init);
 
 #ifdef CONFIG_PM
 static int pxa_gpio_suspend(void)
index 5150df6..465f4ca 100644 (file)
@@ -203,22 +203,11 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
                if (!pctldev)
                        break;
 
-               /*
-                * This assumes that the n GPIO pins are consecutive in the
-                * GPIO number space, and that the pins are also consecutive
-                * in their local number space. Currently it is not possible
-                * to add different ranges for one and the same GPIO chip,
-                * as the code assumes that we have one consecutive range
-                * on both, mapping 1-to-1.
-                *
-                * TODO: make the OF bindings handle multiple sparse ranges
-                * on the same GPIO chip.
-                */
                ret = gpiochip_add_pin_range(chip,
                                             pinctrl_dev_get_devname(pctldev),
-                                            0, /* offset in gpiochip */
                                             pinspec.args[0],
-                                            pinspec.args[1]);
+                                            pinspec.args[1],
+                                            pinspec.args[2]);
 
                if (ret)
                        break;
index 04fa6f1..f83f071 100644 (file)
@@ -506,7 +506,7 @@ drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
 }
 EXPORT_SYMBOL(drm_gtf_mode);
 
-#if IS_ENABLED(CONFIG_VIDEOMODE)
+#ifdef CONFIG_VIDEOMODE_HELPERS
 int drm_display_mode_from_videomode(const struct videomode *vm,
                                    struct drm_display_mode *dmode)
 {
@@ -523,26 +523,25 @@ int drm_display_mode_from_videomode(const struct videomode *vm,
        dmode->clock = vm->pixelclock / 1000;
 
        dmode->flags = 0;
-       if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH)
+       if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
                dmode->flags |= DRM_MODE_FLAG_PHSYNC;
-       else if (vm->dmt_flags & VESA_DMT_HSYNC_LOW)
+       else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
                dmode->flags |= DRM_MODE_FLAG_NHSYNC;
-       if (vm->dmt_flags & VESA_DMT_VSYNC_HIGH)
+       if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
                dmode->flags |= DRM_MODE_FLAG_PVSYNC;
-       else if (vm->dmt_flags & VESA_DMT_VSYNC_LOW)
+       else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
                dmode->flags |= DRM_MODE_FLAG_NVSYNC;
-       if (vm->data_flags & DISPLAY_FLAGS_INTERLACED)
+       if (vm->flags & DISPLAY_FLAGS_INTERLACED)
                dmode->flags |= DRM_MODE_FLAG_INTERLACE;
-       if (vm->data_flags & DISPLAY_FLAGS_DOUBLESCAN)
+       if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
                dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
        drm_mode_set_name(dmode);
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
-#endif
 
-#if IS_ENABLED(CONFIG_OF_VIDEOMODE)
+#ifdef CONFIG_OF
 /**
  * of_get_drm_display_mode - get a drm_display_mode from devicetree
  * @np: device_node with the timing specification
@@ -572,7 +571,8 @@ int of_get_drm_display_mode(struct device_node *np,
        return 0;
 }
 EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
-#endif
+#endif /* CONFIG_OF */
+#endif /* CONFIG_VIDEOMODE_HELPERS */
 
 /**
  * drm_mode_set_name - set the name on a mode
index d24d040..e461e99 100644 (file)
@@ -4,8 +4,7 @@ config DRM_TILCDC
        select DRM_KMS_HELPER
        select DRM_KMS_CMA_HELPER
        select DRM_GEM_CMA_HELPER
-       select OF_VIDEOMODE
-       select OF_DISPLAY_TIMING
+       select VIDEOMODE_HELPERS
        select BACKLIGHT_CLASS_DEVICE
        help
          Choose this option if you have an TI SoC with LCDC display
index 580b74e..90ee497 100644 (file)
@@ -173,7 +173,7 @@ static int panel_connector_get_modes(struct drm_connector *connector)
                struct drm_display_mode *mode = drm_mode_create(dev);
                struct videomode vm;
 
-               if (videomode_from_timing(timings, &vm, i))
+               if (videomode_from_timings(timings, &vm, i))
                        break;
 
                drm_display_mode_from_videomode(&vm, mode);
index e6abfa0..0a74b56 100644 (file)
@@ -5,4 +5,4 @@ obj-$(CONFIG_HYPERV_BALLOON)    += hv_balloon.o
 hv_vmbus-y := vmbus_drv.o \
                 hv.o connection.o channel.o \
                 channel_mgmt.o ring_buffer.o
-hv_utils-y := hv_util.o hv_kvp.o
+hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o
index ff1be16..bad8128 100644 (file)
@@ -165,8 +165,19 @@ static void vmbus_process_rescind_offer(struct work_struct *work)
        struct vmbus_channel *channel = container_of(work,
                                                     struct vmbus_channel,
                                                     work);
+       unsigned long flags;
+       struct vmbus_channel_relid_released msg;
 
        vmbus_device_unregister(channel->device_obj);
+       memset(&msg, 0, sizeof(struct vmbus_channel_relid_released));
+       msg.child_relid = channel->offermsg.child_relid;
+       msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
+       vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
+
+       spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+       list_del(&channel->listentry);
+       spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+       free_channel(channel);
 }
 
 void vmbus_free_channels(void)
index 7311589..ae49237 100644 (file)
@@ -289,9 +289,8 @@ void hv_synic_init(void *arg)
        /* Check the version */
        rdmsrl(HV_X64_MSR_SVERSION, version);
 
-       hv_context.event_dpc[cpu] = (struct tasklet_struct *)
-                                       kmalloc(sizeof(struct tasklet_struct),
-                                               GFP_ATOMIC);
+       hv_context.event_dpc[cpu] = kmalloc(sizeof(struct tasklet_struct),
+                                           GFP_ATOMIC);
        if (hv_context.event_dpc[cpu] == NULL) {
                pr_err("Unable to allocate event dpc\n");
                goto cleanup;
index 3787321..4c605c7 100644 (file)
@@ -117,7 +117,14 @@ union dm_caps {
        struct {
                __u64 balloon:1;
                __u64 hot_add:1;
-               __u64 reservedz:62;
+               /*
+                * To support guests that may have alignment
+                * limitations on hot-add, the guest can specify
+                * its alignment requirements; a value of n
+                * represents an alignment of 2^n in mega bytes.
+                */
+               __u64 hot_add_alignment:4;
+               __u64 reservedz:58;
        } cap_bits;
        __u64 caps;
 } __packed;
@@ -412,13 +419,45 @@ struct dm_info_msg {
  * End protocol definitions.
  */
 
-static bool hot_add;
+/*
+ * State to manage hot adding memory into the guest.
+ * The range start_pfn : end_pfn specifies the range
+ * that the host has asked us to hot add. The range
+ * start_pfn : ha_end_pfn specifies the range that we have
+ * currently hot added. We hot add in multiples of 128M
+ * chunks; it is possible that we may not be able to bring
+ * online all the pages in the region. The range
+ * covered_start_pfn : covered_end_pfn defines the pages that can
+ * be brough online.
+ */
+
+struct hv_hotadd_state {
+       struct list_head list;
+       unsigned long start_pfn;
+       unsigned long covered_start_pfn;
+       unsigned long covered_end_pfn;
+       unsigned long ha_end_pfn;
+       unsigned long end_pfn;
+};
+
+struct balloon_state {
+       __u32 num_pages;
+       struct work_struct wrk;
+};
+
+struct hot_add_wrk {
+       union dm_mem_page_range ha_page_range;
+       union dm_mem_page_range ha_region_range;
+       struct work_struct wrk;
+};
+
+static bool hot_add = true;
 static bool do_hot_add;
 /*
  * Delay reporting memory pressure by
  * the specified number of seconds.
  */
-static uint pressure_report_delay = 30;
+static uint pressure_report_delay = 45;
 
 module_param(hot_add, bool, (S_IRUGO | S_IWUSR));
 MODULE_PARM_DESC(hot_add, "If set attempt memory hot_add");
@@ -446,6 +485,7 @@ enum hv_dm_state {
 static __u8 recv_buffer[PAGE_SIZE];
 static __u8 *send_buffer;
 #define PAGES_IN_2M    512
+#define HA_CHUNK (32 * 1024)
 
 struct hv_dynmem_device {
        struct hv_device *dev;
@@ -459,7 +499,28 @@ struct hv_dynmem_device {
        unsigned int num_pages_ballooned;
 
        /*
-        * This thread handles both balloon/hot-add
+        * State to manage the ballooning (up) operation.
+        */
+       struct balloon_state balloon_wrk;
+
+       /*
+        * State to execute the "hot-add" operation.
+        */
+       struct hot_add_wrk ha_wrk;
+
+       /*
+        * This state tracks if the host has specified a hot-add
+        * region.
+        */
+       bool host_specified_ha_region;
+
+       /*
+        * State to synchronize hot-add.
+        */
+       struct completion  ol_waitevent;
+       bool ha_waiting;
+       /*
+        * This thread handles hot-add
         * requests from the host as well as notifying
         * the host with regards to memory pressure in
         * the guest.
@@ -467,6 +528,11 @@ struct hv_dynmem_device {
        struct task_struct *thread;
 
        /*
+        * A list of hot-add regions.
+        */
+       struct list_head ha_region_list;
+
+       /*
         * We start with the highest version we can support
         * and downgrade based on the host; we save here the
         * next version to try.
@@ -476,35 +542,358 @@ struct hv_dynmem_device {
 
 static struct hv_dynmem_device dm_device;
 
-static void hot_add_req(struct hv_dynmem_device *dm, struct dm_hot_add *msg)
+#ifdef CONFIG_MEMORY_HOTPLUG
+
+static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size)
 {
+       int i;
 
-       struct dm_hot_add_response resp;
+       for (i = 0; i < size; i++) {
+               struct page *pg;
+               pg = pfn_to_page(start_pfn + i);
+               __online_page_set_limits(pg);
+               __online_page_increment_counters(pg);
+               __online_page_free(pg);
+       }
+}
 
-       if (do_hot_add) {
+static void hv_mem_hot_add(unsigned long start, unsigned long size,
+                               unsigned long pfn_count,
+                               struct hv_hotadd_state *has)
+{
+       int ret = 0;
+       int i, nid, t;
+       unsigned long start_pfn;
+       unsigned long processed_pfn;
+       unsigned long total_pfn = pfn_count;
+
+       for (i = 0; i < (size/HA_CHUNK); i++) {
+               start_pfn = start + (i * HA_CHUNK);
+               has->ha_end_pfn +=  HA_CHUNK;
+
+               if (total_pfn > HA_CHUNK) {
+                       processed_pfn = HA_CHUNK;
+                       total_pfn -= HA_CHUNK;
+               } else {
+                       processed_pfn = total_pfn;
+                       total_pfn = 0;
+               }
+
+               has->covered_end_pfn +=  processed_pfn;
+
+               init_completion(&dm_device.ol_waitevent);
+               dm_device.ha_waiting = true;
+
+               nid = memory_add_physaddr_to_nid(PFN_PHYS(start_pfn));
+               ret = add_memory(nid, PFN_PHYS((start_pfn)),
+                               (HA_CHUNK << PAGE_SHIFT));
 
-               pr_info("Memory hot add not supported\n");
+               if (ret) {
+                       pr_info("hot_add memory failed error is %d\n", ret);
+                       if (ret == -EEXIST) {
+                               /*
+                                * This error indicates that the error
+                                * is not a transient failure. This is the
+                                * case where the guest's physical address map
+                                * precludes hot adding memory. Stop all further
+                                * memory hot-add.
+                                */
+                               do_hot_add = false;
+                       }
+                       has->ha_end_pfn -= HA_CHUNK;
+                       has->covered_end_pfn -=  processed_pfn;
+                       break;
+               }
 
                /*
-                * Currently we do not support hot add.
-                * Just fail the request.
+                * Wait for the memory block to be onlined.
                 */
+               t = wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ);
+               if (t == 0) {
+                       pr_info("hot_add memory timedout\n");
+                       has->ha_end_pfn -= HA_CHUNK;
+                       has->covered_end_pfn -=  processed_pfn;
+                       break;
+               }
+
+       }
+
+       return;
+}
+
+static void hv_online_page(struct page *pg)
+{
+       struct list_head *cur;
+       struct hv_hotadd_state *has;
+       unsigned long cur_start_pgp;
+       unsigned long cur_end_pgp;
+
+       if (dm_device.ha_waiting) {
+               dm_device.ha_waiting = false;
+               complete(&dm_device.ol_waitevent);
+       }
+
+       list_for_each(cur, &dm_device.ha_region_list) {
+               has = list_entry(cur, struct hv_hotadd_state, list);
+               cur_start_pgp = (unsigned long)
+                               pfn_to_page(has->covered_start_pfn);
+               cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn);
+
+               if (((unsigned long)pg >= cur_start_pgp) &&
+                       ((unsigned long)pg < cur_end_pgp)) {
+                       /*
+                        * This frame is currently backed; online the
+                        * page.
+                        */
+                       __online_page_set_limits(pg);
+                       __online_page_increment_counters(pg);
+                       __online_page_free(pg);
+                       has->covered_start_pfn++;
+               }
+       }
+}
+
+static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
+{
+       struct list_head *cur;
+       struct hv_hotadd_state *has;
+       unsigned long residual, new_inc;
+
+       if (list_empty(&dm_device.ha_region_list))
+               return false;
+
+       list_for_each(cur, &dm_device.ha_region_list) {
+               has = list_entry(cur, struct hv_hotadd_state, list);
+
+               /*
+                * If the pfn range we are dealing with is not in the current
+                * "hot add block", move on.
+                */
+               if ((start_pfn >= has->end_pfn))
+                       continue;
+               /*
+                * If the current hot add-request extends beyond
+                * our current limit; extend it.
+                */
+               if ((start_pfn + pfn_cnt) > has->end_pfn) {
+                       residual = (start_pfn + pfn_cnt - has->end_pfn);
+                       /*
+                        * Extend the region by multiples of HA_CHUNK.
+                        */
+                       new_inc = (residual / HA_CHUNK) * HA_CHUNK;
+                       if (residual % HA_CHUNK)
+                               new_inc += HA_CHUNK;
+
+                       has->end_pfn += new_inc;
+               }
+
+               /*
+                * If the current start pfn is not where the covered_end
+                * is, update it.
+                */
+
+               if (has->covered_end_pfn != start_pfn) {
+                       has->covered_end_pfn = start_pfn;
+                       has->covered_start_pfn = start_pfn;
+               }
+               return true;
+
        }
 
+       return false;
+}
+
+static unsigned long handle_pg_range(unsigned long pg_start,
+                                       unsigned long pg_count)
+{
+       unsigned long start_pfn = pg_start;
+       unsigned long pfn_cnt = pg_count;
+       unsigned long size;
+       struct list_head *cur;
+       struct hv_hotadd_state *has;
+       unsigned long pgs_ol = 0;
+       unsigned long old_covered_state;
+
+       if (list_empty(&dm_device.ha_region_list))
+               return 0;
+
+       list_for_each(cur, &dm_device.ha_region_list) {
+               has = list_entry(cur, struct hv_hotadd_state, list);
+
+               /*
+                * If the pfn range we are dealing with is not in the current
+                * "hot add block", move on.
+                */
+               if ((start_pfn >= has->end_pfn))
+                       continue;
+
+               old_covered_state = has->covered_end_pfn;
+
+               if (start_pfn < has->ha_end_pfn) {
+                       /*
+                        * This is the case where we are backing pages
+                        * in an already hot added region. Bring
+                        * these pages online first.
+                        */
+                       pgs_ol = has->ha_end_pfn - start_pfn;
+                       if (pgs_ol > pfn_cnt)
+                               pgs_ol = pfn_cnt;
+                       hv_bring_pgs_online(start_pfn, pgs_ol);
+                       has->covered_end_pfn +=  pgs_ol;
+                       has->covered_start_pfn +=  pgs_ol;
+                       pfn_cnt -= pgs_ol;
+               }
+
+               if ((has->ha_end_pfn < has->end_pfn) && (pfn_cnt > 0)) {
+                       /*
+                        * We have some residual hot add range
+                        * that needs to be hot added; hot add
+                        * it now. Hot add a multiple of
+                        * of HA_CHUNK that fully covers the pages
+                        * we have.
+                        */
+                       size = (has->end_pfn - has->ha_end_pfn);
+                       if (pfn_cnt <= size) {
+                               size = ((pfn_cnt / HA_CHUNK) * HA_CHUNK);
+                               if (pfn_cnt % HA_CHUNK)
+                                       size += HA_CHUNK;
+                       } else {
+                               pfn_cnt = size;
+                       }
+                       hv_mem_hot_add(has->ha_end_pfn, size, pfn_cnt, has);
+               }
+               /*
+                * If we managed to online any pages that were given to us,
+                * we declare success.
+                */
+               return has->covered_end_pfn - old_covered_state;
+
+       }
+
+       return 0;
+}
+
+static unsigned long process_hot_add(unsigned long pg_start,
+                                       unsigned long pfn_cnt,
+                                       unsigned long rg_start,
+                                       unsigned long rg_size)
+{
+       struct hv_hotadd_state *ha_region = NULL;
+
+       if (pfn_cnt == 0)
+               return 0;
+
+       if (!dm_device.host_specified_ha_region)
+               if (pfn_covered(pg_start, pfn_cnt))
+                       goto do_pg_range;
+
+       /*
+        * If the host has specified a hot-add range; deal with it first.
+        */
+
+       if (rg_size != 0) {
+               ha_region = kzalloc(sizeof(struct hv_hotadd_state), GFP_KERNEL);
+               if (!ha_region)
+                       return 0;
+
+               INIT_LIST_HEAD(&ha_region->list);
+
+               list_add_tail(&ha_region->list, &dm_device.ha_region_list);
+               ha_region->start_pfn = rg_start;
+               ha_region->ha_end_pfn = rg_start;
+               ha_region->covered_start_pfn = pg_start;
+               ha_region->covered_end_pfn = pg_start;
+               ha_region->end_pfn = rg_start + rg_size;
+       }
+
+do_pg_range:
+       /*
+        * Process the page range specified; bringing them
+        * online if possible.
+        */
+       return handle_pg_range(pg_start, pfn_cnt);
+}
+
+#endif
+
+static void hot_add_req(struct work_struct *dummy)
+{
+       struct dm_hot_add_response resp;
+#ifdef CONFIG_MEMORY_HOTPLUG
+       unsigned long pg_start, pfn_cnt;
+       unsigned long rg_start, rg_sz;
+#endif
+       struct hv_dynmem_device *dm = &dm_device;
+
        memset(&resp, 0, sizeof(struct dm_hot_add_response));
        resp.hdr.type = DM_MEM_HOT_ADD_RESPONSE;
        resp.hdr.size = sizeof(struct dm_hot_add_response);
        resp.hdr.trans_id = atomic_inc_return(&trans_id);
 
-       resp.page_count = 0;
-       resp.result = 0;
+#ifdef CONFIG_MEMORY_HOTPLUG
+       pg_start = dm->ha_wrk.ha_page_range.finfo.start_page;
+       pfn_cnt = dm->ha_wrk.ha_page_range.finfo.page_cnt;
+
+       rg_start = dm->ha_wrk.ha_region_range.finfo.start_page;
+       rg_sz = dm->ha_wrk.ha_region_range.finfo.page_cnt;
+
+       if ((rg_start == 0) && (!dm->host_specified_ha_region)) {
+               unsigned long region_size;
+               unsigned long region_start;
+
+               /*
+                * The host has not specified the hot-add region.
+                * Based on the hot-add page range being specified,
+                * compute a hot-add region that can cover the pages
+                * that need to be hot-added while ensuring the alignment
+                * and size requirements of Linux as it relates to hot-add.
+                */
+               region_start = pg_start;
+               region_size = (pfn_cnt / HA_CHUNK) * HA_CHUNK;
+               if (pfn_cnt % HA_CHUNK)
+                       region_size += HA_CHUNK;
+
+               region_start = (pg_start / HA_CHUNK) * HA_CHUNK;
+
+               rg_start = region_start;
+               rg_sz = region_size;
+       }
+
+       if (do_hot_add)
+               resp.page_count = process_hot_add(pg_start, pfn_cnt,
+                                               rg_start, rg_sz);
+#endif
+       /*
+        * The result field of the response structure has the
+        * following semantics:
+        *
+        * 1. If all or some pages hot-added: Guest should return success.
+        *
+        * 2. If no pages could be hot-added:
+        *
+        * If the guest returns success, then the host
+        * will not attempt any further hot-add operations. This
+        * signifies a permanent failure.
+        *
+        * If the guest returns failure, then this failure will be
+        * treated as a transient failure and the host may retry the
+        * hot-add operation after some delay.
+        */
+       if (resp.page_count > 0)
+               resp.result = 1;
+       else if (!do_hot_add)
+               resp.result = 1;
+       else
+               resp.result = 0;
+
+       if (!do_hot_add || (resp.page_count == 0))
+               pr_info("Memory hot add failed\n");
 
        dm->state = DM_INITIALIZED;
        vmbus_sendpacket(dm->dev->channel, &resp,
                        sizeof(struct dm_hot_add_response),
                        (unsigned long)NULL,
                        VM_PKT_DATA_INBAND, 0);
-
 }
 
 static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)
@@ -523,7 +912,7 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)
        }
 }
 
-unsigned long compute_balloon_floor(void)
+static unsigned long compute_balloon_floor(void)
 {
        unsigned long min_pages;
 #define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
@@ -644,6 +1033,14 @@ static int  alloc_balloon_pages(struct hv_dynmem_device *dm, int num_pages,
 
                dm->num_pages_ballooned += alloc_unit;
 
+               /*
+                * If we allocatted 2M pages; split them so we
+                * can free them in any order we get.
+                */
+
+               if (alloc_unit != 1)
+                       split_page(pg, get_order(alloc_unit << PAGE_SHIFT));
+
                bl_resp->range_count++;
                bl_resp->range_array[i].finfo.start_page =
                        page_to_pfn(pg);
@@ -657,9 +1054,9 @@ static int  alloc_balloon_pages(struct hv_dynmem_device *dm, int num_pages,
 
 
 
-static void balloon_up(struct hv_dynmem_device *dm, struct dm_balloon *req)
+static void balloon_up(struct work_struct *dummy)
 {
-       int num_pages = req->num_pages;
+       int num_pages = dm_device.balloon_wrk.num_pages;
        int num_ballooned = 0;
        struct dm_balloon_response *bl_resp;
        int alloc_unit;
@@ -670,9 +1067,10 @@ static void balloon_up(struct hv_dynmem_device *dm, struct dm_balloon *req)
 
 
        /*
-        * Currently, we only support 4k allocations.
+        * We will attempt 2M allocations. However, if we fail to
+        * allocate 2M chunks, we will go back to 4k allocations.
         */
-       alloc_unit = 1;
+       alloc_unit = 512;
 
        while (!done) {
                bl_resp = (struct dm_balloon_response *)send_buffer;
@@ -684,14 +1082,19 @@ static void balloon_up(struct hv_dynmem_device *dm, struct dm_balloon *req)
 
 
                num_pages -= num_ballooned;
-               num_ballooned = alloc_balloon_pages(dm, num_pages,
+               num_ballooned = alloc_balloon_pages(&dm_device, num_pages,
                                                bl_resp, alloc_unit,
                                                 &alloc_error);
 
+               if ((alloc_error) && (alloc_unit != 1)) {
+                       alloc_unit = 1;
+                       continue;
+               }
+
                if ((alloc_error) || (num_ballooned == num_pages)) {
                        bl_resp->more_pages = 0;
                        done = true;
-                       dm->state = DM_INITIALIZED;
+                       dm_device.state = DM_INITIALIZED;
                }
 
                /*
@@ -719,7 +1122,7 @@ static void balloon_up(struct hv_dynmem_device *dm, struct dm_balloon *req)
                        pr_info("Balloon response failed\n");
 
                        for (i = 0; i < bl_resp->range_count; i++)
-                               free_balloon_pages(dm,
+                               free_balloon_pages(&dm_device,
                                                 &bl_resp->range_array[i]);
 
                        done = true;
@@ -761,7 +1164,6 @@ static int dm_thread_func(void *dm_dev)
 {
        struct hv_dynmem_device *dm = dm_dev;
        int t;
-       unsigned long  scan_start;
 
        while (!kthread_should_stop()) {
                t = wait_for_completion_timeout(&dm_device.config_event, 1*HZ);
@@ -773,22 +1175,6 @@ static int dm_thread_func(void *dm_dev)
                if (t == 0)
                        post_status(dm);
 
-               scan_start = jiffies;
-               switch (dm->state) {
-               case DM_BALLOON_UP:
-                       balloon_up(dm, (struct dm_balloon *)recv_buffer);
-                       break;
-
-               case DM_HOT_ADD:
-                       hot_add_req(dm, (struct dm_hot_add *)recv_buffer);
-                       break;
-               default:
-                       break;
-               }
-
-               if (!time_in_range(jiffies, scan_start, scan_start + HZ))
-                       post_status(dm);
-
        }
 
        return 0;
@@ -861,6 +1247,10 @@ static void balloon_onchannelcallback(void *context)
        struct dm_message *dm_msg;
        struct dm_header *dm_hdr;
        struct hv_dynmem_device *dm = hv_get_drvdata(dev);
+       struct dm_balloon *bal_msg;
+       struct dm_hot_add *ha_msg;
+       union dm_mem_page_range *ha_pg_range;
+       union dm_mem_page_range *ha_region;
 
        memset(recv_buffer, 0, sizeof(recv_buffer));
        vmbus_recvpacket(dev->channel, recv_buffer,
@@ -882,8 +1272,12 @@ static void balloon_onchannelcallback(void *context)
                        break;
 
                case DM_BALLOON_REQUEST:
+                       if (dm->state == DM_BALLOON_UP)
+                               pr_warn("Currently ballooning\n");
+                       bal_msg = (struct dm_balloon *)recv_buffer;
                        dm->state = DM_BALLOON_UP;
-                       complete(&dm->config_event);
+                       dm_device.balloon_wrk.num_pages = bal_msg->num_pages;
+                       schedule_work(&dm_device.balloon_wrk.wrk);
                        break;
 
                case DM_UNBALLOON_REQUEST:
@@ -893,8 +1287,31 @@ static void balloon_onchannelcallback(void *context)
                        break;
 
                case DM_MEM_HOT_ADD_REQUEST:
+                       if (dm->state == DM_HOT_ADD)
+                               pr_warn("Currently hot-adding\n");
                        dm->state = DM_HOT_ADD;
-                       complete(&dm->config_event);
+                       ha_msg = (struct dm_hot_add *)recv_buffer;
+                       if (ha_msg->hdr.size == sizeof(struct dm_hot_add)) {
+                               /*
+                                * This is a normal hot-add request specifying
+                                * hot-add memory.
+                                */
+                               ha_pg_range = &ha_msg->range;
+                               dm->ha_wrk.ha_page_range = *ha_pg_range;
+                               dm->ha_wrk.ha_region_range.page_range = 0;
+                       } else {
+                               /*
+                                * Host is specifying that we first hot-add
+                                * a region and then partially populate this
+                                * region.
+                                */
+                               dm->host_specified_ha_region = true;
+                               ha_pg_range = &ha_msg->range;
+                               ha_region = &ha_pg_range[1];
+                               dm->ha_wrk.ha_page_range = *ha_pg_range;
+                               dm->ha_wrk.ha_region_range = *ha_region;
+                       }
+                       schedule_work(&dm_device.ha_wrk.wrk);
                        break;
 
                case DM_INFO_MESSAGE:
@@ -937,6 +1354,10 @@ static int balloon_probe(struct hv_device *dev,
        dm_device.next_version = DYNMEM_PROTOCOL_VERSION_WIN7;
        init_completion(&dm_device.host_event);
        init_completion(&dm_device.config_event);
+       INIT_LIST_HEAD(&dm_device.ha_region_list);
+       INIT_WORK(&dm_device.balloon_wrk.wrk, balloon_up);
+       INIT_WORK(&dm_device.ha_wrk.wrk, hot_add_req);
+       dm_device.host_specified_ha_region = false;
 
        dm_device.thread =
                 kthread_run(dm_thread_func, &dm_device, "hv_balloon");
@@ -945,6 +1366,10 @@ static int balloon_probe(struct hv_device *dev,
                goto probe_error1;
        }
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+       set_online_page_callback(&hv_online_page);
+#endif
+
        hv_set_drvdata(dev, &dm_device);
        /*
         * Initiate the hand shake with the host and negotiate
@@ -962,8 +1387,7 @@ static int balloon_probe(struct hv_device *dev,
        ret = vmbus_sendpacket(dev->channel, &version_req,
                                sizeof(struct dm_version_request),
                                (unsigned long)NULL,
-                               VM_PKT_DATA_INBAND,
-                               VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+                               VM_PKT_DATA_INBAND, 0);
        if (ret)
                goto probe_error2;
 
@@ -990,13 +1414,13 @@ static int balloon_probe(struct hv_device *dev,
        cap_msg.hdr.trans_id = atomic_inc_return(&trans_id);
 
        cap_msg.caps.cap_bits.balloon = 1;
+       cap_msg.caps.cap_bits.hot_add = 1;
+
        /*
-        * While we currently don't support hot-add,
-        * we still advertise this capability since the
-        * host requires that guests partcipating in the
-        * dynamic memory protocol support hot add.
+        * Specify our alignment requirements as it relates
+        * memory hot-add. Specify 128MB alignment.
         */
-       cap_msg.caps.cap_bits.hot_add = 1;
+       cap_msg.caps.cap_bits.hot_add_alignment = 7;
 
        /*
         * Currently the host does not use these
@@ -1009,8 +1433,7 @@ static int balloon_probe(struct hv_device *dev,
        ret = vmbus_sendpacket(dev->channel, &cap_msg,
                                sizeof(struct dm_capabilities),
                                (unsigned long)NULL,
-                               VM_PKT_DATA_INBAND,
-                               VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+                               VM_PKT_DATA_INBAND, 0);
        if (ret)
                goto probe_error2;
 
@@ -1034,6 +1457,9 @@ static int balloon_probe(struct hv_device *dev,
        return 0;
 
 probe_error2:
+#ifdef CONFIG_MEMORY_HOTPLUG
+       restore_online_page_callback(&hv_online_page);
+#endif
        kthread_stop(dm_device.thread);
 
 probe_error1:
@@ -1046,13 +1472,26 @@ probe_error0:
 static int balloon_remove(struct hv_device *dev)
 {
        struct hv_dynmem_device *dm = hv_get_drvdata(dev);
+       struct list_head *cur, *tmp;
+       struct hv_hotadd_state *has;
 
        if (dm->num_pages_ballooned != 0)
                pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned);
 
+       cancel_work_sync(&dm->balloon_wrk.wrk);
+       cancel_work_sync(&dm->ha_wrk.wrk);
+
        vmbus_close(dev->channel);
        kthread_stop(dm->thread);
        kfree(send_buffer);
+#ifdef CONFIG_MEMORY_HOTPLUG
+       restore_online_page_callback(&hv_online_page);
+#endif
+       list_for_each_safe(cur, tmp, &dm->ha_region_list) {
+               has = list_entry(cur, struct hv_hotadd_state, list);
+               list_del(&has->list);
+               kfree(has);
+       }
 
        return 0;
 }
@@ -1079,14 +1518,7 @@ static int __init init_balloon_drv(void)
        return vmbus_driver_register(&balloon_drv);
 }
 
-static void exit_balloon_drv(void)
-{
-
-       vmbus_driver_unregister(&balloon_drv);
-}
-
 module_init(init_balloon_drv);
-module_exit(exit_balloon_drv);
 
 MODULE_DESCRIPTION("Hyper-V Balloon");
 MODULE_VERSION(HV_DRV_VERSION);
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
new file mode 100644 (file)
index 0000000..8ad5653
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * An implementation of host initiated guest snapshot.
+ *
+ *
+ * Copyright (C) 2013, Microsoft, Inc.
+ * Author : K. Y. Srinivasan <kys@microsoft.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.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/net.h>
+#include <linux/nls.h>
+#include <linux/connector.h>
+#include <linux/workqueue.h>
+#include <linux/hyperv.h>
+
+
+
+/*
+ * Global state maintained for transaction that is being processed.
+ * Note that only one transaction can be active at any point in time.
+ *
+ * This state is set when we receive a request from the host; we
+ * cleanup this state when the transaction is completed - when we respond
+ * to the host with the key value.
+ */
+
+static struct {
+       bool active; /* transaction status - active or not */
+       int recv_len; /* number of bytes received. */
+       struct vmbus_channel *recv_channel; /* chn we got the request */
+       u64 recv_req_id; /* request ID. */
+       struct hv_vss_msg  *msg; /* current message */
+} vss_transaction;
+
+
+static void vss_respond_to_host(int error);
+
+static struct cb_id vss_id = { CN_VSS_IDX, CN_VSS_VAL };
+static const char vss_name[] = "vss_kernel_module";
+static __u8 *recv_buffer;
+
+static void vss_send_op(struct work_struct *dummy);
+static DECLARE_WORK(vss_send_op_work, vss_send_op);
+
+/*
+ * Callback when data is received from user mode.
+ */
+
+static void
+vss_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
+{
+       struct hv_vss_msg *vss_msg;
+
+       vss_msg = (struct hv_vss_msg *)msg->data;
+
+       if (vss_msg->vss_hdr.operation == VSS_OP_REGISTER) {
+               pr_info("VSS daemon registered\n");
+               vss_transaction.active = false;
+               if (vss_transaction.recv_channel != NULL)
+                       hv_vss_onchannelcallback(vss_transaction.recv_channel);
+               return;
+
+       }
+       vss_respond_to_host(vss_msg->error);
+}
+
+
+static void vss_send_op(struct work_struct *dummy)
+{
+       int op = vss_transaction.msg->vss_hdr.operation;
+       struct cn_msg *msg;
+       struct hv_vss_msg *vss_msg;
+
+       msg = kzalloc(sizeof(*msg) + sizeof(*vss_msg), GFP_ATOMIC);
+       if (!msg)
+               return;
+
+       vss_msg = (struct hv_vss_msg *)msg->data;
+
+       msg->id.idx =  CN_VSS_IDX;
+       msg->id.val = CN_VSS_VAL;
+
+       vss_msg->vss_hdr.operation = op;
+       msg->len = sizeof(struct hv_vss_msg);
+
+       cn_netlink_send(msg, 0, GFP_ATOMIC);
+       kfree(msg);
+
+       return;
+}
+
+/*
+ * Send a response back to the host.
+ */
+
+static void
+vss_respond_to_host(int error)
+{
+       struct icmsg_hdr *icmsghdrp;
+       u32     buf_len;
+       struct vmbus_channel *channel;
+       u64     req_id;
+
+       /*
+        * If a transaction is not active; log and return.
+        */
+
+       if (!vss_transaction.active) {
+               /*
+                * This is a spurious call!
+                */
+               pr_warn("VSS: Transaction not active\n");
+               return;
+       }
+       /*
+        * Copy the global state for completing the transaction. Note that
+        * only one transaction can be active at a time.
+        */
+
+       buf_len = vss_transaction.recv_len;
+       channel = vss_transaction.recv_channel;
+       req_id = vss_transaction.recv_req_id;
+       vss_transaction.active = false;
+
+       icmsghdrp = (struct icmsg_hdr *)
+                       &recv_buffer[sizeof(struct vmbuspipe_hdr)];
+
+       if (channel->onchannel_callback == NULL)
+               /*
+                * We have raced with util driver being unloaded;
+                * silently return.
+                */
+               return;
+
+       icmsghdrp->status = error;
+
+       icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
+
+       vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
+                               VM_PKT_DATA_INBAND, 0);
+
+}
+
+/*
+ * This callback is invoked when we get a VSS message from the host.
+ * The host ensures that only one VSS transaction can be active at a time.
+ */
+
+void hv_vss_onchannelcallback(void *context)
+{
+       struct vmbus_channel *channel = context;
+       u32 recvlen;
+       u64 requestid;
+       struct hv_vss_msg *vss_msg;
+
+
+       struct icmsg_hdr *icmsghdrp;
+       struct icmsg_negotiate *negop = NULL;
+
+       if (vss_transaction.active) {
+               /*
+                * We will defer processing this callback once
+                * the current transaction is complete.
+                */
+               vss_transaction.recv_channel = channel;
+               return;
+       }
+
+       vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
+                        &requestid);
+
+       if (recvlen > 0) {
+               icmsghdrp = (struct icmsg_hdr *)&recv_buffer[
+                       sizeof(struct vmbuspipe_hdr)];
+
+               if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+                       vmbus_prep_negotiate_resp(icmsghdrp, negop,
+                                recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
+                       /*
+                        * We currently negotiate the highest number the
+                        * host has presented. If this version is not
+                        * atleast 5.0, reject.
+                        */
+                       negop = (struct icmsg_negotiate *)&recv_buffer[
+                               sizeof(struct vmbuspipe_hdr) +
+                               sizeof(struct icmsg_hdr)];
+
+                       if (negop->icversion_data[1].major < 5)
+                               negop->icframe_vercnt = 0;
+               } else {
+                       vss_msg = (struct hv_vss_msg *)&recv_buffer[
+                               sizeof(struct vmbuspipe_hdr) +
+                               sizeof(struct icmsg_hdr)];
+
+                       /*
+                        * Stash away this global state for completing the
+                        * transaction; note transactions are serialized.
+                        */
+
+                       vss_transaction.recv_len = recvlen;
+                       vss_transaction.recv_channel = channel;
+                       vss_transaction.recv_req_id = requestid;
+                       vss_transaction.active = true;
+                       vss_transaction.msg = (struct hv_vss_msg *)vss_msg;
+
+                       switch (vss_msg->vss_hdr.operation) {
+                               /*
+                                * Initiate a "freeze/thaw"
+                                * operation in the guest.
+                                * We respond to the host once
+                                * the operation is complete.
+                                *
+                                * We send the message to the
+                                * user space daemon and the
+                                * operation is performed in
+                                * the daemon.
+                                */
+                       case VSS_OP_FREEZE:
+                       case VSS_OP_THAW:
+                               schedule_work(&vss_send_op_work);
+                               return;
+
+                       case VSS_OP_HOT_BACKUP:
+                               vss_msg->vss_cf.flags =
+                                        VSS_HBU_NO_AUTO_RECOVERY;
+                               vss_respond_to_host(0);
+                               return;
+
+                       case VSS_OP_GET_DM_INFO:
+                               vss_msg->dm_info.flags = 0;
+                               vss_respond_to_host(0);
+                               return;
+
+                       default:
+                               vss_respond_to_host(0);
+                               return;
+
+                       }
+
+               }
+
+               icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
+                       | ICMSGHDRFLAG_RESPONSE;
+
+               vmbus_sendpacket(channel, recv_buffer,
+                                      recvlen, requestid,
+                                      VM_PKT_DATA_INBAND, 0);
+       }
+
+}
+
+int
+hv_vss_init(struct hv_util_service *srv)
+{
+       int err;
+
+       err = cn_add_callback(&vss_id, vss_name, vss_cn_callback);
+       if (err)
+               return err;
+       recv_buffer = srv->recv_buffer;
+
+       /*
+        * When this driver loads, the user level daemon that
+        * processes the host requests may not yet be running.
+        * Defer processing channel callbacks until the daemon
+        * has registered.
+        */
+       vss_transaction.active = true;
+       return 0;
+}
+
+void hv_vss_deinit(void)
+{
+       cn_del_callback(&vss_id);
+       cancel_work_sync(&vss_send_op_work);
+}
index 1d4cbd8..2f561c5 100644 (file)
@@ -49,6 +49,12 @@ static struct hv_util_service util_kvp = {
        .util_deinit = hv_kvp_deinit,
 };
 
+static struct hv_util_service util_vss = {
+       .util_cb = hv_vss_onchannelcallback,
+       .util_init = hv_vss_init,
+       .util_deinit = hv_vss_deinit,
+};
+
 static void perform_shutdown(struct work_struct *dummy)
 {
        orderly_poweroff(true);
@@ -339,6 +345,10 @@ static const struct hv_vmbus_device_id id_table[] = {
        { HV_KVP_GUID,
          .driver_data = (unsigned long)&util_kvp
        },
+       /* VSS GUID */
+       { HV_VSS_GUID,
+         .driver_data = (unsigned long)&util_vss
+       },
        { },
 };
 
index cafa72f..d6fbb57 100644 (file)
@@ -71,6 +71,7 @@ u32 hv_end_read(struct hv_ring_buffer_info *rbi)
 
 static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi)
 {
+       smp_mb();
        if (rbi->ring_buffer->interrupt_mask)
                return false;
 
index 89ac1cb..4f29117 100644 (file)
@@ -179,9 +179,29 @@ config SENSORS_ADM9240
          This driver can also be built as a module.  If so, the module
          will be called adm9240.
 
+config SENSORS_ADT7X10
+       tristate
+       help
+         This module contains common code shared by the ADT7310/ADT7320 and
+         ADT7410/ADT7420 temperature monitoring chip drivers.
+
+         If build as a module, the module will be called adt7x10.
+
+config SENSORS_ADT7310
+       tristate "Analog Devices ADT7310/ADT7320"
+       depends on SPI_MASTER
+       select SENSORS_ADT7X10
+       help
+         If you say yes here you get support for the Analog Devices
+         ADT7310 and ADT7320 temperature monitoring chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called adt7310.
+
 config SENSORS_ADT7410
        tristate "Analog Devices ADT7410/ADT7420"
        depends on I2C
+       select SENSORS_ADT7X10
        help
          If you say yes here you get support for the Analog Devices
          ADT7410 and ADT7420 temperature monitoring chips.
@@ -751,6 +771,16 @@ config SENSORS_LTC4261
          This driver can also be built as a module. If so, the module will
          be called ltc4261.
 
+config SENSORS_LM95234
+       tristate "National Semiconductor LM95234"
+       depends on I2C
+       help
+         If you say yes here you get support for the LM95234 temperature
+         sensor.
+
+         This driver can also be built as a module.  If so, the module
+         will be called lm95234.
+
 config SENSORS_LM95241
        tristate "National Semiconductor LM95241 and compatibles"
        depends on I2C
@@ -877,8 +907,22 @@ config SENSORS_MCP3021
          This driver can also be built as a module.  If so, the module
          will be called mcp3021.
 
+config SENSORS_NCT6775
+       tristate "Nuvoton NCT6775F and compatibles"
+       depends on !PPC
+       select HWMON_VID
+       help
+         If you say yes here you get support for the hardware monitoring
+         functionality of the Nuvoton NCT6775F, NCT6776F, NCT6779D
+         and compatible Super-I/O chips. This driver replaces the
+         w83627ehf driver for NCT6775F and NCT6776F.
+
+         This driver can also be built as a module.  If so, the module
+         will be called nct6775.
+
 config SENSORS_NTC_THERMISTOR
        tristate "NTC thermistor support"
+       depends on (!OF && !IIO) || (OF && IIO)
        help
          This driver supports NTC thermistors sensor reading and its
          interpretation. The driver can also monitor the temperature and
@@ -1204,8 +1248,8 @@ config SENSORS_TMP401
        tristate "Texas Instruments TMP401 and compatibles"
        depends on I2C
        help
-         If you say yes here you get support for Texas Instruments TMP401 and
-         TMP411 temperature sensor chips.
+         If you say yes here you get support for Texas Instruments TMP401,
+         TMP411, TMP431, and TMP432 temperature sensor chips.
 
          This driver can also be built as a module.  If so, the module
          will be called tmp401.
index 8d6d97e..5c71fe6 100644 (file)
@@ -34,6 +34,8 @@ obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
 obj-$(CONFIG_SENSORS_ADS1015)  += ads1015.o
 obj-$(CONFIG_SENSORS_ADS7828)  += ads7828.o
 obj-$(CONFIG_SENSORS_ADS7871)  += ads7871.o
+obj-$(CONFIG_SENSORS_ADT7X10)  += adt7x10.o
+obj-$(CONFIG_SENSORS_ADT7310)  += adt7310.o
 obj-$(CONFIG_SENSORS_ADT7410)  += adt7410.o
 obj-$(CONFIG_SENSORS_ADT7411)  += adt7411.o
 obj-$(CONFIG_SENSORS_ADT7462)  += adt7462.o
@@ -86,6 +88,7 @@ obj-$(CONFIG_SENSORS_LM87)    += lm87.o
 obj-$(CONFIG_SENSORS_LM90)     += lm90.o
 obj-$(CONFIG_SENSORS_LM92)     += lm92.o
 obj-$(CONFIG_SENSORS_LM93)     += lm93.o
+obj-$(CONFIG_SENSORS_LM95234)  += lm95234.o
 obj-$(CONFIG_SENSORS_LM95241)  += lm95241.o
 obj-$(CONFIG_SENSORS_LM95245)  += lm95245.o
 obj-$(CONFIG_SENSORS_LTC4151)  += ltc4151.o
@@ -103,6 +106,7 @@ obj-$(CONFIG_SENSORS_MAX6650)       += max6650.o
 obj-$(CONFIG_SENSORS_MAX6697)  += max6697.o
 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
 obj-$(CONFIG_SENSORS_MCP3021)  += mcp3021.o
+obj-$(CONFIG_SENSORS_NCT6775)  += nct6775.o
 obj-$(CONFIG_SENSORS_NTC_THERMISTOR)   += ntc_thermistor.o
 obj-$(CONFIG_SENSORS_PC87360)  += pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)  += pc87427.o
index 6119ff8..df0b699 100644 (file)
 #define ABIT_UGURU_MAX_TIMEOUTS                        2
 /* utility macros */
 #define ABIT_UGURU_NAME                                "abituguru"
-#define ABIT_UGURU_DEBUG(level, format, arg...)                                \
-       if (level <= verbose)                                           \
-               printk(KERN_DEBUG ABIT_UGURU_NAME ": "  format , ## arg)
+#define ABIT_UGURU_DEBUG(level, format, arg...)                \
+       do {                                            \
+               if (level <= verbose)                   \
+                       pr_debug(format , ## arg);      \
+       } while (0)
+
 /* Macros to help calculate the sysfs_names array length */
 /*
  * sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
@@ -1533,7 +1536,7 @@ static int abituguru_resume(struct device *dev)
 }
 
 static SIMPLE_DEV_PM_OPS(abituguru_pm, abituguru_suspend, abituguru_resume);
-#define ABIT_UGURU_PM  &abituguru_pm
+#define ABIT_UGURU_PM  (&abituguru_pm)
 #else
 #define ABIT_UGURU_PM  NULL
 #endif /* CONFIG_PM */
index 205327d..1d2da31 100644 (file)
 #define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT                5
 /* utility macros */
 #define ABIT_UGURU3_NAME                       "abituguru3"
-#define ABIT_UGURU3_DEBUG(format, arg...)      \
-       if (verbose)                            \
-               printk(KERN_DEBUG ABIT_UGURU3_NAME ": " format , ## arg)
+#define ABIT_UGURU3_DEBUG(format, arg...)              \
+       do {                                            \
+               if (verbose)                            \
+                       pr_debug(format , ## arg);      \
+       } while (0)
 
 /* Macros to help calculate the sysfs_names array length */
 #define ABIT_UGURU3_MAX_NO_SENSORS 26
@@ -1159,7 +1161,7 @@ static int abituguru3_resume(struct device *dev)
 }
 
 static SIMPLE_DEV_PM_OPS(abituguru3_pm, abituguru3_suspend, abituguru3_resume);
-#define ABIT_UGURU3_PM &abituguru3_pm
+#define ABIT_UGURU3_PM (&abituguru3_pm)
 #else
 #define ABIT_UGURU3_PM NULL
 #endif /* CONFIG_PM */
index a57584d..f4f9b21 100644 (file)
@@ -116,7 +116,7 @@ static int ad7314_probe(struct spi_device *spi_dev)
        if (chip == NULL)
                return -ENOMEM;
 
-       dev_set_drvdata(&spi_dev->dev, chip);
+       spi_set_drvdata(spi_dev, chip);
 
        ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
        if (ret < 0)
@@ -137,7 +137,7 @@ error_remove_group:
 
 static int ad7314_remove(struct spi_device *spi_dev)
 {
-       struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev);
+       struct ad7314_data *chip = spi_get_drvdata(spi_dev);
 
        hwmon_device_unregister(chip->hwmon_dev);
        sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
@@ -166,6 +166,5 @@ static struct spi_driver ad7314_driver = {
 module_spi_driver(ad7314_driver);
 
 MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
-MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital"
-                       " temperature sensor driver");
+MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver");
 MODULE_LICENSE("GPL v2");
index 71bcba8..7e76922 100644 (file)
@@ -312,8 +312,7 @@ static int adm1021_detect(struct i2c_client *client,
        int conv_rate, status, config, man_id, dev_id;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-               pr_debug("adm1021: detect failed, "
-                        "smbus byte data not supported!\n");
+               pr_debug("detect failed, smbus byte data not supported!\n");
                return -ENODEV;
        }
 
@@ -324,7 +323,7 @@ static int adm1021_detect(struct i2c_client *client,
 
        /* Check unused bits */
        if ((status & 0x03) || (config & 0x3F) || (conv_rate & 0xF8)) {
-               pr_debug("adm1021: detect failed, chip not detected!\n");
+               pr_debug("detect failed, chip not detected!\n");
                return -ENODEV;
        }
 
@@ -353,7 +352,7 @@ static int adm1021_detect(struct i2c_client *client,
        else
                type_name = "max1617";
 
-       pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n",
+       pr_debug("Detected chip %s at adapter %d, address 0x%02x.\n",
                 type_name, i2c_adapter_id(adapter), client->addr);
        strlcpy(info->type, type_name, I2C_NAME_SIZE);
 
@@ -368,10 +367,8 @@ static int adm1021_probe(struct i2c_client *client,
 
        data = devm_kzalloc(&client->dev, sizeof(struct adm1021_data),
                            GFP_KERNEL);
-       if (!data) {
-               pr_debug("adm1021: detect failed, devm_kzalloc failed!\n");
+       if (!data)
                return -ENOMEM;
-       }
 
        i2c_set_clientdata(client, data);
        data->type = id->driver_data;
index ea09046..3a6d9ef 100644 (file)
@@ -49,14 +49,14 @@ static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
 module_param_array(gpio_input, int, NULL, 0);
 MODULE_PARM_DESC(gpio_input, "List of GPIO pins (0-16) to program as inputs");
 module_param_array(gpio_output, int, NULL, 0);
-MODULE_PARM_DESC(gpio_output, "List of GPIO pins (0-16) to program as "
-       "outputs");
+MODULE_PARM_DESC(gpio_output,
+                "List of GPIO pins (0-16) to program as outputs");
 module_param_array(gpio_inverted, int, NULL, 0);
-MODULE_PARM_DESC(gpio_inverted, "List of GPIO pins (0-16) to program as "
-       "inverted");
+MODULE_PARM_DESC(gpio_inverted,
+                "List of GPIO pins (0-16) to program as inverted");
 module_param_array(gpio_normal, int, NULL, 0);
-MODULE_PARM_DESC(gpio_normal, "List of GPIO pins (0-16) to program as "
-       "normal/non-inverted");
+MODULE_PARM_DESC(gpio_normal,
+                "List of GPIO pins (0-16) to program as normal/non-inverted");
 module_param_array(gpio_fan, int, NULL, 0);
 MODULE_PARM_DESC(gpio_fan, "List of GPIO pins (0-7) to program as fan tachs");
 
@@ -372,31 +372,31 @@ static void adm1026_init_client(struct i2c_client *client)
        dev_dbg(&client->dev, "ADM1026_REG_CONFIG1 is: 0x%02x\n",
                data->config1);
        if ((data->config1 & CFG1_MONITOR) == 0) {
-               dev_dbg(&client->dev, "Monitoring not currently "
-                       "enabled.\n");
+               dev_dbg(&client->dev,
+                       "Monitoring not currently enabled.\n");
        }
        if (data->config1 & CFG1_INT_ENABLE) {
-               dev_dbg(&client->dev, "SMBALERT interrupts are "
-                       "enabled.\n");
+               dev_dbg(&client->dev,
+                       "SMBALERT interrupts are enabled.\n");
        }
        if (data->config1 & CFG1_AIN8_9) {
-               dev_dbg(&client->dev, "in8 and in9 enabled. "
-                       "temp3 disabled.\n");
+               dev_dbg(&client->dev,
+                       "in8 and in9 enabled. temp3 disabled.\n");
        } else {
-               dev_dbg(&client->dev, "temp3 enabled.  in8 and "
-                       "in9 disabled.\n");
+               dev_dbg(&client->dev,
+                       "temp3 enabled.  in8 and in9 disabled.\n");
        }
        if (data->config1 & CFG1_THERM_HOT) {
-               dev_dbg(&client->dev, "Automatic THERM, PWM, "
-                       "and temp limits enabled.\n");
+               dev_dbg(&client->dev,
+                       "Automatic THERM, PWM, and temp limits enabled.\n");
        }
 
        if (data->config3 & CFG3_GPIO16_ENABLE) {
-               dev_dbg(&client->dev, "GPIO16 enabled.  THERM "
-                       "pin disabled.\n");
+               dev_dbg(&client->dev,
+                       "GPIO16 enabled.  THERM pin disabled.\n");
        } else {
-               dev_dbg(&client->dev, "THERM pin enabled.  "
-                       "GPIO16 disabled.\n");
+               dev_dbg(&client->dev,
+                       "THERM pin enabled.  GPIO16 disabled.\n");
        }
        if (data->config3 & CFG3_VREF_250)
                dev_dbg(&client->dev, "Vref is 2.50 Volts.\n");
@@ -1798,8 +1798,8 @@ static int adm1026_detect(struct i2c_client *client,
        company = adm1026_read_value(client, ADM1026_REG_COMPANY);
        verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP);
 
-       dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with"
-               " COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
+       dev_dbg(&adapter->dev,
+               "Detecting device at %d,0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
                i2c_adapter_id(client->adapter), client->addr,
                company, verstep);
 
@@ -1811,11 +1811,12 @@ static int adm1026_detect(struct i2c_client *client,
                /* Analog Devices ADM1026 */
        } else if (company == ADM1026_COMPANY_ANALOG_DEV
                && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
-               dev_err(&adapter->dev, "Unrecognized stepping "
-                       "0x%02x. Defaulting to ADM1026.\n", verstep);
+               dev_err(&adapter->dev,
+                       "Unrecognized stepping 0x%02x. Defaulting to ADM1026.\n",
+                       verstep);
        } else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
-               dev_err(&adapter->dev, "Found version/stepping "
-                       "0x%02x. Assuming generic ADM1026.\n",
+               dev_err(&adapter->dev,
+                       "Found version/stepping 0x%02x. Assuming generic ADM1026.\n",
                        verstep);
        } else {
                dev_dbg(&adapter->dev, "Autodetection failed\n");
index 97f4718..9ee5e06 100644 (file)
@@ -224,8 +224,9 @@ static ssize_t set_fan_div(struct device *dev,
                break;
        default:
                mutex_unlock(&data->update_lock);
-               dev_err(&client->dev, "fan_div value %ld not "
-                       "supported. Choose one of 1, 2 or 4!\n", val);
+               dev_err(&client->dev,
+                       "fan_div value %ld not supported. Choose one of 1, 2 or 4!\n",
+                       val);
                return -EINVAL;
        }
        /* Update the value */
@@ -326,8 +327,8 @@ static int adm1029_detect(struct i2c_client *client,
                 * There are no "official" CHIP ID, so actually
                 * we use Major/Minor revision for that
                 */
-               pr_info("adm1029: Unknown major revision %x, "
-                       "please let us know\n", chip_id);
+               pr_info("Unknown major revision %x, please let us know\n",
+                       chip_id);
                return -ENODEV;
        }
 
index 2416628..086d02a 100644 (file)
@@ -351,8 +351,9 @@ static void adm9240_write_fan_div(struct i2c_client *client, int nr,
        reg &= ~(3 << shift);
        reg |= (fan_div << shift);
        i2c_smbus_write_byte_data(client, ADM9240_REG_VID_FAN_DIV, reg);
-       dev_dbg(&client->dev, "fan%d clock divider changed from %u "
-                       "to %u\n", nr + 1, 1 << old, 1 << fan_div);
+       dev_dbg(&client->dev,
+               "fan%d clock divider changed from %u to %u\n",
+               nr + 1, 1 << old, 1 << fan_div);
 }
 
 /*
@@ -699,8 +700,8 @@ static void adm9240_init_client(struct i2c_client *client)
                /* start measurement cycle */
                i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1);
 
-               dev_info(&client->dev, "cold start: config was 0x%02x "
-                               "mode %u\n", conf, mode);
+               dev_info(&client->dev,
+                        "cold start: config was 0x%02x mode %u\n", conf, mode);
        }
 }
 
index a798759..3eff73b 100644 (file)
  * the instruction byte
  */
 /*Instruction Bit masks*/
-#define INST_MODE_bm   (1<<7)
-#define INST_READ_bm   (1<<6)
-#define INST_16BIT_bm  (1<<5)
+#define INST_MODE_BM   (1 << 7)
+#define INST_READ_BM   (1 << 6)
+#define INST_16BIT_BM  (1 << 5)
 
 /*From figure 18 in the datasheet*/
 /*bit masks for Rev/Oscillator Control Register*/
-#define MUX_CNV_bv     7
-#define MUX_CNV_bm     (1<<MUX_CNV_bv)
-#define MUX_M3_bm      (1<<3) /*M3 selects single ended*/
-#define MUX_G_bv       4 /*allows for reg = (gain << MUX_G_bv) | ...*/
+#define MUX_CNV_BV     7
+#define MUX_CNV_BM     (1 << MUX_CNV_BV)
+#define MUX_M3_BM      (1 << 3) /*M3 selects single ended*/
+#define MUX_G_BV       4 /*allows for reg = (gain << MUX_G_BV) | ...*/
 
 /*From figure 18 in the datasheet*/
 /*bit masks for Rev/Oscillator Control Register*/
-#define OSC_OSCR_bm    (1<<5)
-#define OSC_OSCE_bm    (1<<4)
-#define OSC_REFE_bm    (1<<3)
-#define OSC_BUFE_bm    (1<<2)
-#define OSC_R2V_bm     (1<<1)
-#define OSC_RBG_bm     (1<<0)
+#define OSC_OSCR_BM    (1 << 5)
+#define OSC_OSCE_BM    (1 << 4)
+#define OSC_REFE_BM    (1 << 3)
+#define OSC_BUFE_BM    (1 << 2)
+#define OSC_R2V_BM     (1 << 1)
+#define OSC_RBG_BM     (1 << 0)
 
 #include <linux/module.h>
 #include <linux/init.h>
@@ -79,7 +79,7 @@ struct ads7871_data {
 static int ads7871_read_reg8(struct spi_device *spi, int reg)
 {
        int ret;
-       reg = reg | INST_READ_bm;
+       reg = reg | INST_READ_BM;
        ret = spi_w8r8(spi, reg);
        return ret;
 }
@@ -87,7 +87,7 @@ static int ads7871_read_reg8(struct spi_device *spi, int reg)
 static int ads7871_read_reg16(struct spi_device *spi, int reg)
 {
        int ret;
-       reg = reg | INST_READ_bm | INST_16BIT_bm;
+       reg = reg | INST_READ_BM | INST_16BIT_BM;
        ret = spi_w8r16(spi, reg);
        return ret;
 }
@@ -111,13 +111,13 @@ static ssize_t show_voltage(struct device *dev,
         * TODO: add support for conversions
         * other than single ended with a gain of 1
         */
-       /*MUX_M3_bm forces single ended*/
+       /*MUX_M3_BM forces single ended*/
        /*This is also where the gain of the PGA would be set*/
        ads7871_write_reg8(spi, REG_GAIN_MUX,
-               (MUX_CNV_bm | MUX_M3_bm | channel));
+               (MUX_CNV_BM | MUX_M3_BM | channel));
 
        ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
-       mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
+       mux_cnv = ((ret & MUX_CNV_BM) >> MUX_CNV_BV);
        /*
         * on 400MHz arm9 platform the conversion
         * is already done when we do this test
@@ -125,14 +125,14 @@ static ssize_t show_voltage(struct device *dev,
        while ((i < 2) && mux_cnv) {
                i++;
                ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
-               mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
+               mux_cnv = ((ret & MUX_CNV_BM) >> MUX_CNV_BV);
                msleep_interruptible(1);
        }
 
        if (mux_cnv == 0) {
                val = ads7871_read_reg16(spi, REG_LS_BYTE);
                /*result in volts*10000 = (val/8192)*2.5*10000*/
-               val = ((val>>2) * 25000) / 8192;
+               val = ((val >> 2) * 25000) / 8192;
                return sprintf(buf, "%d\n", val);
        } else {
                return -1;
@@ -189,7 +189,7 @@ static int ads7871_probe(struct spi_device *spi)
        ads7871_write_reg8(spi, REG_SER_CONTROL, 0);
        ads7871_write_reg8(spi, REG_AD_CONTROL, 0);
 
-       val = (OSC_OSCR_bm | OSC_OSCE_bm | OSC_REFE_bm | OSC_BUFE_bm);
+       val = (OSC_OSCR_BM | OSC_OSCE_BM | OSC_REFE_BM | OSC_BUFE_BM);
        ads7871_write_reg8(spi, REG_OSC_CONTROL, val);
        ret = ads7871_read_reg8(spi, REG_OSC_CONTROL);
 
diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
new file mode 100644 (file)
index 0000000..da5f078
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * ADT7310/ADT7310 digital temperature sensor driver
+ *
+ * Copyright 2012-2013 Analog Devices Inc.
+ *   Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <asm/unaligned.h>
+
+#include "adt7x10.h"
+
+#define ADT7310_STATUS                 0
+#define ADT7310_CONFIG                 1
+#define ADT7310_TEMPERATURE            2
+#define ADT7310_ID                     3
+#define ADT7310_T_CRIT                 4
+#define ADT7310_T_HYST                 5
+#define ADT7310_T_ALARM_HIGH           6
+#define ADT7310_T_ALARM_LOW            7
+
+static const u8 adt7310_reg_table[] = {
+       [ADT7X10_TEMPERATURE]   = ADT7310_TEMPERATURE,
+       [ADT7X10_STATUS]        = ADT7310_STATUS,
+       [ADT7X10_CONFIG]        = ADT7310_CONFIG,
+       [ADT7X10_T_ALARM_HIGH]  = ADT7310_T_ALARM_HIGH,
+       [ADT7X10_T_ALARM_LOW]   = ADT7310_T_ALARM_LOW,
+       [ADT7X10_T_CRIT]        = ADT7310_T_CRIT,
+       [ADT7X10_T_HYST]        = ADT7310_T_HYST,
+       [ADT7X10_ID]            = ADT7310_ID,
+};
+
+#define ADT7310_CMD_REG_OFFSET 3
+#define ADT7310_CMD_READ       0x40
+
+#define AD7310_COMMAND(reg) (adt7310_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
+
+static int adt7310_spi_read_word(struct device *dev, u8 reg)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       int ret;
+
+       ret = spi_w8r16(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
+       if (ret < 0)
+               return ret;
+
+       return be16_to_cpu((__force __be16)ret);
+}
+
+static int adt7310_spi_write_word(struct device *dev, u8 reg, u16 data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       u8 buf[3];
+
+       buf[0] = AD7310_COMMAND(reg);
+       put_unaligned_be16(data, &buf[1]);
+
+       return spi_write(spi, buf, sizeof(buf));
+}
+
+static int adt7310_spi_read_byte(struct device *dev, u8 reg)
+{
+       struct spi_device *spi = to_spi_device(dev);
+
+       return spi_w8r8(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
+}
+
+static int adt7310_spi_write_byte(struct device *dev, u8 reg,
+       u8 data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       u8 buf[2];
+
+       buf[0] = AD7310_COMMAND(reg);
+       buf[1] = data;
+
+       return spi_write(spi, buf, sizeof(buf));
+}
+
+static const struct adt7x10_ops adt7310_spi_ops = {
+       .read_word = adt7310_spi_read_word,
+       .write_word = adt7310_spi_write_word,
+       .read_byte = adt7310_spi_read_byte,
+       .write_byte = adt7310_spi_write_byte,
+};
+
+static int adt7310_spi_probe(struct spi_device *spi)
+{
+       return adt7x10_probe(&spi->dev, spi_get_device_id(spi)->name, spi->irq,
+                       &adt7310_spi_ops);
+}
+
+static int adt7310_spi_remove(struct spi_device *spi)
+{
+       return adt7x10_remove(&spi->dev, spi->irq);
+}
+
+static const struct spi_device_id adt7310_id[] = {
+       { "adt7310", 0 },
+       { "adt7320", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, adt7310_id);
+
+static struct spi_driver adt7310_driver = {
+       .driver = {
+               .name   = "adt7310",
+               .owner  = THIS_MODULE,
+               .pm     = ADT7X10_DEV_PM_OPS,
+       },
+       .probe          = adt7310_spi_probe,
+       .remove         = adt7310_spi_remove,
+       .id_table       = adt7310_id,
+};
+module_spi_driver(adt7310_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ADT7310/ADT7320 driver");
+MODULE_LICENSE("GPL");
index 99a7290..0dc066a 100644 (file)
 /*
- * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
- *      monitoring
- * This driver handles the ADT7410 and compatible digital temperature sensors.
- * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
- * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
- * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
+ * ADT7410/ADT7420 digital temperature sensor driver
  *
- * 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.
+ * Copyright 2012-2013 Analog Devices Inc.
+ *   Author: Lars-Peter Clausen <lars@metafoo.de>
  *
- * 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, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the GPL-2 or later.
  */
 
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-
-/*
- * ADT7410 registers definition
- */
-
-#define ADT7410_TEMPERATURE            0
-#define ADT7410_STATUS                 2
-#define ADT7410_CONFIG                 3
-#define ADT7410_T_ALARM_HIGH           4
-#define ADT7410_T_ALARM_LOW            6
-#define ADT7410_T_CRIT                 8
-#define ADT7410_T_HYST                 0xA
-
-/*
- * ADT7410 status
- */
-#define ADT7410_STAT_T_LOW             (1 << 4)
-#define ADT7410_STAT_T_HIGH            (1 << 5)
-#define ADT7410_STAT_T_CRIT            (1 << 6)
-#define ADT7410_STAT_NOT_RDY           (1 << 7)
-
-/*
- * ADT7410 config
- */
-#define ADT7410_FAULT_QUEUE_MASK       (1 << 0 | 1 << 1)
-#define ADT7410_CT_POLARITY            (1 << 2)
-#define ADT7410_INT_POLARITY           (1 << 3)
-#define ADT7410_EVENT_MODE             (1 << 4)
-#define ADT7410_MODE_MASK              (1 << 5 | 1 << 6)
-#define ADT7410_FULL                   (0 << 5 | 0 << 6)
-#define ADT7410_PD                     (1 << 5 | 1 << 6)
-#define ADT7410_RESOLUTION             (1 << 7)
-
-/*
- * ADT7410 masks
- */
-#define ADT7410_T13_VALUE_MASK                 0xFFF8
-#define ADT7410_T_HYST_MASK                    0xF
-
-/* straight from the datasheet */
-#define ADT7410_TEMP_MIN (-55000)
-#define ADT7410_TEMP_MAX 150000
-
-enum adt7410_type {            /* keep sorted in alphabetical order */
-       adt7410,
-};
-
-static const u8 ADT7410_REG_TEMP[4] = {
-       ADT7410_TEMPERATURE,            /* input */
-       ADT7410_T_ALARM_HIGH,           /* high */
-       ADT7410_T_ALARM_LOW,            /* low */
-       ADT7410_T_CRIT,                 /* critical */
-};
-
-/* Each client has this additional data */
-struct adt7410_data {
-       struct device           *hwmon_dev;
-       struct mutex            update_lock;
-       u8                      config;
-       u8                      oldconfig;
-       bool                    valid;          /* true if registers valid */
-       unsigned long           last_updated;   /* In jiffies */
-       s16                     temp[4];        /* Register values,
-                                                  0 = input
-                                                  1 = high
-                                                  2 = low
-                                                  3 = critical */
-       u8                      hyst;           /* hysteresis offset */
-};
-
-/*
- * adt7410 register access by I2C
- */
-static int adt7410_temp_ready(struct i2c_client *client)
-{
-       int i, status;
-
-       for (i = 0; i < 6; i++) {
-               status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
-               if (status < 0)
-                       return status;
-               if (!(status & ADT7410_STAT_NOT_RDY))
-                       return 0;
-               msleep(60);
-       }
-       return -ETIMEDOUT;
-}
-
-static struct adt7410_data *adt7410_update_device(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7410_data *data = i2c_get_clientdata(client);
-       struct adt7410_data *ret = data;
-       mutex_lock(&data->update_lock);
-
-       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
-           || !data->valid) {
-               int i, status;
 
-               dev_dbg(&client->dev, "Starting update\n");
+#include "adt7x10.h"
 
-               status = adt7410_temp_ready(client); /* check for new value */
-               if (unlikely(status)) {
-                       ret = ERR_PTR(status);
-                       goto abort;
-               }
-               for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
-                       status = i2c_smbus_read_word_swapped(client,
-                                                       ADT7410_REG_TEMP[i]);
-                       if (unlikely(status < 0)) {
-                               dev_dbg(dev,
-                                       "Failed to read value: reg %d, error %d\n",
-                                       ADT7410_REG_TEMP[i], status);
-                               ret = ERR_PTR(status);
-                               goto abort;
-                       }
-                       data->temp[i] = status;
-               }
-               status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
-               if (unlikely(status < 0)) {
-                       dev_dbg(dev,
-                               "Failed to read value: reg %d, error %d\n",
-                               ADT7410_T_HYST, status);
-                       ret = ERR_PTR(status);
-                       goto abort;
-               }
-               data->hyst = status;
-               data->last_updated = jiffies;
-               data->valid = true;
-       }
-
-abort:
-       mutex_unlock(&data->update_lock);
-       return ret;
-}
-
-static s16 ADT7410_TEMP_TO_REG(long temp)
+static int adt7410_i2c_read_word(struct device *dev, u8 reg)
 {
-       return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
-                                          ADT7410_TEMP_MAX) * 128, 1000);
+       return i2c_smbus_read_word_swapped(to_i2c_client(dev), reg);
 }
 
-static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
+static int adt7410_i2c_write_word(struct device *dev, u8 reg, u16 data)
 {
-       /* in 13 bit mode, bits 0-2 are status flags - mask them out */
-       if (!(data->config & ADT7410_RESOLUTION))
-               reg &= ADT7410_T13_VALUE_MASK;
-       /*
-        * temperature is stored in twos complement format, in steps of
-        * 1/128°C
-        */
-       return DIV_ROUND_CLOSEST(reg * 1000, 128);
+       return i2c_smbus_write_word_swapped(to_i2c_client(dev), reg, data);
 }
 
-/*-----------------------------------------------------------------------*/
-
-/* sysfs attributes for hwmon */
-
-static ssize_t adt7410_show_temp(struct device *dev,
-                                struct device_attribute *da, char *buf)
+static int adt7410_i2c_read_byte(struct device *dev, u8 reg)
 {
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-       struct adt7410_data *data = adt7410_update_device(dev);
-
-       if (IS_ERR(data))
-               return PTR_ERR(data);
-
-       return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
-                      data->temp[attr->index]));
+       return i2c_smbus_read_byte_data(to_i2c_client(dev), reg);
 }
 
-static ssize_t adt7410_set_temp(struct device *dev,
-                               struct device_attribute *da,
-                               const char *buf, size_t count)
+static int adt7410_i2c_write_byte(struct device *dev, u8 reg, u8 data)
 {
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7410_data *data = i2c_get_clientdata(client);
-       int nr = attr->index;
-       long temp;
-       int ret;
-
-       ret = kstrtol(buf, 10, &temp);
-       if (ret)
-               return ret;
-
-       mutex_lock(&data->update_lock);
-       data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
-       ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
-                                          data->temp[nr]);
-       if (ret)
-               count = ret;
-       mutex_unlock(&data->update_lock);
-       return count;
+       return i2c_smbus_write_byte_data(to_i2c_client(dev), reg, data);
 }
 
-static ssize_t adt7410_show_t_hyst(struct device *dev,
-                                  struct device_attribute *da,
-                                  char *buf)
-{
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-       struct adt7410_data *data;
-       int nr = attr->index;
-       int hyst;
-
-       data = adt7410_update_device(dev);
-       if (IS_ERR(data))
-               return PTR_ERR(data);
-       hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
-
-       /*
-        * hysteresis is stored as a 4 bit offset in the device, convert it
-        * to an absolute value
-        */
-       if (nr == 2)    /* min has positive offset, others have negative */
-               hyst = -hyst;
-       return sprintf(buf, "%d\n",
-                      ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
-}
-
-static ssize_t adt7410_set_t_hyst(struct device *dev,
-                                 struct device_attribute *da,
-                                 const char *buf, size_t count)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7410_data *data = i2c_get_clientdata(client);
-       int limit, ret;
-       long hyst;
-
-       ret = kstrtol(buf, 10, &hyst);
-       if (ret)
-               return ret;
-       /* convert absolute hysteresis value to a 4 bit delta value */
-       limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
-       hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
-       data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
-                              ADT7410_T_HYST_MASK);
-       ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
-       if (ret)
-               return ret;
-
-       return count;
-}
-
-static ssize_t adt7410_show_alarm(struct device *dev,
-                                 struct device_attribute *da,
-                                 char *buf)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-       int ret;
-
-       ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
-       if (ret < 0)
-               return ret;
-
-       return sprintf(buf, "%d\n", !!(ret & attr->index));
-}
-
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
-                         adt7410_show_temp, adt7410_set_temp, 1);
-static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
-                         adt7410_show_temp, adt7410_set_temp, 2);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
-                         adt7410_show_temp, adt7410_set_temp, 3);
-static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
-                         adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
-static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
-                         adt7410_show_t_hyst, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
-                         adt7410_show_t_hyst, NULL, 3);
-static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
-                         NULL, ADT7410_STAT_T_LOW);
-static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
-                         NULL, ADT7410_STAT_T_HIGH);
-static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
-                         NULL, ADT7410_STAT_T_CRIT);
-
-static struct attribute *adt7410_attributes[] = {
-       &sensor_dev_attr_temp1_input.dev_attr.attr,
-       &sensor_dev_attr_temp1_max.dev_attr.attr,
-       &sensor_dev_attr_temp1_min.dev_attr.attr,
-       &sensor_dev_attr_temp1_crit.dev_attr.attr,
-       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
-       &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
-       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
-       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
-       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
-       &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
-       NULL
+static const struct adt7x10_ops adt7410_i2c_ops = {
+       .read_word = adt7410_i2c_read_word,
+       .write_word = adt7410_i2c_write_word,
+       .read_byte = adt7410_i2c_read_byte,
+       .write_byte = adt7410_i2c_write_byte,
 };
 
-static const struct attribute_group adt7410_group = {
-       .attrs = adt7410_attributes,
-};
-
-/*-----------------------------------------------------------------------*/
-
-/* device probe and removal */
-
-static int adt7410_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int adt7410_i2c_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
 {
-       struct adt7410_data *data;
-       int ret;
-
        if (!i2c_check_functionality(client->adapter,
                        I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
                return -ENODEV;
 
-       data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
-                           GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       i2c_set_clientdata(client, data);
-       mutex_init(&data->update_lock);
-
-       /* configure as specified */
-       ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
-       if (ret < 0) {
-               dev_dbg(&client->dev, "Can't read config? %d\n", ret);
-               return ret;
-       }
-       data->oldconfig = ret;
-       /*
-        * Set to 16 bit resolution, continous conversion and comparator mode.
-        */
-       ret &= ~ADT7410_MODE_MASK;
-       data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
-                       ADT7410_EVENT_MODE;
-       if (data->config != data->oldconfig) {
-               ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
-                                               data->config);
-               if (ret)
-                       return ret;
-       }
-       dev_dbg(&client->dev, "Config %02x\n", data->config);
-
-       /* Register sysfs hooks */
-       ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
-       if (ret)
-               goto exit_restore;
-
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               ret = PTR_ERR(data->hwmon_dev);
-               goto exit_remove;
-       }
-
-       dev_info(&client->dev, "sensor '%s'\n", client->name);
-
-       return 0;
-
-exit_remove:
-       sysfs_remove_group(&client->dev.kobj, &adt7410_group);
-exit_restore:
-       i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
-       return ret;
+       return adt7x10_probe(&client->dev, NULL, client->irq, &adt7410_i2c_ops);
 }
 
-static int adt7410_remove(struct i2c_client *client)
+static int adt7410_i2c_remove(struct i2c_client *client)
 {
-       struct adt7410_data *data = i2c_get_clientdata(client);
-
-       hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_group(&client->dev.kobj, &adt7410_group);
-       if (data->oldconfig != data->config)
-               i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
-                                         data->oldconfig);
-       return 0;
+       return adt7x10_remove(&client->dev, client->irq);
 }
 
 static const struct i2c_device_id adt7410_ids[] = {
-       { "adt7410", adt7410, },
-       { "adt7420", adt7410, },
-       { /* LIST END */ }
+       { "adt7410", 0 },
+       { "adt7420", 0 },
+       {}
 };
 MODULE_DEVICE_TABLE(i2c, adt7410_ids);
 
-#ifdef CONFIG_PM_SLEEP
-static int adt7410_suspend(struct device *dev)
-{
-       int ret;
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7410_data *data = i2c_get_clientdata(client);
-
-       ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
-                                       data->config | ADT7410_PD);
-       return ret;
-}
-
-static int adt7410_resume(struct device *dev)
-{
-       int ret;
-       struct i2c_client *client = to_i2c_client(dev);
-       struct adt7410_data *data = i2c_get_clientdata(client);
-
-       ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
-       return ret;
-}
-
-static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
-
-#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
-#else
-#define ADT7410_DEV_PM_OPS NULL
-#endif /* CONFIG_PM */
-
 static struct i2c_driver adt7410_driver = {
        .class          = I2C_CLASS_HWMON,
        .driver = {
                .name   = "adt7410",
-               .pm     = ADT7410_DEV_PM_OPS,
+               .pm     = ADT7X10_DEV_PM_OPS,
        },
-       .probe          = adt7410_probe,
-       .remove         = adt7410_remove,
+       .probe          = adt7410_i2c_probe,
+       .remove         = adt7410_i2c_remove,
        .id_table       = adt7410_ids,
        .address_list   = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
 };
-
 module_i2c_driver(adt7410_driver);
 
-MODULE_AUTHOR("Hartmut Knaack");
-MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ADT7410/AD7420 driver");
 MODULE_LICENSE("GPL");
index 34ff03a..d9299de 100644 (file)
@@ -259,15 +259,17 @@ static int adt7411_detect(struct i2c_client *client,
 
        val = i2c_smbus_read_byte_data(client, ADT7411_REG_MANUFACTURER_ID);
        if (val < 0 || val != ADT7411_MANUFACTURER_ID) {
-               dev_dbg(&client->dev, "Wrong manufacturer ID. Got %d, "
-                       "expected %d\n", val, ADT7411_MANUFACTURER_ID);
+               dev_dbg(&client->dev,
+                       "Wrong manufacturer ID. Got %d, expected %d\n",
+                       val, ADT7411_MANUFACTURER_ID);
                return -ENODEV;
        }
 
        val = i2c_smbus_read_byte_data(client, ADT7411_REG_DEVICE_ID);
        if (val < 0 || val != ADT7411_DEVICE_ID) {
-               dev_dbg(&client->dev, "Wrong device ID. Got %d, "
-                       "expected %d\n", val, ADT7411_DEVICE_ID);
+               dev_dbg(&client->dev,
+                       "Wrong device ID. Got %d, expected %d\n",
+                       val, ADT7411_DEVICE_ID);
                return -ENODEV;
        }
 
diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c
new file mode 100644 (file)
index 0000000..98141f4
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * adt7x10.c - Part of lm_sensors, Linux kernel modules for hardware
+ *      monitoring
+ * This driver handles the ADT7410 and compatible digital temperature sensors.
+ * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
+ * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
+ * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include "adt7x10.h"
+
+/*
+ * ADT7X10 status
+ */
+#define ADT7X10_STAT_T_LOW             (1 << 4)
+#define ADT7X10_STAT_T_HIGH            (1 << 5)
+#define ADT7X10_STAT_T_CRIT            (1 << 6)
+#define ADT7X10_STAT_NOT_RDY           (1 << 7)
+
+/*
+ * ADT7X10 config
+ */
+#define ADT7X10_FAULT_QUEUE_MASK       (1 << 0 | 1 << 1)
+#define ADT7X10_CT_POLARITY            (1 << 2)
+#define ADT7X10_INT_POLARITY           (1 << 3)
+#define ADT7X10_EVENT_MODE             (1 << 4)
+#define ADT7X10_MODE_MASK              (1 << 5 | 1 << 6)
+#define ADT7X10_FULL                   (0 << 5 | 0 << 6)
+#define ADT7X10_PD                     (1 << 5 | 1 << 6)
+#define ADT7X10_RESOLUTION             (1 << 7)
+
+/*
+ * ADT7X10 masks
+ */
+#define ADT7X10_T13_VALUE_MASK         0xFFF8
+#define ADT7X10_T_HYST_MASK            0xF
+
+/* straight from the datasheet */
+#define ADT7X10_TEMP_MIN (-55000)
+#define ADT7X10_TEMP_MAX 150000
+
+/* Each client has this additional data */
+struct adt7x10_data {
+       const struct adt7x10_ops *ops;
+       const char              *name;
+       struct device           *hwmon_dev;
+       struct mutex            update_lock;
+       u8                      config;
+       u8                      oldconfig;
+       bool                    valid;          /* true if registers valid */
+       unsigned long           last_updated;   /* In jiffies */
+       s16                     temp[4];        /* Register values,
+                                                  0 = input
+                                                  1 = high
+                                                  2 = low
+                                                  3 = critical */
+       u8                      hyst;           /* hysteresis offset */
+};
+
+static int adt7x10_read_byte(struct device *dev, u8 reg)
+{
+       struct adt7x10_data *d = dev_get_drvdata(dev);
+       return d->ops->read_byte(dev, reg);
+}
+
+static int adt7x10_write_byte(struct device *dev, u8 reg, u8 data)
+{
+       struct adt7x10_data *d = dev_get_drvdata(dev);
+       return d->ops->write_byte(dev, reg, data);
+}
+
+static int adt7x10_read_word(struct device *dev, u8 reg)
+{
+       struct adt7x10_data *d = dev_get_drvdata(dev);
+       return d->ops->read_word(dev, reg);
+}
+
+static int adt7x10_write_word(struct device *dev, u8 reg, u16 data)
+{
+       struct adt7x10_data *d = dev_get_drvdata(dev);
+       return d->ops->write_word(dev, reg, data);
+}
+
+static const u8 ADT7X10_REG_TEMP[4] = {
+       ADT7X10_TEMPERATURE,            /* input */
+       ADT7X10_T_ALARM_HIGH,           /* high */
+       ADT7X10_T_ALARM_LOW,            /* low */
+       ADT7X10_T_CRIT,                 /* critical */
+};
+
+static irqreturn_t adt7x10_irq_handler(int irq, void *private)
+{
+       struct device *dev = private;
+       int status;
+
+       status = adt7x10_read_byte(dev, ADT7X10_STATUS);
+       if (status < 0)
+               return IRQ_HANDLED;
+
+       if (status & ADT7X10_STAT_T_HIGH)
+               sysfs_notify(&dev->kobj, NULL, "temp1_max_alarm");
+       if (status & ADT7X10_STAT_T_LOW)
+               sysfs_notify(&dev->kobj, NULL, "temp1_min_alarm");
+       if (status & ADT7X10_STAT_T_CRIT)
+               sysfs_notify(&dev->kobj, NULL, "temp1_crit_alarm");
+
+       return IRQ_HANDLED;
+}
+
+static int adt7x10_temp_ready(struct device *dev)
+{
+       int i, status;
+
+       for (i = 0; i < 6; i++) {
+               status = adt7x10_read_byte(dev, ADT7X10_STATUS);
+               if (status < 0)
+                       return status;
+               if (!(status & ADT7X10_STAT_NOT_RDY))
+                       return 0;
+               msleep(60);
+       }
+       return -ETIMEDOUT;
+}
+
+static int adt7x10_update_temp(struct device *dev)
+{
+       struct adt7x10_data *data = dev_get_drvdata(dev);
+       int ret = 0;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+           || !data->valid) {
+               int temp;
+
+               dev_dbg(dev, "Starting update\n");
+
+               ret = adt7x10_temp_ready(dev); /* check for new value */
+               if (ret)
+                       goto abort;
+
+               temp = adt7x10_read_word(dev, ADT7X10_REG_TEMP[0]);
+               if (temp < 0) {
+                       ret = temp;
+                       dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+                               ADT7X10_REG_TEMP[0], ret);
+                       goto abort;
+               }
+               data->temp[0] = temp;
+               data->last_updated = jiffies;
+               data->valid = true;
+       }
+
+abort:
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static int adt7x10_fill_cache(struct device *dev)
+{
+       struct adt7x10_data *data = dev_get_drvdata(dev);
+       int ret;
+       int i;
+
+       for (i = 1; i < ARRAY_SIZE(data->temp); i++) {
+               ret = adt7x10_read_word(dev, ADT7X10_REG_TEMP[i]);
+               if (ret < 0) {
+                       dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+                               ADT7X10_REG_TEMP[i], ret);
+                       return ret;
+               }
+               data->temp[i] = ret;
+       }
+
+       ret = adt7x10_read_byte(dev, ADT7X10_T_HYST);
+       if (ret < 0) {
+               dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+                               ADT7X10_T_HYST, ret);
+               return ret;
+       }
+       data->hyst = ret;
+
+       return 0;
+}
+
+static s16 ADT7X10_TEMP_TO_REG(long temp)
+{
+       return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7X10_TEMP_MIN,
+                                              ADT7X10_TEMP_MAX) * 128, 1000);
+}
+
+static int ADT7X10_REG_TO_TEMP(struct adt7x10_data *data, s16 reg)
+{
+       /* in 13 bit mode, bits 0-2 are status flags - mask them out */
+       if (!(data->config & ADT7X10_RESOLUTION))
+               reg &= ADT7X10_T13_VALUE_MASK;
+       /*
+        * temperature is stored in twos complement format, in steps of
+        * 1/128°C
+        */
+       return DIV_ROUND_CLOSEST(reg * 1000, 128);
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* sysfs attributes for hwmon */
+
+static ssize_t adt7x10_show_temp(struct device *dev,
+                                struct device_attribute *da,
+                                char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct adt7x10_data *data = dev_get_drvdata(dev);
+
+
+       if (attr->index == 0) {
+               int ret;
+
+               ret = adt7x10_update_temp(dev);
+               if (ret)
+                       return ret;
+       }
+
+       return sprintf(buf, "%d\n", ADT7X10_REG_TO_TEMP(data,
+                      data->temp[attr->index]));
+}
+
+static ssize_t adt7x10_set_temp(struct device *dev,
+                               struct device_attribute *da,
+                               const char *buf, size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct adt7x10_data *data = dev_get_drvdata(dev);
+       int nr = attr->index;
+       long temp;
+       int ret;
+
+       ret = kstrtol(buf, 10, &temp);
+       if (ret)
+               return ret;
+
+       mutex_lock(&data->update_lock);
+       data->temp[nr] = ADT7X10_TEMP_TO_REG(temp);
+       ret = adt7x10_write_word(dev, ADT7X10_REG_TEMP[nr], data->temp[nr]);
+       if (ret)
+               count = ret;
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t adt7x10_show_t_hyst(struct device *dev,
+                                  struct device_attribute *da,
+                                  char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct adt7x10_data *data = dev_get_drvdata(dev);
+       int nr = attr->index;
+       int hyst;
+
+       hyst = (data->hyst & ADT7X10_T_HYST_MASK) * 1000;
+
+       /*
+        * hysteresis is stored as a 4 bit offset in the device, convert it
+        * to an absolute value
+        */
+       if (nr == 2)    /* min has positive offset, others have negative */
+               hyst = -hyst;
+       return sprintf(buf, "%d\n",
+                      ADT7X10_REG_TO_TEMP(data, data->temp[nr]) - hyst);
+}
+
+static ssize_t adt7x10_set_t_hyst(struct device *dev,
+                                 struct device_attribute *da,
+                                 const char *buf, size_t count)
+{
+       struct adt7x10_data *data = dev_get_drvdata(dev);
+       int limit, ret;
+       long hyst;
+
+       ret = kstrtol(buf, 10, &hyst);
+       if (ret)
+               return ret;
+       /* convert absolute hysteresis value to a 4 bit delta value */
+       limit = ADT7X10_REG_TO_TEMP(data, data->temp[1]);
+       hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX);
+       data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000),
+                                  0, ADT7X10_T_HYST_MASK);
+       ret = adt7x10_write_byte(dev, ADT7X10_T_HYST, data->hyst);
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static ssize_t adt7x10_show_alarm(struct device *dev,
+                                 struct device_attribute *da,
+                                 char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int ret;
+
+       ret = adt7x10_read_byte(dev, ADT7X10_STATUS);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d\n", !!(ret & attr->index));
+}
+
+static ssize_t adt7x10_show_name(struct device *dev,
+                                struct device_attribute *da,
+                                char *buf)
+{
+       struct adt7x10_data *data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", data->name);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7x10_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+                         adt7x10_show_temp, adt7x10_set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+                         adt7x10_show_temp, adt7x10_set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
+                         adt7x10_show_temp, adt7x10_set_temp, 3);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+                         adt7x10_show_t_hyst, adt7x10_set_t_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
+                         adt7x10_show_t_hyst, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
+                         adt7x10_show_t_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7x10_show_alarm,
+                         NULL, ADT7X10_STAT_T_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7x10_show_alarm,
+                         NULL, ADT7X10_STAT_T_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7x10_show_alarm,
+                         NULL, ADT7X10_STAT_T_CRIT);
+static DEVICE_ATTR(name, S_IRUGO, adt7x10_show_name, NULL);
+
+static struct attribute *adt7x10_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group adt7x10_group = {
+       .attrs = adt7x10_attributes,
+};
+
+int adt7x10_probe(struct device *dev, const char *name, int irq,
+                 const struct adt7x10_ops *ops)
+{
+       struct adt7x10_data *data;
+       int ret;
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->ops = ops;
+       data->name = name;
+
+       dev_set_drvdata(dev, data);
+       mutex_init(&data->update_lock);
+
+       /* configure as specified */
+       ret = adt7x10_read_byte(dev, ADT7X10_CONFIG);
+       if (ret < 0) {
+               dev_dbg(dev, "Can't read config? %d\n", ret);
+               return ret;
+       }
+       data->oldconfig = ret;
+
+       /*
+        * Set to 16 bit resolution, continous conversion and comparator mode.
+        */
+       data->config = data->oldconfig;
+       data->config &= ~(ADT7X10_MODE_MASK | ADT7X10_CT_POLARITY |
+                       ADT7X10_INT_POLARITY);
+       data->config |= ADT7X10_FULL | ADT7X10_RESOLUTION | ADT7X10_EVENT_MODE;
+
+       if (data->config != data->oldconfig) {
+               ret = adt7x10_write_byte(dev, ADT7X10_CONFIG, data->config);
+               if (ret)
+                       return ret;
+       }
+       dev_dbg(dev, "Config %02x\n", data->config);
+
+       ret = adt7x10_fill_cache(dev);
+       if (ret)
+               goto exit_restore;
+
+       /* Register sysfs hooks */
+       ret = sysfs_create_group(&dev->kobj, &adt7x10_group);
+       if (ret)
+               goto exit_restore;
+
+       /*
+        * The I2C device will already have it's own 'name' attribute, but for
+        * the SPI device we need to register it. name will only be non NULL if
+        * the device doesn't register the 'name' attribute on its own.
+        */
+       if (name) {
+               ret = device_create_file(dev, &dev_attr_name);
+               if (ret)
+                       goto exit_remove;
+       }
+
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               ret = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_name;
+       }
+
+       if (irq > 0) {
+               ret = request_threaded_irq(irq, NULL, adt7x10_irq_handler,
+                               IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                               dev_name(dev), dev);
+               if (ret)
+                       goto exit_hwmon_device_unregister;
+       }
+
+       return 0;
+
+exit_hwmon_device_unregister:
+       hwmon_device_unregister(data->hwmon_dev);
+exit_remove_name:
+       if (name)
+               device_remove_file(dev, &dev_attr_name);
+exit_remove:
+       sysfs_remove_group(&dev->kobj, &adt7x10_group);
+exit_restore:
+       adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(adt7x10_probe);
+
+int adt7x10_remove(struct device *dev, int irq)
+{
+       struct adt7x10_data *data = dev_get_drvdata(dev);
+
+       if (irq > 0)
+               free_irq(irq, dev);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       if (data->name)
+               device_remove_file(dev, &dev_attr_name);
+       sysfs_remove_group(&dev->kobj, &adt7x10_group);
+       if (data->oldconfig != data->config)
+               adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(adt7x10_remove);
+
+#ifdef CONFIG_PM_SLEEP
+
+static int adt7x10_suspend(struct device *dev)
+{
+       struct adt7x10_data *data = dev_get_drvdata(dev);
+
+       return adt7x10_write_byte(dev, ADT7X10_CONFIG,
+               data->config | ADT7X10_PD);
+}
+
+static int adt7x10_resume(struct device *dev)
+{
+       struct adt7x10_data *data = dev_get_drvdata(dev);
+
+       return adt7x10_write_byte(dev, ADT7X10_CONFIG, data->config);
+}
+
+SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops, adt7x10_suspend, adt7x10_resume);
+EXPORT_SYMBOL_GPL(adt7x10_dev_pm_ops);
+
+#endif /* CONFIG_PM_SLEEP */
+
+MODULE_AUTHOR("Hartmut Knaack");
+MODULE_DESCRIPTION("ADT7410/ADT7420, ADT7310/ADT7320 common code");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h
new file mode 100644 (file)
index 0000000..d491c69
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __HWMON_ADT7X10_H__
+#define __HWMON_ADT7X10_H__
+
+#include <linux/types.h>
+#include <linux/pm.h>
+
+/* ADT7410 registers definition */
+#define ADT7X10_TEMPERATURE            0
+#define ADT7X10_STATUS                 2
+#define ADT7X10_CONFIG                 3
+#define ADT7X10_T_ALARM_HIGH           4
+#define ADT7X10_T_ALARM_LOW            6
+#define ADT7X10_T_CRIT                 8
+#define ADT7X10_T_HYST                 0xA
+#define ADT7X10_ID                     0xB
+
+struct device;
+
+struct adt7x10_ops {
+       int (*read_byte)(struct device *, u8 reg);
+       int (*write_byte)(struct device *, u8 reg, u8 data);
+       int (*read_word)(struct device *, u8 reg);
+       int (*write_word)(struct device *, u8 reg, u16 data);
+};
+
+int adt7x10_probe(struct device *dev, const char *name, int irq,
+       const struct adt7x10_ops *ops);
+int adt7x10_remove(struct device *dev, int irq);
+
+#ifdef CONFIG_PM_SLEEP
+extern const struct dev_pm_ops adt7x10_dev_pm_ops;
+#define ADT7X10_DEV_PM_OPS (&adt7x10_dev_pm_ops)
+#else
+#define ADT7X10_DEV_PM_OPS NULL
+#endif
+
+#endif
index b41baff..62c2e32 100644 (file)
@@ -922,7 +922,7 @@ static void applesmc_brightness_set(struct led_classdev *led_cdev,
        ret = queue_work(applesmc_led_wq, &backlight_work);
 
        if (debug && (!ret))
-               printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
+               dev_dbg(led_cdev->dev, "work was already on the queue.\n");
 }
 
 static ssize_t applesmc_key_count_show(struct device *dev,
index 6ac612c..f960636 100644 (file)
@@ -55,8 +55,8 @@ static const unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
 
 static unsigned short force_subclients[4];
 module_param_array(force_subclients, short, NULL, 0);
-MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
-       "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+MODULE_PARM_DESC(force_subclients,
+       "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
 
 /* Voltage IN registers 0-6 */
 #define ASB100_REG_IN(nr)      (0x20 + (nr))
@@ -689,8 +689,8 @@ static int asb100_detect_subclients(struct i2c_client *client)
                for (i = 2; i <= 3; i++) {
                        if (force_subclients[i] < 0x48 ||
                            force_subclients[i] > 0x4f) {
-                               dev_err(&client->dev, "invalid subclient "
-                                       "address %d; must be 0x48-0x4f\n",
+                               dev_err(&client->dev,
+                                       "invalid subclient address %d; must be 0x48-0x4f\n",
                                        force_subclients[i]);
                                err = -ENODEV;
                                goto ERROR_SC_2;
@@ -708,24 +708,27 @@ static int asb100_detect_subclients(struct i2c_client *client)
        }
 
        if (sc_addr[0] == sc_addr[1]) {
-               dev_err(&client->dev, "duplicate addresses 0x%x "
-                               "for subclients\n", sc_addr[0]);
+               dev_err(&client->dev,
+                       "duplicate addresses 0x%x for subclients\n",
+                       sc_addr[0]);
                err = -ENODEV;
                goto ERROR_SC_2;
        }
 
        data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
        if (!data->lm75[0]) {
-               dev_err(&client->dev, "subclient %d registration "
-                       "at address 0x%x failed.\n", 1, sc_addr[0]);
+               dev_err(&client->dev,
+                       "subclient %d registration at address 0x%x failed.\n",
+                       1, sc_addr[0]);
                err = -ENOMEM;
                goto ERROR_SC_2;
        }
 
        data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
        if (!data->lm75[1]) {
-               dev_err(&client->dev, "subclient %d registration "
-                       "at address 0x%x failed.\n", 2, sc_addr[1]);
+               dev_err(&client->dev,
+                       "subclient %d registration at address 0x%x failed.\n",
+                       2, sc_addr[1]);
                err = -ENOMEM;
                goto ERROR_SC_3;
        }
index da7f5b5..3ad9d84 100644 (file)
@@ -159,12 +159,12 @@ static inline int write_byte(struct i2c_client *client, u8 reg, u8 data)
  * and retrieval of like parameters.
  */
 
-#define SETUP_SHOW_data_param(d, a) \
+#define SETUP_SHOW_DATA_PARAM(d, a) \
        struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
        struct asc7621_data *data = asc7621_update_device(d); \
        struct asc7621_param *param = to_asc7621_param(sda)
 
-#define SETUP_STORE_data_param(d, a) \
+#define SETUP_STORE_DATA_PARAM(d, a) \
        struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
        struct i2c_client *client = to_i2c_client(d); \
        struct asc7621_data *data = i2c_get_clientdata(client); \
@@ -177,7 +177,7 @@ static inline int write_byte(struct i2c_client *client, u8 reg, u8 data)
 static ssize_t show_u8(struct device *dev, struct device_attribute *attr,
                       char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
 
        return sprintf(buf, "%u\n", data->reg[param->msb[0]]);
 }
@@ -185,7 +185,7 @@ static ssize_t show_u8(struct device *dev, struct device_attribute *attr,
 static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       SETUP_STORE_data_param(dev, attr);
+       SETUP_STORE_DATA_PARAM(dev, attr);
        long reqval;
 
        if (kstrtol(buf, 10, &reqval))
@@ -206,7 +206,7 @@ static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
 static ssize_t show_bitmask(struct device *dev,
                            struct device_attribute *attr, char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
 
        return sprintf(buf, "%u\n",
                       (data->reg[param->msb[0]] >> param->
@@ -217,7 +217,7 @@ static ssize_t store_bitmask(struct device *dev,
                             struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       SETUP_STORE_data_param(dev, attr);
+       SETUP_STORE_DATA_PARAM(dev, attr);
        long reqval;
        u8 currval;
 
@@ -246,7 +246,7 @@ static ssize_t store_bitmask(struct device *dev,
 static ssize_t show_fan16(struct device *dev,
                          struct device_attribute *attr, char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
        u16 regval;
 
        mutex_lock(&data->update_lock);
@@ -262,7 +262,7 @@ static ssize_t store_fan16(struct device *dev,
                           struct device_attribute *attr, const char *buf,
                           size_t count)
 {
-       SETUP_STORE_data_param(dev, attr);
+       SETUP_STORE_DATA_PARAM(dev, attr);
        long reqval;
 
        if (kstrtol(buf, 10, &reqval))
@@ -307,7 +307,7 @@ static int asc7621_in_scaling[] = {
 static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
                         char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
        u16 regval;
        u8 nr = sda->index;
 
@@ -325,7 +325,7 @@ static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
 static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
                        char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
        u8 nr = sda->index;
 
        return sprintf(buf, "%u\n",
@@ -336,7 +336,7 @@ static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
 static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
                         const char *buf, size_t count)
 {
-       SETUP_STORE_data_param(dev, attr);
+       SETUP_STORE_DATA_PARAM(dev, attr);
        long reqval;
        u8 nr = sda->index;
 
@@ -360,7 +360,7 @@ static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
 static ssize_t show_temp8(struct device *dev,
                          struct device_attribute *attr, char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
 
        return sprintf(buf, "%d\n", ((s8) data->reg[param->msb[0]]) * 1000);
 }
@@ -369,7 +369,7 @@ static ssize_t store_temp8(struct device *dev,
                           struct device_attribute *attr, const char *buf,
                           size_t count)
 {
-       SETUP_STORE_data_param(dev, attr);
+       SETUP_STORE_DATA_PARAM(dev, attr);
        long reqval;
        s8 temp;
 
@@ -397,7 +397,7 @@ static ssize_t store_temp8(struct device *dev,
 static ssize_t show_temp10(struct device *dev,
                           struct device_attribute *attr, char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
        u8 msb, lsb;
        int temp;
 
@@ -414,7 +414,7 @@ static ssize_t show_temp10(struct device *dev,
 static ssize_t show_temp62(struct device *dev,
                           struct device_attribute *attr, char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
        u8 regval = data->reg[param->msb[0]];
        int temp = ((s8) (regval & 0xfc) * 1000) + ((regval & 0x03) * 250);
 
@@ -425,7 +425,7 @@ static ssize_t store_temp62(struct device *dev,
                            struct device_attribute *attr, const char *buf,
                            size_t count)
 {
-       SETUP_STORE_data_param(dev, attr);
+       SETUP_STORE_DATA_PARAM(dev, attr);
        long reqval, i, f;
        s8 temp;
 
@@ -459,7 +459,7 @@ static u32 asc7621_range_map[] = {
 static ssize_t show_ap2_temp(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
        long auto_point1;
        u8 regval;
        int temp;
@@ -479,7 +479,7 @@ static ssize_t store_ap2_temp(struct device *dev,
                              struct device_attribute *attr,
                              const char *buf, size_t count)
 {
-       SETUP_STORE_data_param(dev, attr);
+       SETUP_STORE_DATA_PARAM(dev, attr);
        long reqval, auto_point1;
        int i;
        u8 currval, newval = 0;
@@ -510,7 +510,7 @@ static ssize_t store_ap2_temp(struct device *dev,
 static ssize_t show_pwm_ac(struct device *dev,
                           struct device_attribute *attr, char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
        u8 config, altbit, regval;
        u8 map[] = {
                0x01, 0x02, 0x04, 0x1f, 0x00, 0x06, 0x07, 0x10,
@@ -530,7 +530,7 @@ static ssize_t store_pwm_ac(struct device *dev,
                            struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       SETUP_STORE_data_param(dev, attr);
+       SETUP_STORE_DATA_PARAM(dev, attr);
        unsigned long reqval;
        u8 currval, config, altbit, newval;
        u16 map[] = {
@@ -569,7 +569,7 @@ static ssize_t store_pwm_ac(struct device *dev,
 static ssize_t show_pwm_enable(struct device *dev,
                               struct device_attribute *attr, char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
        u8 config, altbit, minoff, val, newval;
 
        mutex_lock(&data->update_lock);
@@ -599,7 +599,7 @@ static ssize_t store_pwm_enable(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t count)
 {
-       SETUP_STORE_data_param(dev, attr);
+       SETUP_STORE_DATA_PARAM(dev, attr);
        long reqval;
        u8 currval, config, altbit, newval, minoff = 255;
 
@@ -659,7 +659,7 @@ static u32 asc7621_pwm_freq_map[] = {
 static ssize_t show_pwm_freq(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
        u8 regval =
            (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
 
@@ -672,7 +672,7 @@ static ssize_t store_pwm_freq(struct device *dev,
                              struct device_attribute *attr,
                              const char *buf, size_t count)
 {
-       SETUP_STORE_data_param(dev, attr);
+       SETUP_STORE_DATA_PARAM(dev, attr);
        unsigned long reqval;
        u8 currval, newval = 255;
        int i;
@@ -707,7 +707,7 @@ static u32 asc7621_pwm_auto_spinup_map[] =  {
 static ssize_t show_pwm_ast(struct device *dev,
                            struct device_attribute *attr, char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
        u8 regval =
            (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
 
@@ -721,7 +721,7 @@ static ssize_t store_pwm_ast(struct device *dev,
                             struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       SETUP_STORE_data_param(dev, attr);
+       SETUP_STORE_DATA_PARAM(dev, attr);
        long reqval;
        u8 currval, newval = 255;
        u32 i;
@@ -756,7 +756,7 @@ static u32 asc7621_temp_smoothing_time_map[] = {
 static ssize_t show_temp_st(struct device *dev,
                            struct device_attribute *attr, char *buf)
 {
-       SETUP_SHOW_data_param(dev, attr);
+       SETUP_SHOW_DATA_PARAM(dev, attr);
        u8 regval =
            (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
        regval = clamp_val(regval, 0, 7);
@@ -768,7 +768,7 @@ static ssize_t store_temp_st(struct device *dev,
                             struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       SETUP_STORE_data_param(dev, attr);
+       SETUP_STORE_DATA_PARAM(dev, attr);
        long reqval;
        u8 currval, newval = 255;
        u32 i;
index 3f1e297..658ce3a 100644 (file)
@@ -411,8 +411,7 @@ static int __cpuinit chk_ucode_version(unsigned int cpu)
         * fixed for stepping D0 (6EC).
         */
        if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) {
-               pr_err("Errata AE18 not fixed, update BIOS or "
-                      "microcode of the CPU!\n");
+               pr_err("Errata AE18 not fixed, update BIOS or microcode of the CPU!\n");
                return -ENODEV;
        }
        return 0;
index ab4452c..960fac3 100644 (file)
@@ -43,19 +43,19 @@ static const char * const input_names[] = {
 };
 
 /* Conversion function for VDDOUT and VBAT */
-static inline int volt_reg_to_mV(int value)
+static inline int volt_reg_to_mv(int value)
 {
        return DIV_ROUND_CLOSEST(value * 1000, 512) + 2500;
 }
 
 /* Conversion function for ADC channels 4, 5 and 6 */
-static inline int input_reg_to_mV(int value)
+static inline int input_reg_to_mv(int value)
 {
        return DIV_ROUND_CLOSEST(value * 2500, 1023);
 }
 
 /* Conversion function for VBBAT */
-static inline int vbbat_reg_to_mV(int value)
+static inline int vbbat_reg_to_mv(int value)
 {
        return DIV_ROUND_CLOSEST(value * 2500, 512);
 }
@@ -96,7 +96,7 @@ static ssize_t da9052_read_vddout(struct device *dev,
                goto hwmon_err;
 
        mutex_unlock(&hwmon->hwmon_lock);
-       return sprintf(buf, "%d\n", volt_reg_to_mV(vdd));
+       return sprintf(buf, "%d\n", volt_reg_to_mv(vdd));
 
 hwmon_err_release:
        da9052_disable_vddout_channel(hwmon->da9052);
@@ -137,7 +137,7 @@ static ssize_t da9052_read_vbat(struct device *dev,
        if (ret < 0)
                return ret;
 
-       return sprintf(buf, "%d\n", volt_reg_to_mV(ret));
+       return sprintf(buf, "%d\n", volt_reg_to_mv(ret));
 }
 
 static ssize_t da9052_read_misc_channel(struct device *dev,
@@ -152,7 +152,7 @@ static ssize_t da9052_read_misc_channel(struct device *dev,
        if (ret < 0)
                return ret;
 
-       return sprintf(buf, "%d\n", input_reg_to_mV(ret));
+       return sprintf(buf, "%d\n", input_reg_to_mv(ret));
 }
 
 static ssize_t da9052_read_tjunc(struct device *dev,
@@ -187,7 +187,7 @@ static ssize_t da9052_read_vbbat(struct device *dev,
        if (ret < 0)
                return ret;
 
-       return sprintf(buf, "%d\n", vbbat_reg_to_mV(ret));
+       return sprintf(buf, "%d\n", vbbat_reg_to_mv(ret));
 }
 
 static ssize_t da9052_hwmon_show_name(struct device *dev,
index 9465c05..029ecab 100644 (file)
@@ -119,7 +119,7 @@ static irqreturn_t da9055_auxadc_irq(int irq, void *irq_data)
 }
 
 /* Conversion function for VSYS and ADCINx */
-static inline int volt_reg_to_mV(int value, int channel)
+static inline int volt_reg_to_mv(int value, int channel)
 {
        if (channel == DA9055_ADC_VSYS)
                return DIV_ROUND_CLOSEST(value * 1000, DA9055_VSYS_DIV) + 2500;
@@ -168,7 +168,7 @@ static ssize_t da9055_read_auto_ch(struct device *dev,
 
        mutex_unlock(&hwmon->hwmon_lock);
 
-       return sprintf(buf, "%d\n", volt_reg_to_mV(adc, channel));
+       return sprintf(buf, "%d\n", volt_reg_to_mv(adc, channel));
 
 hwmon_err_release:
        da9055_disable_auto_mode(hwmon->da9055, channel);
index c347c94..4ae3fff 100644 (file)
@@ -55,14 +55,16 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
 
 static bool probe_all_addr;
 module_param(probe_all_addr, bool, 0);
-MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC "
-                "addresses");
+MODULE_PARM_DESC(probe_all_addr,
+                "Include probing of non-standard LPC addresses");
 
 /* Addresses to scan */
 static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
 
 enum chips { dme1737, sch5027, sch311x, sch5127 };
 
+#define        DO_REPORT "Please report to the driver maintainer."
+
 /* ---------------------------------------------------------------------
  * Registers
  *
@@ -566,9 +568,9 @@ static u8 dme1737_read(const struct dme1737_data *data, u8 reg)
                val = i2c_smbus_read_byte_data(client, reg);
 
                if (val < 0) {
-                       dev_warn(&client->dev, "Read from register "
-                                "0x%02x failed! Please report to the driver "
-                                "maintainer.\n", reg);
+                       dev_warn(&client->dev,
+                                "Read from register 0x%02x failed! %s\n",
+                                reg, DO_REPORT);
                }
        } else { /* ISA device */
                outb(reg, data->addr);
@@ -587,9 +589,9 @@ static s32 dme1737_write(const struct dme1737_data *data, u8 reg, u8 val)
                res = i2c_smbus_write_byte_data(client, reg, val);
 
                if (res < 0) {
-                       dev_warn(&client->dev, "Write to register "
-                                "0x%02x failed! Please report to the driver "
-                                "maintainer.\n", reg);
+                       dev_warn(&client->dev,
+                                "Write to register 0x%02x failed! %s\n",
+                                reg, DO_REPORT);
                }
        } else { /* ISA device */
                outb(reg, data->addr);
@@ -1167,8 +1169,8 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
                /* Only valid for fan[1-4] */
                if (!(val == 1 || val == 2 || val == 4)) {
                        count = -EINVAL;
-                       dev_warn(dev, "Fan type value %ld not "
-                                "supported. Choose one of 1, 2, or 4.\n",
+                       dev_warn(dev,
+                                "Fan type value %ld not supported. Choose one of 1, 2, or 4.\n",
                                 val);
                        goto exit;
                }
@@ -1294,8 +1296,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                /* Only valid for pwm[1-3] */
                if (val < 0 || val > 2) {
                        count = -EINVAL;
-                       dev_warn(dev, "PWM enable %ld not "
-                                "supported. Choose one of 0, 1, or 2.\n",
+                       dev_warn(dev,
+                                "PWM enable %ld not supported. Choose one of 0, 1, or 2.\n",
                                 val);
                        goto exit;
                }
@@ -1399,8 +1401,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                if (!(val == 1 || val == 2 || val == 4 ||
                      val == 6 || val == 7)) {
                        count = -EINVAL;
-                       dev_warn(dev, "PWM auto channels zone %ld "
-                                "not supported. Choose one of 1, 2, 4, 6, "
+                       dev_warn(dev,
+                                "PWM auto channels zone %ld not supported. Choose one of 1, 2, 4, 6, "
                                 "or 7.\n", val);
                        goto exit;
                }
@@ -2178,8 +2180,8 @@ static int dme1737_create_files(struct device *dev)
         * selected attributes from read-only to read-writeable.
         */
        if (data->config & 0x02) {
-               dev_info(dev, "Device is locked. Some attributes "
-                        "will be read-only.\n");
+               dev_info(dev,
+                        "Device is locked. Some attributes will be read-only.\n");
        } else {
                /* Change permissions of zone sysfs attributes */
                dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
@@ -2247,9 +2249,8 @@ static int dme1737_init_device(struct device *dev)
        /* Inform if part is not monitoring/started */
        if (!(data->config & 0x01)) {
                if (!force_start) {
-                       dev_err(dev, "Device is not monitoring. "
-                               "Use the force_start load parameter to "
-                               "override.\n");
+                       dev_err(dev,
+                               "Device is not monitoring. Use the force_start load parameter to override.\n");
                        return -EFAULT;
                }
 
@@ -2289,8 +2290,8 @@ static int dme1737_init_device(struct device *dev)
                 */
                if (dme1737_i2c_get_features(0x2e, data) &&
                    dme1737_i2c_get_features(0x4e, data)) {
-                       dev_warn(dev, "Failed to query Super-IO for optional "
-                                "features.\n");
+                       dev_warn(dev,
+                                "Failed to query Super-IO for optional features.\n");
                }
        }
 
@@ -2317,8 +2318,8 @@ static int dme1737_init_device(struct device *dev)
                break;
        }
 
-       dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
-                "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
+       dev_info(dev,
+                "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
                 (data->has_features & HAS_PWM(2)) ? "yes" : "no",
                 (data->has_features & HAS_PWM(4)) ? "yes" : "no",
                 (data->has_features & HAS_PWM(5)) ? "yes" : "no",
@@ -2330,18 +2331,16 @@ static int dme1737_init_device(struct device *dev)
        reg = dme1737_read(data, DME1737_REG_TACH_PWM);
        /* Inform if fan-to-pwm mapping differs from the default */
        if (client && reg != 0xa4) {   /* I2C chip */
-               dev_warn(dev, "Non-standard fan to pwm mapping: "
-                        "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
-                        "fan4->pwm%d. Please report to the driver "
-                        "maintainer.\n",
+               dev_warn(dev,
+                        "Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, fan4->pwm%d. %s\n",
                         (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
-                        ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
+                        ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1,
+                        DO_REPORT);
        } else if (!client && reg != 0x24) {   /* ISA chip */
-               dev_warn(dev, "Non-standard fan to pwm mapping: "
-                        "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. "
-                        "Please report to the driver maintainer.\n",
+               dev_warn(dev,
+                        "Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. %s\n",
                         (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
-                        ((reg >> 4) & 0x03) + 1);
+                        ((reg >> 4) & 0x03) + 1, DO_REPORT);
        }
 
        /*
@@ -2355,8 +2354,9 @@ static int dme1737_init_device(struct device *dev)
                                                DME1737_REG_PWM_CONFIG(ix));
                        if ((data->has_features & HAS_PWM(ix)) &&
                            (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
-                               dev_info(dev, "Switching pwm%d to "
-                                        "manual mode.\n", ix + 1);
+                               dev_info(dev,
+                                        "Switching pwm%d to manual mode.\n",
+                                        ix + 1);
                                data->pwm_config[ix] = PWM_EN_TO_REG(1,
                                                        data->pwm_config[ix]);
                                dme1737_write(data, DME1737_REG_PWM(ix), 0);
index a981697..0c9f3da 100644 (file)
@@ -1350,8 +1350,7 @@ static void f71805f_init_device(struct f71805f_data *data)
 
        reg = f71805f_read8(data, F71805F_REG_START);
        if ((reg & 0x41) != 0x01) {
-               printk(KERN_DEBUG DRVNAME ": Starting monitoring "
-                      "operations\n");
+               pr_debug("Starting monitoring operations\n");
                f71805f_write8(data, F71805F_REG_START, (reg | 0x01) & ~0x40);
        }
 
index b757088..dff8410 100644 (file)
@@ -189,8 +189,8 @@ static void fam15h_power_init_data(struct pci_dev *f4,
 
        /* result not allowed to be >= 256W */
        if ((tmp >> 16) >= 256)
-               dev_warn(&f4->dev, "Bogus value for ProcessorPwrWatts "
-                        "(processor_pwr_watts>=%u)\n",
+               dev_warn(&f4->dev,
+                        "Bogus value for ProcessorPwrWatts (processor_pwr_watts>=%u)\n",
                         (unsigned int) (tmp >> 16));
 
        /* convert to microWatt */
index 8af2755..d58abdc 100644 (file)
@@ -463,8 +463,9 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute
                v = 3;
                break;
        default:
-               dev_err(dev, "fan_div value %lu not supported. "
-                       "Choose one of 2, 4 or 8!\n", v);
+               dev_err(dev,
+                       "fan_div value %lu not supported. Choose one of 2, 4 or 8!\n",
+                       v);
                return -EINVAL;
        }
 
@@ -1249,8 +1250,8 @@ static int fschmd_probe(struct i2c_client *client,
        }
        if (i == ARRAY_SIZE(watchdog_minors)) {
                data->watchdog_miscdev.minor = 0;
-               dev_warn(&client->dev, "Couldn't register watchdog chardev "
-                       "(due to no free minor)\n");
+               dev_warn(&client->dev,
+                        "Couldn't register watchdog chardev (due to no free minor)\n");
        }
        mutex_unlock(&watchdog_data_mutex);
 
index e2e5909..95257a5 100644 (file)
@@ -344,8 +344,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
                val = 3;
                break;
        default:
-               dev_err(dev, "Invalid fan clock divider %lu, choose one "
-                       "of 1, 2, 4 or 8\n", val);
+               dev_err(dev,
+                       "Invalid fan clock divider %lu, choose one of 1, 2, 4 or 8\n",
+                       val);
                return -EINVAL;
        }
 
index 3978194..3104149 100644 (file)
@@ -105,10 +105,6 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data,
        if (err)
                return err;
 
-       err = device_create_file(&pdev->dev, &dev_attr_fan1_alarm);
-       if (err)
-               return err;
-
        /*
         * If the alarm GPIO don't support interrupts, just leave
         * without initializing the fail notification support.
@@ -121,23 +117,9 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data,
        irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
        err = devm_request_irq(&pdev->dev, alarm_irq, fan_alarm_irq_handler,
                               IRQF_SHARED, "GPIO fan alarm", fan_data);
-       if (err)
-               goto err_free_sysfs;
-
-       return 0;
-
-err_free_sysfs:
-       device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
        return err;
 }
 
-static void fan_alarm_free(struct gpio_fan_data *fan_data)
-{
-       struct platform_device *pdev = fan_data->pdev;
-
-       device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
-}
-
 /*
  * Control GPIOs.
  */
@@ -327,6 +309,12 @@ exit_unlock:
        return ret;
 }
 
+static ssize_t show_name(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "gpio-fan\n");
+}
+
 static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm);
 static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
                   show_pwm_enable, set_pwm_enable);
@@ -336,8 +324,26 @@ static DEVICE_ATTR(fan1_max, S_IRUGO, show_rpm_max, NULL);
 static DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, NULL);
 static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_rpm, set_rpm);
 
-static struct attribute *gpio_fan_ctrl_attributes[] = {
-       &dev_attr_pwm1.attr,
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static umode_t gpio_fan_is_visible(struct kobject *kobj,
+                                  struct attribute *attr, int index)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct gpio_fan_data *data = dev_get_drvdata(dev);
+
+       if (index == 1 && !data->alarm)
+               return 0;
+       if (index > 1 && !data->ctrl)
+               return 0;
+
+       return attr->mode;
+}
+
+static struct attribute *gpio_fan_attributes[] = {
+       &dev_attr_name.attr,
+       &dev_attr_fan1_alarm.attr,              /* 1 */
+       &dev_attr_pwm1.attr,                    /* 2 */
        &dev_attr_pwm1_enable.attr,
        &dev_attr_pwm1_mode.attr,
        &dev_attr_fan1_input.attr,
@@ -347,8 +353,9 @@ static struct attribute *gpio_fan_ctrl_attributes[] = {
        NULL
 };
 
-static const struct attribute_group gpio_fan_ctrl_group = {
-       .attrs = gpio_fan_ctrl_attributes,
+static const struct attribute_group gpio_fan_group = {
+       .attrs = gpio_fan_attributes,
+       .is_visible = gpio_fan_is_visible,
 };
 
 static int fan_ctrl_init(struct gpio_fan_data *fan_data,
@@ -379,30 +386,9 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
        if (fan_data->speed_index < 0)
                return -ENODEV;
 
-       err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
-       return err;
-}
-
-static void fan_ctrl_free(struct gpio_fan_data *fan_data)
-{
-       struct platform_device *pdev = fan_data->pdev;
-
-       sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
-}
-
-/*
- * Platform driver.
- */
-
-static ssize_t show_name(struct device *dev,
-                        struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "gpio-fan\n");
+       return 0;
 }
 
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-
-
 #ifdef CONFIG_OF_GPIO
 /*
  * Translate OpenFirmware node properties into platform_data
@@ -546,38 +532,30 @@ static int gpio_fan_probe(struct platform_device *pdev)
 
        /* Configure control GPIOs if available. */
        if (pdata->ctrl && pdata->num_ctrl > 0) {
-               if (!pdata->speed || pdata->num_speed <= 1) {
-                       err = -EINVAL;
-                       goto err_free_alarm;
-               }
+               if (!pdata->speed || pdata->num_speed <= 1)
+                       return -EINVAL;
                err = fan_ctrl_init(fan_data, pdata);
                if (err)
-                       goto err_free_alarm;
+                       return err;
        }
 
-       err = device_create_file(&pdev->dev, &dev_attr_name);
+       err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_group);
        if (err)
-               goto err_free_ctrl;
+               return err;
 
        /* Make this driver part of hwmon class. */
        fan_data->hwmon_dev = hwmon_device_register(&pdev->dev);
        if (IS_ERR(fan_data->hwmon_dev)) {
                err = PTR_ERR(fan_data->hwmon_dev);
-               goto err_remove_name;
+               goto err_remove;
        }
 
        dev_info(&pdev->dev, "GPIO fan initialized\n");
 
        return 0;
 
-err_remove_name:
-       device_remove_file(&pdev->dev, &dev_attr_name);
-err_free_ctrl:
-       if (fan_data->ctrl)
-               fan_ctrl_free(fan_data);
-err_free_alarm:
-       if (fan_data->alarm)
-               fan_alarm_free(fan_data);
+err_remove:
+       sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_group);
        return err;
 }
 
@@ -586,11 +564,7 @@ static int gpio_fan_remove(struct platform_device *pdev)
        struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
 
        hwmon_device_unregister(fan_data->hwmon_dev);
-       device_remove_file(&pdev->dev, &dev_attr_name);
-       if (fan_data->alarm)
-               fan_alarm_free(fan_data);
-       if (fan_data->ctrl)
-               fan_ctrl_free(fan_data);
+       sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_group);
 
        return 0;
 }
@@ -619,7 +593,7 @@ static int gpio_fan_resume(struct device *dev)
 }
 
 static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
-#define GPIO_FAN_PM    &gpio_fan_pm
+#define GPIO_FAN_PM    (&gpio_fan_pm)
 #else
 #define GPIO_FAN_PM    NULL
 #endif
index a14f634..1429f6e 100644 (file)
@@ -289,8 +289,9 @@ static int aem_init_ipmi_data(struct aem_ipmi_data *data, int iface,
        err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
                               data, &data->user);
        if (err < 0) {
-               dev_err(bmc, "Unable to register user with IPMI "
-                       "interface %d\n", data->interface);
+               dev_err(bmc,
+                       "Unable to register user with IPMI interface %d\n",
+                       data->interface);
                return -EACCES;
        }
 
@@ -328,8 +329,8 @@ static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
        struct aem_ipmi_data *data = user_msg_data;
 
        if (msg->msgid != data->tx_msgid) {
-               dev_err(data->bmc_device, "Mismatch between received msgid "
-                       "(%02x) and transmitted msgid (%02x)!\n",
+               dev_err(data->bmc_device,
+                       "Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n",
                        (int)msg->msgid,
                        (int)data->tx_msgid);
                ipmi_free_recv_msg(msg);
@@ -575,8 +576,8 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle)
        /* Register with hwmon */
        data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
        if (IS_ERR(data->hwmon_dev)) {
-               dev_err(&data->pdev->dev, "Unable to register hwmon "
-                       "device for IPMI interface %d\n",
+               dev_err(&data->pdev->dev,
+                       "Unable to register hwmon device for IPMI interface %d\n",
                        probe->interface);
                res = PTR_ERR(data->hwmon_dev);
                goto hwmon_reg_err;
@@ -715,8 +716,8 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe,
        /* Register with hwmon */
        data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
        if (IS_ERR(data->hwmon_dev)) {
-               dev_err(&data->pdev->dev, "Unable to register hwmon "
-                       "device for IPMI interface %d\n",
+               dev_err(&data->pdev->dev,
+                       "Unable to register hwmon device for IPMI interface %d\n",
                        probe->interface);
                res = PTR_ERR(data->hwmon_dev);
                goto hwmon_reg_err;
@@ -768,8 +769,8 @@ static void aem_init_aem2(struct aem_ipmi_data *probe)
 
        while (!aem_find_aem2(probe, &fi_resp, i)) {
                if (fi_resp.major != 2) {
-                       dev_err(probe->bmc_device, "Unknown AEM v%d; please "
-                               "report this to the maintainer.\n",
+                       dev_err(probe->bmc_device,
+                               "Unknown AEM v%d; please report this to the maintainer.\n",
                                fi_resp.major);
                        i++;
                        continue;
index b622a93..74b365e 100644 (file)
@@ -163,8 +163,8 @@ static int ibmpex_ver_check(struct ibmpex_bmc_data *data)
        data->sensor_major = data->rx_msg_data[0];
        data->sensor_minor = data->rx_msg_data[1];
 
-       dev_info(data->bmc_device, "Found BMC with sensor interface "
-                "v%d.%d %d-%02d-%02d on interface %d\n",
+       dev_info(data->bmc_device,
+                "Found BMC with sensor interface v%d.%d %d-%02d-%02d on interface %d\n",
                 data->sensor_major,
                 data->sensor_minor,
                 extract_value(data->rx_msg_data, 2),
@@ -478,8 +478,9 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
        err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
                               data, &data->user);
        if (err < 0) {
-               dev_err(dev, "Unable to register user with IPMI "
-                       "interface %d\n", data->interface);
+               dev_err(dev,
+                       "Unable to register user with IPMI interface %d\n",
+                       data->interface);
                goto out;
        }
 
@@ -501,8 +502,8 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
        data->hwmon_dev = hwmon_device_register(data->bmc_device);
 
        if (IS_ERR(data->hwmon_dev)) {
-               dev_err(data->bmc_device, "Unable to register hwmon "
-                       "device for IPMI interface %d\n",
+               dev_err(data->bmc_device,
+                       "Unable to register hwmon device for IPMI interface %d\n",
                        data->interface);
                goto out_user;
        }
@@ -567,8 +568,8 @@ static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
        struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
 
        if (msg->msgid != data->tx_msgid) {
-               dev_err(data->bmc_device, "Mismatch between received msgid "
-                       "(%02x) and transmitted msgid (%02x)!\n",
+               dev_err(data->bmc_device,
+                       "Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n",
                        (int)msg->msgid,
                        (int)data->tx_msgid);
                ipmi_free_recv_msg(msg);
index 8e7158c..4958b2f 100644 (file)
@@ -186,20 +186,20 @@ static ssize_t ina2xx_show_value(struct device *dev,
 }
 
 /* shunt voltage */
-static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \
-       ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE);
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
+                         INA2XX_SHUNT_VOLTAGE);
 
 /* bus voltage */
-static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
-       ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina2xx_show_value, NULL,
+                         INA2XX_BUS_VOLTAGE);
 
 /* calculated current */
-static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
-       ina2xx_show_value, NULL, INA2XX_CURRENT);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina2xx_show_value, NULL,
+                         INA2XX_CURRENT);
 
 /* calculated power */
-static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \
-       ina2xx_show_value, NULL, INA2XX_POWER);
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL,
+                         INA2XX_POWER);
 
 /* pointers to created device attributes */
 static struct attribute *ina2xx_attributes[] = {
index 37fc980..72b21d5 100644 (file)
@@ -1778,7 +1778,7 @@ static int __init it87_find(unsigned short *address,
                superio_select(5);
                sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
        } else if (sio_data->type == it8783) {
-               int reg25, reg27, reg2A, reg2C, regEF;
+               int reg25, reg27, reg2a, reg2c, regef;
 
                sio_data->skip_vid = 1; /* No VID */
 
@@ -1786,15 +1786,15 @@ static int __init it87_find(unsigned short *address,
 
                reg25 = superio_inb(IT87_SIO_GPIO1_REG);
                reg27 = superio_inb(IT87_SIO_GPIO3_REG);
-               reg2A = superio_inb(IT87_SIO_PINX1_REG);
-               reg2C = superio_inb(IT87_SIO_PINX2_REG);
-               regEF = superio_inb(IT87_SIO_SPI_REG);
+               reg2a = superio_inb(IT87_SIO_PINX1_REG);
+               reg2c = superio_inb(IT87_SIO_PINX2_REG);
+               regef = superio_inb(IT87_SIO_SPI_REG);
 
                /* Check if fan3 is there or not */
-               if ((reg27 & (1 << 0)) || !(reg2C & (1 << 2)))
+               if ((reg27 & (1 << 0)) || !(reg2c & (1 << 2)))
                        sio_data->skip_fan |= (1 << 2);
                if ((reg25 & (1 << 4))
-                   || (!(reg2A & (1 << 1)) && (regEF & (1 << 0))))
+                   || (!(reg2a & (1 << 1)) && (regef & (1 << 0))))
                        sio_data->skip_pwm |= (1 << 2);
 
                /* Check if fan2 is there or not */
@@ -1804,7 +1804,7 @@ static int __init it87_find(unsigned short *address,
                        sio_data->skip_pwm |= (1 << 1);
 
                /* VIN5 */
-               if ((reg27 & (1 << 0)) || (reg2C & (1 << 2)))
+               if ((reg27 & (1 << 0)) || (reg2c & (1 << 2)))
                        sio_data->skip_in |= (1 << 5); /* No VIN5 */
 
                /* VIN6 */
@@ -1829,18 +1829,18 @@ static int __init it87_find(unsigned short *address,
                         * not the case, and ask the user to report if the
                         * resulting voltage is sane.
                         */
-                       if (!(reg2C & (1 << 1))) {
-                               reg2C |= (1 << 1);
-                               superio_outb(IT87_SIO_PINX2_REG, reg2C);
+                       if (!(reg2c & (1 << 1))) {
+                               reg2c |= (1 << 1);
+                               superio_outb(IT87_SIO_PINX2_REG, reg2c);
                                pr_notice("Routing internal VCCH5V to in7.\n");
                        }
                        pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
                        pr_notice("Please report if it displays a reasonable voltage.\n");
                }
 
-               if (reg2C & (1 << 0))
+               if (reg2c & (1 << 0))
                        sio_data->internal |= (1 << 0);
-               if (reg2C & (1 << 1))
+               if (reg2c & (1 << 1))
                        sio_data->internal |= (1 << 1);
 
                sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
index 9f3c0ae..5b50e9e 100644 (file)
@@ -200,8 +200,8 @@ static int k8temp_probe(struct pci_dev *pdev,
         */
        if (model >= 0x40) {
                data->swap_core_select = 1;
-               dev_warn(&pdev->dev, "Temperature readouts might be wrong - "
-                        "check erratum #141\n");
+               dev_warn(&pdev->dev,
+                        "Temperature readouts might be wrong - check erratum #141\n");
        }
 
        /*
index 483538f..6cf6bff 100644 (file)
@@ -386,8 +386,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
                data->fan_div[nr] = 3;
                break;
        default:
-               dev_err(dev, "fan_div value %ld not "
-                       "supported. Choose one of 1, 2, 4 or 8!\n", val);
+               dev_err(dev,
+                       "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
+                       val);
                mutex_unlock(&data->update_lock);
                return -EINVAL;
        }
@@ -636,8 +637,9 @@ static int lm78_i2c_detect(struct i2c_client *client,
                goto err_nodev;
 
        if (lm78_alias_detect(client, i)) {
-               dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
-                       "be the same as ISA device\n", address);
+               dev_dbg(&adapter->dev,
+                       "Device at 0x%02x appears to be the same as ISA device\n",
+                       address);
                goto err_nodev;
        }
 
index 357fbb9..eba89aa 100644 (file)
@@ -286,8 +286,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
                data->fan_div[nr] = 3;
                break;
        default:
-               dev_err(&client->dev, "fan_div value %ld not "
-                       "supported. Choose one of 1, 2, 4 or 8!\n", val);
+               dev_err(&client->dev,
+                       "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
+                       val);
                mutex_unlock(&data->update_lock);
                return -EINVAL;
        }
index 47ade8b..3894c40 100644 (file)
@@ -1293,8 +1293,8 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
        company = lm85_read_value(client, LM85_REG_COMPANY);
        verstep = lm85_read_value(client, LM85_REG_VERSTEP);
 
-       dev_dbg(&adapter->dev, "Detecting device at 0x%02x with "
-               "COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
+       dev_dbg(&adapter->dev,
+               "Detecting device at 0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
                address, company, verstep);
 
        /* All supported chips have the version in common */
index b40f34c..a6f4605 100644 (file)
@@ -354,12 +354,12 @@ static const unsigned long lm93_vin_val_max[16] = {
 
 static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
 {
-       const long uV_max = lm93_vin_val_max[nr] * 1000;
-       const long uV_min = lm93_vin_val_min[nr] * 1000;
+       const long uv_max = lm93_vin_val_max[nr] * 1000;
+       const long uv_min = lm93_vin_val_min[nr] * 1000;
 
-       const long slope = (uV_max - uV_min) /
+       const long slope = (uv_max - uv_min) /
                (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
-       const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
+       const long intercept = uv_min - slope * lm93_vin_reg_min[nr];
 
        return (slope * reg + intercept + 500) / 1000;
 }
@@ -371,20 +371,20 @@ static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
 static u8 LM93_IN_TO_REG(int nr, unsigned val)
 {
        /* range limit */
-       const long mV = clamp_val(val,
+       const long mv = clamp_val(val,
                                  lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
 
        /* try not to lose too much precision here */
-       const long uV = mV * 1000;
-       const long uV_max = lm93_vin_val_max[nr] * 1000;
-       const long uV_min = lm93_vin_val_min[nr] * 1000;
+       const long uv = mv * 1000;
+       const long uv_max = lm93_vin_val_max[nr] * 1000;
+       const long uv_min = lm93_vin_val_min[nr] * 1000;
 
        /* convert */
-       const long slope = (uV_max - uV_min) /
+       const long slope = (uv_max - uv_min) /
                (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
-       const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
+       const long intercept = uv_min - slope * lm93_vin_reg_min[nr];
 
-       u8 result = ((uV - intercept + (slope/2)) / slope);
+       u8 result = ((uv - intercept + (slope/2)) / slope);
        result = clamp_val(result,
                           lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
        return result;
@@ -393,10 +393,10 @@ static u8 LM93_IN_TO_REG(int nr, unsigned val)
 /* vid in mV, upper == 0 indicates low limit, otherwise upper limit */
 static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
 {
-       const long uV_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
+       const long uv_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
                                (((reg >> 0 & 0x0f) + 1) * -25000);
-       const long uV_vid = vid * 1000;
-       return (uV_vid + uV_offset + 5000) / 10000;
+       const long uv_vid = vid * 1000;
+       return (uv_vid + uv_offset + 5000) / 10000;
 }
 
 #define LM93_IN_MIN_FROM_REG(reg, vid) LM93_IN_REL_FROM_REG((reg), 0, (vid))
@@ -409,13 +409,13 @@ static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
  */
 static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
 {
-       long uV_offset = vid * 1000 - val * 10000;
+       long uv_offset = vid * 1000 - val * 10000;
        if (upper) {
-               uV_offset = clamp_val(uV_offset, 12500, 200000);
-               return (u8)((uV_offset /  12500 - 1) << 4);
+               uv_offset = clamp_val(uv_offset, 12500, 200000);
+               return (u8)((uv_offset /  12500 - 1) << 4);
        } else {
-               uV_offset = clamp_val(uV_offset, -400000, -25000);
-               return (u8)((uV_offset / -25000 - 1) << 0);
+               uv_offset = clamp_val(uv_offset, -400000, -25000);
+               return (u8)((uv_offset / -25000 - 1) << 0);
        }
 }
 
@@ -818,8 +818,9 @@ static u8 lm93_read_byte(struct i2c_client *client, u8 reg)
                if (value >= 0) {
                        return value;
                } else {
-                       dev_warn(&client->dev, "lm93: read byte data failed, "
-                               "address 0x%02x.\n", reg);
+                       dev_warn(&client->dev,
+                                "lm93: read byte data failed, address 0x%02x.\n",
+                                reg);
                        mdelay(i + 3);
                }
 
@@ -838,8 +839,9 @@ static int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value)
        result = i2c_smbus_write_byte_data(client, reg, value);
 
        if (result < 0)
-               dev_warn(&client->dev, "lm93: write byte data failed, "
-                        "0x%02x at address 0x%02x.\n", value, reg);
+               dev_warn(&client->dev,
+                        "lm93: write byte data failed, 0x%02x at address 0x%02x.\n",
+                        value, reg);
 
        return result;
 }
@@ -854,8 +856,9 @@ static u16 lm93_read_word(struct i2c_client *client, u8 reg)
                if (value >= 0) {
                        return value;
                } else {
-                       dev_warn(&client->dev, "lm93: read word data failed, "
-                                "address 0x%02x.\n", reg);
+                       dev_warn(&client->dev,
+                                "lm93: read word data failed, address 0x%02x.\n",
+                                reg);
                        mdelay(i + 3);
                }
 
@@ -874,8 +877,9 @@ static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value)
        result = i2c_smbus_write_word_data(client, reg, value);
 
        if (result < 0)
-               dev_warn(&client->dev, "lm93: write word data failed, "
-                        "0x%04x at address 0x%02x.\n", value, reg);
+               dev_warn(&client->dev,
+                        "lm93: write word data failed, 0x%04x at address 0x%02x.\n",
+                        value, reg);
 
        return result;
 }
@@ -898,8 +902,8 @@ static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values)
                if (result == lm93_block_read_cmds[fbn].len) {
                        break;
                } else {
-                       dev_warn(&client->dev, "lm93: block read data failed, "
-                                "command 0x%02x.\n",
+                       dev_warn(&client->dev,
+                                "lm93: block read data failed, command 0x%02x.\n",
                                 lm93_block_read_cmds[fbn].cmd);
                        mdelay(i + 3);
                }
@@ -2672,8 +2676,8 @@ static void lm93_init_client(struct i2c_client *client)
                        return;
        }
 
-       dev_warn(&client->dev, "timed out waiting for sensor "
-                "chip to signal ready!\n");
+       dev_warn(&client->dev,
+                "timed out waiting for sensor chip to signal ready!\n");
 }
 
 /* Return 0 if detection is successful, -ENODEV otherwise */
@@ -2733,12 +2737,12 @@ static int lm93_probe(struct i2c_client *client,
                dev_dbg(&client->dev, "using SMBus block data transactions\n");
                update = lm93_update_client_full;
        } else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
-               dev_dbg(&client->dev, "disabled SMBus block data "
-                       "transactions\n");
+               dev_dbg(&client->dev,
+                       "disabled SMBus block data transactions\n");
                update = lm93_update_client_min;
        } else {
-               dev_dbg(&client->dev, "detect failed, "
-                       "smbus byte and/or word data not supported!\n");
+               dev_dbg(&client->dev,
+                       "detect failed, smbus byte and/or word data not supported!\n");
                return -ENODEV;
        }
 
diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c
new file mode 100644 (file)
index 0000000..307c9ea
--- /dev/null
@@ -0,0 +1,769 @@
+/*
+ * Driver for Texas Instruments / National Semiconductor LM95234
+ *
+ * Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net>
+ *
+ * Derived from lm95241.c
+ * Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+#define DRVNAME "lm95234"
+
+static const unsigned short normal_i2c[] = { 0x18, 0x4d, 0x4e, I2C_CLIENT_END };
+
+/* LM95234 registers */
+#define LM95234_REG_MAN_ID             0xFE
+#define LM95234_REG_CHIP_ID            0xFF
+#define LM95234_REG_STATUS             0x02
+#define LM95234_REG_CONFIG             0x03
+#define LM95234_REG_CONVRATE           0x04
+#define LM95234_REG_STS_FAULT          0x07
+#define LM95234_REG_STS_TCRIT1         0x08
+#define LM95234_REG_STS_TCRIT2         0x09
+#define LM95234_REG_TEMPH(x)           ((x) + 0x10)
+#define LM95234_REG_TEMPL(x)           ((x) + 0x20)
+#define LM95234_REG_UTEMPH(x)          ((x) + 0x19)    /* Remote only */
+#define LM95234_REG_UTEMPL(x)          ((x) + 0x29)
+#define LM95234_REG_REM_MODEL          0x30
+#define LM95234_REG_REM_MODEL_STS      0x38
+#define LM95234_REG_OFFSET(x)          ((x) + 0x31)    /* Remote only */
+#define LM95234_REG_TCRIT1(x)          ((x) + 0x40)
+#define LM95234_REG_TCRIT2(x)          ((x) + 0x49)    /* Remote channel 1,2 */
+#define LM95234_REG_TCRIT_HYST         0x5a
+
+#define NATSEMI_MAN_ID                 0x01
+#define LM95234_CHIP_ID                        0x79
+
+/* Client data (each client gets its own) */
+struct lm95234_data {
+       struct device *hwmon_dev;
+       struct mutex update_lock;
+       unsigned long last_updated, interval;   /* in jiffies */
+       bool valid;             /* false until following fields are valid */
+       /* registers values */
+       int temp[5];            /* temperature (signed) */
+       u32 status;             /* fault/alarm status */
+       u8 tcrit1[5];           /* critical temperature limit */
+       u8 tcrit2[2];           /* high temperature limit */
+       s8 toffset[4];          /* remote temperature offset */
+       u8 thyst;               /* common hysteresis */
+
+       u8 sensor_type;         /* temperature sensor type */
+};
+
+static int lm95234_read_temp(struct i2c_client *client, int index, int *t)
+{
+       int val;
+       u16 temp = 0;
+
+       if (index) {
+               val = i2c_smbus_read_byte_data(client,
+                                              LM95234_REG_UTEMPH(index - 1));
+               if (val < 0)
+                       return val;
+               temp = val << 8;
+               val = i2c_smbus_read_byte_data(client,
+                                              LM95234_REG_UTEMPL(index - 1));
+               if (val < 0)
+                       return val;
+               temp |= val;
+               *t = temp;
+       }
+       /*
+        * Read signed temperature if unsigned temperature is 0,
+        * or if this is the local sensor.
+        */
+       if (!temp) {
+               val = i2c_smbus_read_byte_data(client,
+                                              LM95234_REG_TEMPH(index));
+               if (val < 0)
+                       return val;
+               temp = val << 8;
+               val = i2c_smbus_read_byte_data(client,
+                                              LM95234_REG_TEMPL(index));
+               if (val < 0)
+                       return val;
+               temp |= val;
+               *t = (s16)temp;
+       }
+       return 0;
+}
+
+static u16 update_intervals[] = { 143, 364, 1000, 2500 };
+
+/* Fill value cache. Must be called with update lock held. */
+
+static int lm95234_fill_cache(struct i2c_client *client)
+{
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       int i, ret;
+
+       ret = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
+       if (ret < 0)
+               return ret;
+
+       data->interval = msecs_to_jiffies(update_intervals[ret & 0x03]);
+
+       for (i = 0; i < ARRAY_SIZE(data->tcrit1); i++) {
+               ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT1(i));
+               if (ret < 0)
+                       return ret;
+               data->tcrit1[i] = ret;
+       }
+       for (i = 0; i < ARRAY_SIZE(data->tcrit2); i++) {
+               ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT2(i));
+               if (ret < 0)
+                       return ret;
+               data->tcrit2[i] = ret;
+       }
+       for (i = 0; i < ARRAY_SIZE(data->toffset); i++) {
+               ret = i2c_smbus_read_byte_data(client, LM95234_REG_OFFSET(i));
+               if (ret < 0)
+                       return ret;
+               data->toffset[i] = ret;
+       }
+
+       ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT_HYST);
+       if (ret < 0)
+               return ret;
+       data->thyst = ret;
+
+       ret = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
+       if (ret < 0)
+               return ret;
+       data->sensor_type = ret;
+
+       return 0;
+}
+
+static int lm95234_update_device(struct i2c_client *client,
+                                struct lm95234_data *data)
+{
+       int ret;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + data->interval) ||
+           !data->valid) {
+               int i;
+
+               if (!data->valid) {
+                       ret = lm95234_fill_cache(client);
+                       if (ret < 0)
+                               goto abort;
+               }
+
+               data->valid = false;
+               for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+                       ret = lm95234_read_temp(client, i, &data->temp[i]);
+                       if (ret < 0)
+                               goto abort;
+               }
+
+               ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_FAULT);
+               if (ret < 0)
+                       goto abort;
+               data->status = ret;
+
+               ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT1);
+               if (ret < 0)
+                       goto abort;
+               data->status |= ret << 8;
+
+               ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT2);
+               if (ret < 0)
+                       goto abort;
+               data->status |= ret << 16;
+
+               data->last_updated = jiffies;
+               data->valid = true;
+       }
+       ret = 0;
+abort:
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       int index = to_sensor_dev_attr(attr)->index;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%d\n",
+                      DIV_ROUND_CLOSEST(data->temp[index] * 125, 32));
+}
+
+static ssize_t show_alarm(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       u32 mask = to_sensor_dev_attr(attr)->index;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u", !!(data->status & mask));
+}
+
+static ssize_t show_type(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       u8 mask = to_sensor_dev_attr(attr)->index;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       return sprintf(buf, data->sensor_type & mask ? "1\n" : "2\n");
+}
+
+static ssize_t set_type(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+       u8 mask = to_sensor_dev_attr(attr)->index;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       ret = kstrtoul(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       if (val != 1 && val != 2)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       if (val == 1)
+               data->sensor_type |= mask;
+       else
+               data->sensor_type &= ~mask;
+       data->valid = false;
+       i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL,
+                                 data->sensor_type);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_tcrit2(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       int index = to_sensor_dev_attr(attr)->index;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u", data->tcrit2[index] * 1000);
+}
+
+static ssize_t set_tcrit2(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       int index = to_sensor_dev_attr(attr)->index;
+       long val;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, index ? 255 : 127);
+
+       mutex_lock(&data->update_lock);
+       data->tcrit2[index] = val;
+       i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT2(index), val);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_tcrit2_hyst(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       int index = to_sensor_dev_attr(attr)->index;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       /* Result can be negative, so be careful with unsigned operands */
+       return sprintf(buf, "%d",
+                      ((int)data->tcrit2[index] - (int)data->thyst) * 1000);
+}
+
+static ssize_t show_tcrit1(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       int index = to_sensor_dev_attr(attr)->index;
+
+       return sprintf(buf, "%u", data->tcrit1[index] * 1000);
+}
+
+static ssize_t set_tcrit1(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       int index = to_sensor_dev_attr(attr)->index;
+       long val;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
+
+       mutex_lock(&data->update_lock);
+       data->tcrit1[index] = val;
+       i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT1(index), val);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_tcrit1_hyst(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       int index = to_sensor_dev_attr(attr)->index;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       /* Result can be negative, so be careful with unsigned operands */
+       return sprintf(buf, "%d",
+                      ((int)data->tcrit1[index] - (int)data->thyst) * 1000);
+}
+
+static ssize_t set_tcrit1_hyst(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       int index = to_sensor_dev_attr(attr)->index;
+       long val;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       val = DIV_ROUND_CLOSEST(val, 1000);
+       val = clamp_val((int)data->tcrit1[index] - val, 0, 31);
+
+       mutex_lock(&data->update_lock);
+       data->thyst = val;
+       i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT_HYST, val);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_offset(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       int index = to_sensor_dev_attr(attr)->index;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%d", data->toffset[index] * 500);
+}
+
+static ssize_t set_offset(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       int index = to_sensor_dev_attr(attr)->index;
+       long val;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       /* Accuracy is 1/2 degrees C */
+       val = clamp_val(DIV_ROUND_CLOSEST(val, 500), -128, 127);
+
+       mutex_lock(&data->update_lock);
+       data->toffset[index] = val;
+       i2c_smbus_write_byte_data(client, LM95234_REG_OFFSET(index), val);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%lu\n",
+                      DIV_ROUND_CLOSEST(data->interval * 1000, HZ));
+}
+
+static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95234_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+       u8 regval;
+       int ret = lm95234_update_device(client, data);
+
+       if (ret)
+               return ret;
+
+       ret = kstrtoul(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       for (regval = 0; regval < 3; regval++) {
+               if (val <= update_intervals[regval])
+                       break;
+       }
+
+       mutex_lock(&data->update_lock);
+       data->interval = msecs_to_jiffies(update_intervals[regval]);
+       i2c_smbus_write_byte_data(client, LM95234_REG_CONVRATE, regval);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL,
+                         BIT(0) | BIT(1));
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL,
+                         BIT(2) | BIT(3));
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL,
+                         BIT(4) | BIT(5));
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_alarm, NULL,
+                         BIT(6) | BIT(7));
+
+static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type,
+                         BIT(1));
+static SENSOR_DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type, set_type,
+                         BIT(2));
+static SENSOR_DEVICE_ATTR(temp4_type, S_IWUSR | S_IRUGO, show_type, set_type,
+                         BIT(3));
+static SENSOR_DEVICE_ATTR(temp5_type, S_IWUSR | S_IRUGO, show_type, set_type,
+                         BIT(4));
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_tcrit1,
+                         set_tcrit1, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_tcrit2,
+                         set_tcrit2, 0);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_tcrit2,
+                         set_tcrit2, 1);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_tcrit1,
+                         set_tcrit1, 3);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_tcrit1,
+                         set_tcrit1, 4);
+
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_tcrit1_hyst,
+                         set_tcrit1_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO, show_tcrit2_hyst, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO, show_tcrit2_hyst, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_max_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 4);
+
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+                         BIT(0 + 8));
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL,
+                         BIT(1 + 16));
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL,
+                         BIT(2 + 16));
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL,
+                         BIT(3 + 8));
+static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL,
+                         BIT(4 + 8));
+
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_tcrit1,
+                         set_tcrit1, 1);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_tcrit1,
+                         set_tcrit1, 2);
+
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 2);
+
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
+                         BIT(1 + 8));
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL,
+                         BIT(2 + 8));
+
+static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_offset,
+                         set_offset, 0);
+static SENSOR_DEVICE_ATTR(temp3_offset, S_IWUSR | S_IRUGO, show_offset,
+                         set_offset, 1);
+static SENSOR_DEVICE_ATTR(temp4_offset, S_IWUSR | S_IRUGO, show_offset,
+                         set_offset, 2);
+static SENSOR_DEVICE_ATTR(temp5_offset, S_IWUSR | S_IRUGO, show_offset,
+                         set_offset, 3);
+
+static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
+                  set_interval);
+
+static struct attribute *lm95234_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp4_input.dev_attr.attr,
+       &sensor_dev_attr_temp5_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
+       &sensor_dev_attr_temp4_fault.dev_attr.attr,
+       &sensor_dev_attr_temp5_fault.dev_attr.attr,
+       &sensor_dev_attr_temp2_type.dev_attr.attr,
+       &sensor_dev_attr_temp3_type.dev_attr.attr,
+       &sensor_dev_attr_temp4_type.dev_attr.attr,
+       &sensor_dev_attr_temp5_type.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp4_max.dev_attr.attr,
+       &sensor_dev_attr_temp5_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_offset.dev_attr.attr,
+       &sensor_dev_attr_temp3_offset.dev_attr.attr,
+       &sensor_dev_attr_temp4_offset.dev_attr.attr,
+       &sensor_dev_attr_temp5_offset.dev_attr.attr,
+       &dev_attr_update_interval.attr,
+       NULL
+};
+
+static const struct attribute_group lm95234_group = {
+       .attrs = lm95234_attributes,
+};
+
+static int lm95234_detect(struct i2c_client *client,
+                         struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       int mfg_id, chip_id, val;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       mfg_id = i2c_smbus_read_byte_data(client, LM95234_REG_MAN_ID);
+       if (mfg_id != NATSEMI_MAN_ID)
+               return -ENODEV;
+
+       chip_id = i2c_smbus_read_byte_data(client, LM95234_REG_CHIP_ID);
+       if (chip_id != LM95234_CHIP_ID)
+               return -ENODEV;
+
+       val = i2c_smbus_read_byte_data(client, LM95234_REG_STATUS);
+       if (val & 0x30)
+               return -ENODEV;
+
+       val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
+       if (val & 0xbc)
+               return -ENODEV;
+
+       val = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
+       if (val & 0xfc)
+               return -ENODEV;
+
+       val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
+       if (val & 0xe1)
+               return -ENODEV;
+
+       val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
+       if (val & 0xe1)
+               return -ENODEV;
+
+       strlcpy(info->type, "lm95234", I2C_NAME_SIZE);
+       return 0;
+}
+
+static int lm95234_init_client(struct i2c_client *client)
+{
+       int val, model;
+
+       /* start conversion if necessary */
+       val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
+       if (val < 0)
+               return val;
+       if (val & 0x40)
+               i2c_smbus_write_byte_data(client, LM95234_REG_CONFIG,
+                                         val & ~0x40);
+
+       /* If diode type status reports an error, try to fix it */
+       val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
+       if (val < 0)
+               return val;
+       model = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
+       if (model < 0)
+               return model;
+       if (model & val) {
+               dev_notice(&client->dev,
+                          "Fixing remote diode type misconfiguration (0x%x)\n",
+                          val);
+               i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL,
+                                         model & ~val);
+       }
+       return 0;
+}
+
+static int lm95234_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct lm95234_data *data;
+       int err;
+
+       data = devm_kzalloc(dev, sizeof(struct lm95234_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       /* Initialize the LM95234 chip */
+       err = lm95234_init_client(client);
+       if (err < 0)
+               return err;
+
+       /* Register sysfs hooks */
+       err = sysfs_create_group(&dev->kobj, &lm95234_group);
+       if (err)
+               return err;
+
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_files;
+       }
+
+       return 0;
+
+exit_remove_files:
+       sysfs_remove_group(&dev->kobj, &lm95234_group);
+       return err;
+}
+
+static int lm95234_remove(struct i2c_client *client)
+{
+       struct lm95234_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &lm95234_group);
+
+       return 0;
+}
+
+/* Driver data (common to all clients) */
+static const struct i2c_device_id lm95234_id[] = {
+       { "lm95234", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lm95234_id);
+
+static struct i2c_driver lm95234_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = DRVNAME,
+       },
+       .probe          = lm95234_probe,
+       .remove         = lm95234_remove,
+       .id_table       = lm95234_id,
+       .detect         = lm95234_detect,
+       .address_list   = normal_i2c,
+};
+
+module_i2c_driver(lm95234_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LM95234 sensor driver");
+MODULE_LICENSE("GPL");
index 4319a94..af81be1 100644 (file)
@@ -146,14 +146,14 @@ static ssize_t ltc4151_show_value(struct device *dev,
 /*
  * Input voltages.
  */
-static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
-       ltc4151_show_value, NULL, LTC4151_VIN_H);
-static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, \
-       ltc4151_show_value, NULL, LTC4151_ADIN_H);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4151_show_value, NULL,
+                         LTC4151_VIN_H);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4151_show_value, NULL,
+                         LTC4151_ADIN_H);
 
 /* Currents (via sense resistor) */
-static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
-       ltc4151_show_value, NULL, LTC4151_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4151_show_value, NULL,
+                         LTC4151_SENSE_H);
 
 /*
  * Finally, construct an array of pointers to members of the above objects,
index e887610..8a14296 100644 (file)
@@ -172,12 +172,12 @@ static ssize_t ltc4215_show_alarm(struct device *dev,
                                          struct device_attribute *da,
                                          char *buf)
 {
-       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
        struct ltc4215_data *data = ltc4215_update_device(dev);
-       const u8 reg = data->regs[attr->index];
-       const u32 mask = attr->nr;
+       const u8 reg = data->regs[LTC4215_STATUS];
+       const u32 mask = attr->index;
 
-       return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0);
+       return snprintf(buf, PAGE_SIZE, "%u\n", !!(reg & mask));
 }
 
 /*
@@ -186,39 +186,29 @@ static ssize_t ltc4215_show_alarm(struct device *dev,
  * for each register.
  */
 
-#define LTC4215_VOLTAGE(name, ltc4215_cmd_idx) \
-       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
-       ltc4215_show_voltage, NULL, ltc4215_cmd_idx)
-
-#define LTC4215_CURRENT(name) \
-       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
-       ltc4215_show_current, NULL, 0);
-
-#define LTC4215_POWER(name) \
-       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
-       ltc4215_show_power, NULL, 0);
-
-#define LTC4215_ALARM(name, mask, reg) \
-       static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \
-       ltc4215_show_alarm, NULL, (mask), reg)
-
 /* Construct a sensor_device_attribute structure for each register */
 
 /* Current */
-LTC4215_CURRENT(curr1_input);
-LTC4215_ALARM(curr1_max_alarm, (1 << 2),       LTC4215_STATUS);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4215_show_current, NULL, 0);
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
+                         1 << 2);
 
 /* Power (virtual) */
-LTC4215_POWER(power1_input);
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc4215_show_power, NULL, 0);
 
 /* Input Voltage */
-LTC4215_VOLTAGE(in1_input,                     LTC4215_ADIN);
-LTC4215_ALARM(in1_max_alarm,   (1 << 0),       LTC4215_STATUS);
-LTC4215_ALARM(in1_min_alarm,   (1 << 1),       LTC4215_STATUS);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4215_show_voltage, NULL,
+                         LTC4215_ADIN);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
+                         1 << 0);
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
+                         1 << 1);
 
 /* Output Voltage */
-LTC4215_VOLTAGE(in2_input,                     LTC4215_SOURCE);
-LTC4215_ALARM(in2_min_alarm,   (1 << 3),       LTC4215_STATUS);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4215_show_voltage, NULL,
+                         LTC4215_SOURCE);
+static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
+                         1 << 3);
 
 /*
  * Finally, construct an array of pointers to members of the above objects,
index 3653f79..cdc1ecc 100644 (file)
@@ -319,80 +319,82 @@ static ssize_t ltc4245_show_gpio(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%u\n", val * 10);
 }
 
-/*
- * These macros are used below in constructing device attribute objects
- * for use with sysfs_create_group() to make a sysfs device file
- * for each register.
- */
-
-#define LTC4245_VOLTAGE(name, ltc4245_cmd_idx) \
-       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
-       ltc4245_show_voltage, NULL, ltc4245_cmd_idx)
-
-#define LTC4245_CURRENT(name, ltc4245_cmd_idx) \
-       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
-       ltc4245_show_current, NULL, ltc4245_cmd_idx)
-
-#define LTC4245_POWER(name, ltc4245_cmd_idx) \
-       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
-       ltc4245_show_power, NULL, ltc4245_cmd_idx)
-
-#define LTC4245_ALARM(name, mask, reg) \
-       static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \
-       ltc4245_show_alarm, NULL, (mask), reg)
-
-#define LTC4245_GPIO_VOLTAGE(name, gpio_num) \
-       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
-       ltc4245_show_gpio, NULL, gpio_num)
-
 /* Construct a sensor_device_attribute structure for each register */
 
 /* Input voltages */
-LTC4245_VOLTAGE(in1_input,                     LTC4245_12VIN);
-LTC4245_VOLTAGE(in2_input,                     LTC4245_5VIN);
-LTC4245_VOLTAGE(in3_input,                     LTC4245_3VIN);
-LTC4245_VOLTAGE(in4_input,                     LTC4245_VEEIN);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4245_show_voltage, NULL,
+                         LTC4245_12VIN);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4245_show_voltage, NULL,
+                         LTC4245_5VIN);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4245_show_voltage, NULL,
+                         LTC4245_3VIN);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4245_show_voltage, NULL,
+                         LTC4245_VEEIN);
 
 /* Input undervoltage alarms */
-LTC4245_ALARM(in1_min_alarm,   (1 << 0),       LTC4245_FAULT1);
-LTC4245_ALARM(in2_min_alarm,   (1 << 1),       LTC4245_FAULT1);
-LTC4245_ALARM(in3_min_alarm,   (1 << 2),       LTC4245_FAULT1);
-LTC4245_ALARM(in4_min_alarm,   (1 << 3),       LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+                           1 << 0, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(in2_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+                           1 << 1, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+                           1 << 2, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(in4_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+                           1 << 3, LTC4245_FAULT1);
 
 /* Currents (via sense resistor) */
-LTC4245_CURRENT(curr1_input,                   LTC4245_12VSENSE);
-LTC4245_CURRENT(curr2_input,                   LTC4245_5VSENSE);
-LTC4245_CURRENT(curr3_input,                   LTC4245_3VSENSE);
-LTC4245_CURRENT(curr4_input,                   LTC4245_VEESENSE);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4245_show_current, NULL,
+                         LTC4245_12VSENSE);
+static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4245_show_current, NULL,
+                         LTC4245_5VSENSE);
+static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO, ltc4245_show_current, NULL,
+                         LTC4245_3VSENSE);
+static SENSOR_DEVICE_ATTR(curr4_input, S_IRUGO, ltc4245_show_current, NULL,
+                         LTC4245_VEESENSE);
 
 /* Overcurrent alarms */
-LTC4245_ALARM(curr1_max_alarm, (1 << 4),       LTC4245_FAULT1);
-LTC4245_ALARM(curr2_max_alarm, (1 << 5),       LTC4245_FAULT1);
-LTC4245_ALARM(curr3_max_alarm, (1 << 6),       LTC4245_FAULT1);
-LTC4245_ALARM(curr4_max_alarm, (1 << 7),       LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+                           1 << 4, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+                           1 << 5, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(curr3_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+                           1 << 6, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(curr4_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+                           1 << 7, LTC4245_FAULT1);
 
 /* Output voltages */
-LTC4245_VOLTAGE(in5_input,                     LTC4245_12VOUT);
-LTC4245_VOLTAGE(in6_input,                     LTC4245_5VOUT);
-LTC4245_VOLTAGE(in7_input,                     LTC4245_3VOUT);
-LTC4245_VOLTAGE(in8_input,                     LTC4245_VEEOUT);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ltc4245_show_voltage, NULL,
+                         LTC4245_12VOUT);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ltc4245_show_voltage, NULL,
+                         LTC4245_5VOUT);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ltc4245_show_voltage, NULL,
+                         LTC4245_3VOUT);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, ltc4245_show_voltage, NULL,
+                         LTC4245_VEEOUT);
 
 /* Power Bad alarms */
-LTC4245_ALARM(in5_min_alarm,   (1 << 0),       LTC4245_FAULT2);
-LTC4245_ALARM(in6_min_alarm,   (1 << 1),       LTC4245_FAULT2);
-LTC4245_ALARM(in7_min_alarm,   (1 << 2),       LTC4245_FAULT2);
-LTC4245_ALARM(in8_min_alarm,   (1 << 3),       LTC4245_FAULT2);
+static SENSOR_DEVICE_ATTR_2(in5_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+                           1 << 0, LTC4245_FAULT2);
+static SENSOR_DEVICE_ATTR_2(in6_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+                           1 << 1, LTC4245_FAULT2);
+static SENSOR_DEVICE_ATTR_2(in7_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+                           1 << 2, LTC4245_FAULT2);
+static SENSOR_DEVICE_ATTR_2(in8_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+                           1 << 3, LTC4245_FAULT2);
 
 /* GPIO voltages */
-LTC4245_GPIO_VOLTAGE(in9_input,                        0);
-LTC4245_GPIO_VOLTAGE(in10_input,               1);
-LTC4245_GPIO_VOLTAGE(in11_input,               2);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, ltc4245_show_gpio, NULL, 0);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, ltc4245_show_gpio, NULL, 1);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, ltc4245_show_gpio, NULL, 2);
 
 /* Power Consumption (virtual) */
-LTC4245_POWER(power1_input,                    LTC4245_12VSENSE);
-LTC4245_POWER(power2_input,                    LTC4245_5VSENSE);
-LTC4245_POWER(power3_input,                    LTC4245_3VSENSE);
-LTC4245_POWER(power4_input,                    LTC4245_VEESENSE);
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc4245_show_power, NULL,
+                         LTC4245_12VSENSE);
+static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, ltc4245_show_power, NULL,
+                         LTC4245_5VSENSE);
+static SENSOR_DEVICE_ATTR(power3_input, S_IRUGO, ltc4245_show_power, NULL,
+                         LTC4245_3VSENSE);
+static SENSOR_DEVICE_ATTR(power4_input, S_IRUGO, ltc4245_show_power, NULL,
+                         LTC4245_VEESENSE);
 
 /*
  * Finally, construct an array of pointers to members of the above objects,
index 84a2d28..487da58 100644 (file)
@@ -165,24 +165,12 @@ static ssize_t ltc4261_show_bool(struct device *dev,
 }
 
 /*
- * These macros are used below in constructing device attribute objects
- * for use with sysfs_create_group() to make a sysfs device file
- * for each register.
- */
-
-#define LTC4261_VALUE(name, ltc4261_cmd_idx) \
-       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
-       ltc4261_show_value, NULL, ltc4261_cmd_idx)
-
-#define LTC4261_BOOL(name, mask) \
-       static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
-       ltc4261_show_bool, NULL, (mask))
-
-/*
  * Input voltages.
  */
-LTC4261_VALUE(in1_input, LTC4261_ADIN_H);
-LTC4261_VALUE(in2_input, LTC4261_ADIN2_H);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4261_show_value, NULL,
+                         LTC4261_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4261_show_value, NULL,
+                         LTC4261_ADIN2_H);
 
 /*
  * Voltage alarms. The chip has only one set of voltage alarm status bits,
@@ -192,16 +180,22 @@ LTC4261_VALUE(in2_input, LTC4261_ADIN2_H);
  * To ensure that the alarm condition is reported to the user, report it
  * with both voltage sensors.
  */
-LTC4261_BOOL(in1_min_alarm, FAULT_UV);
-LTC4261_BOOL(in1_max_alarm, FAULT_OV);
-LTC4261_BOOL(in2_min_alarm, FAULT_UV);
-LTC4261_BOOL(in2_max_alarm, FAULT_OV);
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+                         FAULT_UV);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+                         FAULT_OV);
+static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+                         FAULT_UV);
+static SENSOR_DEVICE_ATTR(in2_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+                         FAULT_OV);
 
 /* Currents (via sense resistor) */
-LTC4261_VALUE(curr1_input, LTC4261_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4261_show_value, NULL,
+                         LTC4261_SENSE_H);
 
 /* Overcurrent alarm */
-LTC4261_BOOL(curr1_max_alarm, FAULT_OC);
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+                         FAULT_OC);
 
 static struct attribute *ltc4261_attributes[] = {
        &sensor_dev_attr_in1_input.dev_attr.attr,
index bf4aa37..328fb03 100644 (file)
@@ -399,82 +399,95 @@ static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_alarm, NULL, 5);
 static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_alarm, NULL, 6);
 static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_alarm, NULL, 7);
 
-static struct attribute *max6697_attributes[8][7] = {
-       {
-               &sensor_dev_attr_temp1_input.dev_attr.attr,
-               &sensor_dev_attr_temp1_max.dev_attr.attr,
-               &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp1_crit.dev_attr.attr,
-               &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
-               NULL
-       }, {
-               &sensor_dev_attr_temp2_input.dev_attr.attr,
-               &sensor_dev_attr_temp2_max.dev_attr.attr,
-               &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp2_crit.dev_attr.attr,
-               &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp2_fault.dev_attr.attr,
-               NULL
-       }, {
-               &sensor_dev_attr_temp3_input.dev_attr.attr,
-               &sensor_dev_attr_temp3_max.dev_attr.attr,
-               &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp3_crit.dev_attr.attr,
-               &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp3_fault.dev_attr.attr,
-               NULL
-       }, {
-               &sensor_dev_attr_temp4_input.dev_attr.attr,
-               &sensor_dev_attr_temp4_max.dev_attr.attr,
-               &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp4_crit.dev_attr.attr,
-               &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp4_fault.dev_attr.attr,
-               NULL
-       }, {
-               &sensor_dev_attr_temp5_input.dev_attr.attr,
-               &sensor_dev_attr_temp5_max.dev_attr.attr,
-               &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp5_crit.dev_attr.attr,
-               &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp5_fault.dev_attr.attr,
-               NULL
-       }, {
-               &sensor_dev_attr_temp6_input.dev_attr.attr,
-               &sensor_dev_attr_temp6_max.dev_attr.attr,
-               &sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp6_crit.dev_attr.attr,
-               &sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp6_fault.dev_attr.attr,
-               NULL
-       }, {
-               &sensor_dev_attr_temp7_input.dev_attr.attr,
-               &sensor_dev_attr_temp7_max.dev_attr.attr,
-               &sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp7_crit.dev_attr.attr,
-               &sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp7_fault.dev_attr.attr,
-               NULL
-       }, {
-               &sensor_dev_attr_temp8_input.dev_attr.attr,
-               &sensor_dev_attr_temp8_max.dev_attr.attr,
-               &sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp8_crit.dev_attr.attr,
-               &sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
-               &sensor_dev_attr_temp8_fault.dev_attr.attr,
-               NULL
-       }
+static DEVICE_ATTR(dummy, 0, NULL, NULL);
+
+static umode_t max6697_is_visible(struct kobject *kobj, struct attribute *attr,
+                                 int index)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct max6697_data *data = i2c_get_clientdata(client);
+       const struct max6697_chip_data *chip = data->chip;
+       int channel = index / 6;        /* channel number */
+       int nr = index % 6;             /* attribute index within channel */
+
+       if (channel >= chip->channels)
+               return 0;
+
+       if ((nr == 3 || nr == 4) && !(chip->have_crit & (1 << channel)))
+               return 0;
+       if (nr == 5 && !(chip->have_fault & (1 << channel)))
+               return 0;
+
+       return attr->mode;
+}
+
+/*
+ * max6697_is_visible uses the index into the following array to determine
+ * if attributes should be created or not. Any change in order or content
+ * must be matched in max6697_is_visible.
+ */
+static struct attribute *max6697_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+       &dev_attr_dummy.attr,
+
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
+
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
+
+       &sensor_dev_attr_temp4_input.dev_attr.attr,
+       &sensor_dev_attr_temp4_max.dev_attr.attr,
+       &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp4_crit.dev_attr.attr,
+       &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp4_fault.dev_attr.attr,
+
+       &sensor_dev_attr_temp5_input.dev_attr.attr,
+       &sensor_dev_attr_temp5_max.dev_attr.attr,
+       &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp5_crit.dev_attr.attr,
+       &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp5_fault.dev_attr.attr,
+
+       &sensor_dev_attr_temp6_input.dev_attr.attr,
+       &sensor_dev_attr_temp6_max.dev_attr.attr,
+       &sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp6_crit.dev_attr.attr,
+       &sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp6_fault.dev_attr.attr,
+
+       &sensor_dev_attr_temp7_input.dev_attr.attr,
+       &sensor_dev_attr_temp7_max.dev_attr.attr,
+       &sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp7_crit.dev_attr.attr,
+       &sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp7_fault.dev_attr.attr,
+
+       &sensor_dev_attr_temp8_input.dev_attr.attr,
+       &sensor_dev_attr_temp8_max.dev_attr.attr,
+       &sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp8_crit.dev_attr.attr,
+       &sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp8_fault.dev_attr.attr,
+       NULL
 };
 
-static const struct attribute_group max6697_group[8] = {
-       { .attrs = max6697_attributes[0] },
-       { .attrs = max6697_attributes[1] },
-       { .attrs = max6697_attributes[2] },
-       { .attrs = max6697_attributes[3] },
-       { .attrs = max6697_attributes[4] },
-       { .attrs = max6697_attributes[5] },
-       { .attrs = max6697_attributes[6] },
-       { .attrs = max6697_attributes[7] },
+static const struct attribute_group max6697_group = {
+       .attrs = max6697_attributes, .is_visible = max6697_is_visible,
 };
 
 static void max6697_get_config_of(struct device_node *node,
@@ -606,21 +619,13 @@ done:
        return 0;
 }
 
-static void max6697_remove_files(struct i2c_client *client)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(max6697_group); i++)
-               sysfs_remove_group(&client->dev.kobj, &max6697_group[i]);
-}
-
 static int max6697_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
        struct i2c_adapter *adapter = client->adapter;
        struct device *dev = &client->dev;
        struct max6697_data *data;
-       int i, err;
+       int err;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
@@ -639,37 +644,9 @@ static int max6697_probe(struct i2c_client *client,
        if (err)
                return err;
 
-       for (i = 0; i < data->chip->channels; i++) {
-               err = sysfs_create_file(&dev->kobj,
-                                       max6697_attributes[i][0]);
-               if (err)
-                       goto error;
-               err = sysfs_create_file(&dev->kobj,
-                                       max6697_attributes[i][1]);
-               if (err)
-                       goto error;
-               err = sysfs_create_file(&dev->kobj,
-                                       max6697_attributes[i][2]);
-               if (err)
-                       goto error;
-
-               if (data->chip->have_crit & (1 << i)) {
-                       err = sysfs_create_file(&dev->kobj,
-                                               max6697_attributes[i][3]);
-                       if (err)
-                               goto error;
-                       err = sysfs_create_file(&dev->kobj,
-                                               max6697_attributes[i][4]);
-                       if (err)
-                               goto error;
-               }
-               if (data->chip->have_fault & (1 << i)) {
-                       err = sysfs_create_file(&dev->kobj,
-                                               max6697_attributes[i][5]);
-                       if (err)
-                               goto error;
-               }
-       }
+       err = sysfs_create_group(&client->dev.kobj, &max6697_group);
+       if (err)
+               return err;
 
        data->hwmon_dev = hwmon_device_register(dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -680,7 +657,7 @@ static int max6697_probe(struct i2c_client *client,
        return 0;
 
 error:
-       max6697_remove_files(client);
+       sysfs_remove_group(&client->dev.kobj, &max6697_group);
        return err;
 }
 
@@ -689,7 +666,7 @@ static int max6697_remove(struct i2c_client *client)
        struct max6697_data *data = i2c_get_clientdata(client);
 
        hwmon_device_unregister(data->hwmon_dev);
-       max6697_remove_files(client);
+       sysfs_remove_group(&client->dev.kobj, &max6697_group);
 
        return 0;
 }
index 2a7f331..982d862 100644 (file)
@@ -273,18 +273,7 @@ static struct platform_driver mc13783_adc_driver = {
        .id_table       = mc13783_adc_idtable,
 };
 
-static int __init mc13783_adc_init(void)
-{
-       return platform_driver_probe(&mc13783_adc_driver, mc13783_adc_probe);
-}
-
-static void __exit mc13783_adc_exit(void)
-{
-       platform_driver_unregister(&mc13783_adc_driver);
-}
-
-module_init(mc13783_adc_init);
-module_exit(mc13783_adc_exit);
+module_platform_driver_probe(mc13783_adc_driver, mc13783_adc_probe);
 
 MODULE_DESCRIPTION("MC13783 ADC driver");
 MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
new file mode 100644 (file)
index 0000000..f43f5e5
--- /dev/null
@@ -0,0 +1,4191 @@
+/*
+ * nct6775 - Driver for the hardware monitoring functionality of
+ *            Nuvoton NCT677x Super-I/O chips
+ *
+ * Copyright (C) 2012  Guenter Roeck <linux@roeck-us.net>
+ *
+ * Derived from w83627ehf driver
+ * Copyright (C) 2005-2012  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2006  Yuan Mu (Winbond),
+ *                    Rudolf Marek <r.marek@assembler.cz>
+ *                    David Hubbard <david.c.hubbard@gmail.com>
+ *                    Daniel J Blueman <daniel.blueman@gmail.com>
+ * Copyright (C) 2010  Sheng-Yuan Huang (Nuvoton) (PS00)
+ *
+ * Shamelessly ripped from the w83627hf driver
+ * Copyright (C) 2003  Mark Studebaker
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Supports the following chips:
+ *
+ * Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
+ * nct6775f     9      4       3       6+3    0xb470 0xc1    0x5ca3
+ * nct6776f     9      5       3       6+3    0xc330 0xc1    0x5ca3
+ * nct6779d    15      5       5       2+6    0xc560 0xc1    0x5ca3
+ *
+ * #temp lists the number of monitored temperature sources (first value) plus
+ * the number of directly connectable temperature sensors (second value).
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include "lm75.h"
+
+#define USE_ALTERNATE
+
+enum kinds { nct6775, nct6776, nct6779 };
+
+/* used to set data->name = nct6775_device_names[data->sio_kind] */
+static const char * const nct6775_device_names[] = {
+       "nct6775",
+       "nct6776",
+       "nct6779",
+};
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+static unsigned short fan_debounce;
+module_param(fan_debounce, ushort, 0);
+MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
+
+#define DRVNAME "nct6775"
+
+/*
+ * Super-I/O constants and functions
+ */
+
+#define NCT6775_LD_ACPI                0x0a
+#define NCT6775_LD_HWM         0x0b
+#define NCT6775_LD_VID         0x0d
+
+#define SIO_REG_LDSEL          0x07    /* Logical device select */
+#define SIO_REG_DEVID          0x20    /* Device ID (2 bytes) */
+#define SIO_REG_ENABLE         0x30    /* Logical device enable */
+#define SIO_REG_ADDR           0x60    /* Logical device address (2 bytes) */
+
+#define SIO_NCT6775_ID         0xb470
+#define SIO_NCT6776_ID         0xc330
+#define SIO_NCT6779_ID         0xc560
+#define SIO_ID_MASK            0xFFF0
+
+enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
+
+static inline void
+superio_outb(int ioreg, int reg, int val)
+{
+       outb(reg, ioreg);
+       outb(val, ioreg + 1);
+}
+
+static inline int
+superio_inb(int ioreg, int reg)
+{
+       outb(reg, ioreg);
+       return inb(ioreg + 1);
+}
+
+static inline void
+superio_select(int ioreg, int ld)
+{
+       outb(SIO_REG_LDSEL, ioreg);
+       outb(ld, ioreg + 1);
+}
+
+static inline int
+superio_enter(int ioreg)
+{
+       /*
+        * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
+        */
+       if (!request_muxed_region(ioreg, 2, DRVNAME))
+               return -EBUSY;
+
+       outb(0x87, ioreg);
+       outb(0x87, ioreg);
+
+       return 0;
+}
+
+static inline void
+superio_exit(int ioreg)
+{
+       outb(0xaa, ioreg);
+       outb(0x02, ioreg);
+       outb(0x02, ioreg + 1);
+       release_region(ioreg, 2);
+}
+
+/*
+ * ISA constants
+ */
+
+#define IOREGION_ALIGNMENT     (~7)
+#define IOREGION_OFFSET                5
+#define IOREGION_LENGTH                2
+#define ADDR_REG_OFFSET                0
+#define DATA_REG_OFFSET                1
+
+#define NCT6775_REG_BANK       0x4E
+#define NCT6775_REG_CONFIG     0x40
+
+/*
+ * Not currently used:
+ * REG_MAN_ID has the value 0x5ca3 for all supported chips.
+ * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
+ * REG_MAN_ID is at port 0x4f
+ * REG_CHIP_ID is at port 0x58
+ */
+
+#define NUM_TEMP       10      /* Max number of temp attribute sets w/ limits*/
+#define NUM_TEMP_FIXED 6       /* Max number of fixed temp attribute sets */
+
+#define NUM_REG_ALARM  4       /* Max number of alarm registers */
+
+/* Common and NCT6775 specific data */
+
+/* Voltage min/max registers for nr=7..14 are in bank 5 */
+
+static const u16 NCT6775_REG_IN_MAX[] = {
+       0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
+       0x55c, 0x55e, 0x560, 0x562 };
+static const u16 NCT6775_REG_IN_MIN[] = {
+       0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
+       0x55d, 0x55f, 0x561, 0x563 };
+static const u16 NCT6775_REG_IN[] = {
+       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
+};
+
+#define NCT6775_REG_VBAT               0x5D
+#define NCT6775_REG_DIODE              0x5E
+
+#define NCT6775_REG_FANDIV1            0x506
+#define NCT6775_REG_FANDIV2            0x507
+
+#define NCT6775_REG_CR_FAN_DEBOUNCE    0xf0
+
+static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
+
+/* 0..15 voltages, 16..23 fans, 24..31 temperatures */
+
+static const s8 NCT6775_ALARM_BITS[] = {
+       0, 1, 2, 3, 8, 21, 20, 16,      /* in0.. in7 */
+       17, -1, -1, -1, -1, -1, -1,     /* in8..in14 */
+       -1,                             /* unused */
+       6, 7, 11, 10, 23,               /* fan1..fan5 */
+       -1, -1, -1,                     /* unused */
+       4, 5, 13, -1, -1, -1,           /* temp1..temp6 */
+       12, -1 };                       /* intrusion0, intrusion1 */
+
+#define FAN_ALARM_BASE         16
+#define TEMP_ALARM_BASE                24
+#define INTRUSION_ALARM_BASE   30
+
+static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
+static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
+
+/* DC or PWM output fan configuration */
+static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
+static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
+
+/* Advanced Fan control, some values are common for all fans */
+
+static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301, 0x801, 0x901 };
+static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302, 0x802, 0x902 };
+static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
+       0x103, 0x203, 0x303, 0x803, 0x903 };
+static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
+       0x104, 0x204, 0x304, 0x804, 0x904 };
+static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
+       0x105, 0x205, 0x305, 0x805, 0x905 };
+static const u16 NCT6775_REG_FAN_START_OUTPUT[]
+       = { 0x106, 0x206, 0x306, 0x806, 0x906 };
+static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
+static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
+
+static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
+       0x107, 0x207, 0x307, 0x807, 0x907 };
+static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309, 0x809, 0x909 };
+static const u16 NCT6775_REG_PWM_READ[] = { 0x01, 0x03, 0x11, 0x13, 0x15 };
+
+static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
+static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
+static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
+
+static const u16 NCT6775_REG_TEMP[] = {
+       0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
+
+static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+       0, 0x152, 0x252, 0x628, 0x629, 0x62A };
+static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+       0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
+static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+       0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
+
+static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+       0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
+
+static const u16 NCT6775_REG_TEMP_SEL[] = {
+       0x100, 0x200, 0x300, 0x800, 0x900 };
+
+static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
+       0x139, 0x239, 0x339, 0x839, 0x939 };
+static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
+       0x13a, 0x23a, 0x33a, 0x83a, 0x93a };
+static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
+       0x13b, 0x23b, 0x33b, 0x83b, 0x93b };
+static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
+       0x13c, 0x23c, 0x33c, 0x83c, 0x93c };
+static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
+       0x13d, 0x23d, 0x33d, 0x83d, 0x93d };
+
+static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
+
+static const u16 NCT6775_REG_AUTO_TEMP[] = {
+       0x121, 0x221, 0x321, 0x821, 0x921 };
+static const u16 NCT6775_REG_AUTO_PWM[] = {
+       0x127, 0x227, 0x327, 0x827, 0x927 };
+
+#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
+#define NCT6775_AUTO_PWM(data, nr, p)  ((data)->REG_AUTO_PWM[nr] + (p))
+
+static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
+
+static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
+       0x135, 0x235, 0x335, 0x835, 0x935 };
+static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
+       0x138, 0x238, 0x338, 0x838, 0x938 };
+
+static const char *const nct6775_temp_label[] = {
+       "",
+       "SYSTIN",
+       "CPUTIN",
+       "AUXTIN",
+       "AMD SB-TSI",
+       "PECI Agent 0",
+       "PECI Agent 1",
+       "PECI Agent 2",
+       "PECI Agent 3",
+       "PECI Agent 4",
+       "PECI Agent 5",
+       "PECI Agent 6",
+       "PECI Agent 7",
+       "PCH_CHIP_CPU_MAX_TEMP",
+       "PCH_CHIP_TEMP",
+       "PCH_CPU_TEMP",
+       "PCH_MCH_TEMP",
+       "PCH_DIM0_TEMP",
+       "PCH_DIM1_TEMP",
+       "PCH_DIM2_TEMP",
+       "PCH_DIM3_TEMP"
+};
+
+static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1]
+       = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
+
+static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1]
+       = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06,
+           0xa07 };
+
+/* NCT6776 specific data */
+
+static const s8 NCT6776_ALARM_BITS[] = {
+       0, 1, 2, 3, 8, 21, 20, 16,      /* in0.. in7 */
+       17, -1, -1, -1, -1, -1, -1,     /* in8..in14 */
+       -1,                             /* unused */
+       6, 7, 11, 10, 23,               /* fan1..fan5 */
+       -1, -1, -1,                     /* unused */
+       4, 5, 13, -1, -1, -1,           /* temp1..temp6 */
+       12, 9 };                        /* intrusion0, intrusion1 */
+
+static const u16 NCT6776_REG_TOLERANCE_H[] = {
+       0x10c, 0x20c, 0x30c, 0x80c, 0x90c };
+
+static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0 };
+static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0 };
+
+static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
+static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
+
+static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
+       0x13e, 0x23e, 0x33e, 0x83e, 0x93e };
+
+static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+       0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
+
+static const char *const nct6776_temp_label[] = {
+       "",
+       "SYSTIN",
+       "CPUTIN",
+       "AUXTIN",
+       "SMBUSMASTER 0",
+       "SMBUSMASTER 1",
+       "SMBUSMASTER 2",
+       "SMBUSMASTER 3",
+       "SMBUSMASTER 4",
+       "SMBUSMASTER 5",
+       "SMBUSMASTER 6",
+       "SMBUSMASTER 7",
+       "PECI Agent 0",
+       "PECI Agent 1",
+       "PCH_CHIP_CPU_MAX_TEMP",
+       "PCH_CHIP_TEMP",
+       "PCH_CPU_TEMP",
+       "PCH_MCH_TEMP",
+       "PCH_DIM0_TEMP",
+       "PCH_DIM1_TEMP",
+       "PCH_DIM2_TEMP",
+       "PCH_DIM3_TEMP",
+       "BYTE_TEMP"
+};
+
+static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
+       = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
+
+static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
+       = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
+
+/* NCT6779 specific data */
+
+static const u16 NCT6779_REG_IN[] = {
+       0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
+       0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
+
+static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
+       0x459, 0x45A, 0x45B, 0x568 };
+
+static const s8 NCT6779_ALARM_BITS[] = {
+       0, 1, 2, 3, 8, 21, 20, 16,      /* in0.. in7 */
+       17, 24, 25, 26, 27, 28, 29,     /* in8..in14 */
+       -1,                             /* unused */
+       6, 7, 11, 10, 23,               /* fan1..fan5 */
+       -1, -1, -1,                     /* unused */
+       4, 5, 13, -1, -1, -1,           /* temp1..temp6 */
+       12, 9 };                        /* intrusion0, intrusion1 */
+
+static const u16 NCT6779_REG_FAN[] = { 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8 };
+static const u16 NCT6779_REG_FAN_PULSES[] = {
+       0x644, 0x645, 0x646, 0x647, 0x648 };
+
+static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
+       0x136, 0x236, 0x336, 0x836, 0x936 };
+static const u16 NCT6779_REG_CRITICAL_PWM[] = {
+       0x137, 0x237, 0x337, 0x837, 0x937 };
+
+static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
+static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
+       0x18, 0x152 };
+static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
+       0x3a, 0x153 };
+static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
+       0x39, 0x155 };
+
+static const u16 NCT6779_REG_TEMP_OFFSET[] = {
+       0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
+
+static const char *const nct6779_temp_label[] = {
+       "",
+       "SYSTIN",
+       "CPUTIN",
+       "AUXTIN0",
+       "AUXTIN1",
+       "AUXTIN2",
+       "AUXTIN3",
+       "",
+       "SMBUSMASTER 0",
+       "SMBUSMASTER 1",
+       "SMBUSMASTER 2",
+       "SMBUSMASTER 3",
+       "SMBUSMASTER 4",
+       "SMBUSMASTER 5",
+       "SMBUSMASTER 6",
+       "SMBUSMASTER 7",
+       "PECI Agent 0",
+       "PECI Agent 1",
+       "PCH_CHIP_CPU_MAX_TEMP",
+       "PCH_CHIP_TEMP",
+       "PCH_CPU_TEMP",
+       "PCH_MCH_TEMP",
+       "PCH_DIM0_TEMP",
+       "PCH_DIM1_TEMP",
+       "PCH_DIM2_TEMP",
+       "PCH_DIM3_TEMP",
+       "BYTE_TEMP"
+};
+
+static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1]
+       = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
+           0, 0, 0, 0, 0, 0, 0, 0,
+           0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
+           0x408, 0 };
+
+static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1]
+       = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
+
+static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
+{
+       if (mode == 0 && pwm == 255)
+               return off;
+       return mode + 1;
+}
+
+static int pwm_enable_to_reg(enum pwm_enable mode)
+{
+       if (mode == off)
+               return 0;
+       return mode - 1;
+}
+
+/*
+ * Conversions
+ */
+
+/* 1 is DC mode, output in ms */
+static unsigned int step_time_from_reg(u8 reg, u8 mode)
+{
+       return mode ? 400 * reg : 100 * reg;
+}
+
+static u8 step_time_to_reg(unsigned int msec, u8 mode)
+{
+       return clamp_val((mode ? (msec + 200) / 400 :
+                                       (msec + 50) / 100), 1, 255);
+}
+
+static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
+{
+       if (reg == 0 || reg == 255)
+               return 0;
+       return 1350000U / (reg << divreg);
+}
+
+static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
+{
+       if ((reg & 0xff1f) == 0xff1f)
+               return 0;
+
+       reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
+
+       if (reg == 0)
+               return 0;
+
+       return 1350000U / reg;
+}
+
+static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
+{
+       if (reg == 0 || reg == 0xffff)
+               return 0;
+
+       /*
+        * Even though the registers are 16 bit wide, the fan divisor
+        * still applies.
+        */
+       return 1350000U / (reg << divreg);
+}
+
+static u16 fan_to_reg(u32 fan, unsigned int divreg)
+{
+       if (!fan)
+               return 0;
+
+       return (1350000U / fan) >> divreg;
+}
+
+static inline unsigned int
+div_from_reg(u8 reg)
+{
+       return 1 << reg;
+}
+
+/*
+ * Some of the voltage inputs have internal scaling, the tables below
+ * contain 8 (the ADC LSB in mV) * scaling factor * 100
+ */
+static const u16 scale_in[15] = {
+       800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
+       800, 800
+};
+
+static inline long in_from_reg(u8 reg, u8 nr)
+{
+       return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
+}
+
+static inline u8 in_to_reg(u32 val, u8 nr)
+{
+       return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
+}
+
+/*
+ * Data structures and manipulation thereof
+ */
+
+struct nct6775_data {
+       int addr;       /* IO base of hw monitor block */
+       enum kinds kind;
+       const char *name;
+
+       struct device *hwmon_dev;
+
+       u16 reg_temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+                                   * 3=temp_crit
+                                   */
+       u8 temp_src[NUM_TEMP];
+       u16 reg_temp_config[NUM_TEMP];
+       const char * const *temp_label;
+       int temp_label_num;
+
+       u16 REG_CONFIG;
+       u16 REG_VBAT;
+       u16 REG_DIODE;
+
+       const s8 *ALARM_BITS;
+
+       const u16 *REG_VIN;
+       const u16 *REG_IN_MINMAX[2];
+
+       const u16 *REG_TARGET;
+       const u16 *REG_FAN;
+       const u16 *REG_FAN_MODE;
+       const u16 *REG_FAN_MIN;
+       const u16 *REG_FAN_PULSES;
+       const u16 *REG_FAN_TIME[3];
+
+       const u16 *REG_TOLERANCE_H;
+
+       const u8 *REG_PWM_MODE;
+       const u8 *PWM_MODE_MASK;
+
+       const u16 *REG_PWM[7];  /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
+                                * [3]=pwm_max, [4]=pwm_step,
+                                * [5]=weight_duty_step, [6]=weight_duty_base
+                                */
+       const u16 *REG_PWM_READ;
+
+       const u16 *REG_AUTO_TEMP;
+       const u16 *REG_AUTO_PWM;
+
+       const u16 *REG_CRITICAL_TEMP;
+       const u16 *REG_CRITICAL_TEMP_TOLERANCE;
+
+       const u16 *REG_TEMP_SOURCE;     /* temp register sources */
+       const u16 *REG_TEMP_SEL;
+       const u16 *REG_WEIGHT_TEMP_SEL;
+       const u16 *REG_WEIGHT_TEMP[3];  /* 0=base, 1=tolerance, 2=step */
+
+       const u16 *REG_TEMP_OFFSET;
+
+       const u16 *REG_ALARM;
+
+       unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
+       unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
+
+       struct mutex update_lock;
+       bool valid;             /* true if following fields are valid */
+       unsigned long last_updated;     /* In jiffies */
+
+       /* Register values */
+       u8 bank;                /* current register bank */
+       u8 in_num;              /* number of in inputs we have */
+       u8 in[15][3];           /* [0]=in, [1]=in_max, [2]=in_min */
+       unsigned int rpm[5];
+       u16 fan_min[5];
+       u8 fan_pulses[5];
+       u8 fan_div[5];
+       u8 has_pwm;
+       u8 has_fan;             /* some fan inputs can be disabled */
+       u8 has_fan_min;         /* some fans don't have min register */
+       bool has_fan_div;
+
+       u8 temp_fixed_num;      /* 3 or 6 */
+       u8 temp_type[NUM_TEMP_FIXED];
+       s8 temp_offset[NUM_TEMP_FIXED];
+       s16 temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+                               * 3=temp_crit */
+       u64 alarms;
+
+       u8 pwm_num;     /* number of pwm */
+       u8 pwm_mode[5]; /* 1->DC variable voltage, 0->PWM variable duty cycle */
+       enum pwm_enable pwm_enable[5];
+                       /* 0->off
+                        * 1->manual
+                        * 2->thermal cruise mode (also called SmartFan I)
+                        * 3->fan speed cruise mode
+                        * 4->SmartFan III
+                        * 5->enhanced variable thermal cruise (SmartFan IV)
+                        */
+       u8 pwm[7][5];   /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
+                        * [3]=pwm_max, [4]=pwm_step,
+                        * [5]=weight_duty_step, [6]=weight_duty_base
+                        */
+
+       u8 target_temp[5];
+       u8 target_temp_mask;
+       u32 target_speed[5];
+       u32 target_speed_tolerance[5];
+       u8 speed_tolerance_limit;
+
+       u8 temp_tolerance[2][5];
+       u8 tolerance_mask;
+
+       u8 fan_time[3][5]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
+
+       /* Automatic fan speed control registers */
+       int auto_pwm_num;
+       u8 auto_pwm[5][7];
+       u8 auto_temp[5][7];
+       u8 pwm_temp_sel[5];
+       u8 pwm_weight_temp_sel[5];
+       u8 weight_temp[3][5];   /* 0->temp_step, 1->temp_step_tol,
+                                * 2->temp_base
+                                */
+
+       u8 vid;
+       u8 vrm;
+
+       u16 have_temp;
+       u16 have_temp_fixed;
+       u16 have_in;
+#ifdef CONFIG_PM
+       /* Remember extra register values over suspend/resume */
+       u8 vbat;
+       u8 fandiv1;
+       u8 fandiv2;
+#endif
+};
+
+struct nct6775_sio_data {
+       int sioreg;
+       enum kinds kind;
+};
+
+static bool is_word_sized(struct nct6775_data *data, u16 reg)
+{
+       switch (data->kind) {
+       case nct6775:
+               return (((reg & 0xff00) == 0x100 ||
+                   (reg & 0xff00) == 0x200) &&
+                  ((reg & 0x00ff) == 0x50 ||
+                   (reg & 0x00ff) == 0x53 ||
+                   (reg & 0x00ff) == 0x55)) ||
+                 (reg & 0xfff0) == 0x630 ||
+                 reg == 0x640 || reg == 0x642 ||
+                 reg == 0x662 ||
+                 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
+                 reg == 0x73 || reg == 0x75 || reg == 0x77;
+       case nct6776:
+               return (((reg & 0xff00) == 0x100 ||
+                   (reg & 0xff00) == 0x200) &&
+                  ((reg & 0x00ff) == 0x50 ||
+                   (reg & 0x00ff) == 0x53 ||
+                   (reg & 0x00ff) == 0x55)) ||
+                 (reg & 0xfff0) == 0x630 ||
+                 reg == 0x402 ||
+                 reg == 0x640 || reg == 0x642 ||
+                 ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
+                 reg == 0x73 || reg == 0x75 || reg == 0x77;
+       case nct6779:
+               return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
+                 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x09) ||
+                 reg == 0x402 ||
+                 reg == 0x63a || reg == 0x63c || reg == 0x63e ||
+                 reg == 0x640 || reg == 0x642 ||
+                 reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
+                 reg == 0x7b;
+       }
+       return false;
+}
+
+/*
+ * On older chips, only registers 0x50-0x5f are banked.
+ * On more recent chips, all registers are banked.
+ * Assume that is the case and set the bank number for each access.
+ * Cache the bank number so it only needs to be set if it changes.
+ */
+static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
+{
+       u8 bank = reg >> 8;
+       if (data->bank != bank) {
+               outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
+               outb_p(bank, data->addr + DATA_REG_OFFSET);
+               data->bank = bank;
+       }
+}
+
+static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
+{
+       int res, word_sized = is_word_sized(data, reg);
+
+       nct6775_set_bank(data, reg);
+       outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
+       res = inb_p(data->addr + DATA_REG_OFFSET);
+       if (word_sized) {
+               outb_p((reg & 0xff) + 1,
+                      data->addr + ADDR_REG_OFFSET);
+               res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
+       }
+       return res;
+}
+
+static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
+{
+       int word_sized = is_word_sized(data, reg);
+
+       nct6775_set_bank(data, reg);
+       outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
+       if (word_sized) {
+               outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
+               outb_p((reg & 0xff) + 1,
+                      data->addr + ADDR_REG_OFFSET);
+       }
+       outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
+       return 0;
+}
+
+/* We left-align 8-bit temperature values to make the code simpler */
+static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
+{
+       u16 res;
+
+       res = nct6775_read_value(data, reg);
+       if (!is_word_sized(data, reg))
+               res <<= 8;
+
+       return res;
+}
+
+static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
+{
+       if (!is_word_sized(data, reg))
+               value >>= 8;
+       return nct6775_write_value(data, reg, value);
+}
+
+/* This function assumes that the caller holds data->update_lock */
+static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
+{
+       u8 reg;
+
+       switch (nr) {
+       case 0:
+               reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
+                   | (data->fan_div[0] & 0x7);
+               nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
+               break;
+       case 1:
+               reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
+                   | ((data->fan_div[1] << 4) & 0x70);
+               nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
+               break;
+       case 2:
+               reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
+                   | (data->fan_div[2] & 0x7);
+               nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
+               break;
+       case 3:
+               reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
+                   | ((data->fan_div[3] << 4) & 0x70);
+               nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
+               break;
+       }
+}
+
+static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
+{
+       if (data->kind == nct6775)
+               nct6775_write_fan_div(data, nr);
+}
+
+static void nct6775_update_fan_div(struct nct6775_data *data)
+{
+       u8 i;
+
+       i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
+       data->fan_div[0] = i & 0x7;
+       data->fan_div[1] = (i & 0x70) >> 4;
+       i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
+       data->fan_div[2] = i & 0x7;
+       if (data->has_fan & (1 << 3))
+               data->fan_div[3] = (i & 0x70) >> 4;
+}
+
+static void nct6775_update_fan_div_common(struct nct6775_data *data)
+{
+       if (data->kind == nct6775)
+               nct6775_update_fan_div(data);
+}
+
+static void nct6775_init_fan_div(struct nct6775_data *data)
+{
+       int i;
+
+       nct6775_update_fan_div_common(data);
+       /*
+        * For all fans, start with highest divider value if the divider
+        * register is not initialized. This ensures that we get a
+        * reading from the fan count register, even if it is not optimal.
+        * We'll compute a better divider later on.
+        */
+       for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
+               if (!(data->has_fan & (1 << i)))
+                       continue;
+               if (data->fan_div[i] == 0) {
+                       data->fan_div[i] = 7;
+                       nct6775_write_fan_div_common(data, i);
+               }
+       }
+}
+
+static void nct6775_init_fan_common(struct device *dev,
+                                   struct nct6775_data *data)
+{
+       int i;
+       u8 reg;
+
+       if (data->has_fan_div)
+               nct6775_init_fan_div(data);
+
+       /*
+        * If fan_min is not set (0), set it to 0xff to disable it. This
+        * prevents the unnecessary warning when fanX_min is reported as 0.
+        */
+       for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
+               if (data->has_fan_min & (1 << i)) {
+                       reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
+                       if (!reg)
+                               nct6775_write_value(data, data->REG_FAN_MIN[i],
+                                                   data->has_fan_div ? 0xff
+                                                                     : 0xff1f);
+               }
+       }
+}
+
+static void nct6775_select_fan_div(struct device *dev,
+                                  struct nct6775_data *data, int nr, u16 reg)
+{
+       u8 fan_div = data->fan_div[nr];
+       u16 fan_min;
+
+       if (!data->has_fan_div)
+               return;
+
+       /*
+        * If we failed to measure the fan speed, or the reported value is not
+        * in the optimal range, and the clock divider can be modified,
+        * let's try that for next time.
+        */
+       if (reg == 0x00 && fan_div < 0x07)
+               fan_div++;
+       else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
+               fan_div--;
+
+       if (fan_div != data->fan_div[nr]) {
+               dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
+                       nr + 1, div_from_reg(data->fan_div[nr]),
+                       div_from_reg(fan_div));
+
+               /* Preserve min limit if possible */
+               if (data->has_fan_min & (1 << nr)) {
+                       fan_min = data->fan_min[nr];
+                       if (fan_div > data->fan_div[nr]) {
+                               if (fan_min != 255 && fan_min > 1)
+                                       fan_min >>= 1;
+                       } else {
+                               if (fan_min != 255) {
+                                       fan_min <<= 1;
+                                       if (fan_min > 254)
+                                               fan_min = 254;
+                               }
+                       }
+                       if (fan_min != data->fan_min[nr]) {
+                               data->fan_min[nr] = fan_min;
+                               nct6775_write_value(data, data->REG_FAN_MIN[nr],
+                                                   fan_min);
+                       }
+               }
+               data->fan_div[nr] = fan_div;
+               nct6775_write_fan_div_common(data, nr);
+       }
+}
+
+static void nct6775_update_pwm(struct device *dev)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       int i, j;
+       int fanmodecfg, reg;
+       bool duty_is_dc;
+
+       for (i = 0; i < data->pwm_num; i++) {
+               if (!(data->has_pwm & (1 << i)))
+                       continue;
+
+               duty_is_dc = data->REG_PWM_MODE[i] &&
+                 (nct6775_read_value(data, data->REG_PWM_MODE[i])
+                  & data->PWM_MODE_MASK[i]);
+               data->pwm_mode[i] = duty_is_dc;
+
+               fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
+               for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
+                       if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
+                               data->pwm[j][i]
+                                 = nct6775_read_value(data,
+                                                      data->REG_PWM[j][i]);
+                       }
+               }
+
+               data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
+                                                       (fanmodecfg >> 4) & 7);
+
+               if (!data->temp_tolerance[0][i] ||
+                   data->pwm_enable[i] != speed_cruise)
+                       data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
+               if (!data->target_speed_tolerance[i] ||
+                   data->pwm_enable[i] == speed_cruise) {
+                       u8 t = fanmodecfg & 0x0f;
+                       if (data->REG_TOLERANCE_H) {
+                               t |= (nct6775_read_value(data,
+                                     data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
+                       }
+                       data->target_speed_tolerance[i] = t;
+               }
+
+               data->temp_tolerance[1][i] =
+                       nct6775_read_value(data,
+                                       data->REG_CRITICAL_TEMP_TOLERANCE[i]);
+
+               reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
+               data->pwm_temp_sel[i] = reg & 0x1f;
+               /* If fan can stop, report floor as 0 */
+               if (reg & 0x80)
+                       data->pwm[2][i] = 0;
+
+               reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
+               data->pwm_weight_temp_sel[i] = reg & 0x1f;
+               /* If weight is disabled, report weight source as 0 */
+               if (j == 1 && !(reg & 0x80))
+                       data->pwm_weight_temp_sel[i] = 0;
+
+               /* Weight temp data */
+               for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
+                       data->weight_temp[j][i]
+                         = nct6775_read_value(data,
+                                              data->REG_WEIGHT_TEMP[j][i]);
+               }
+       }
+}
+
+static void nct6775_update_pwm_limits(struct device *dev)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       int i, j;
+       u8 reg;
+       u16 reg_t;
+
+       for (i = 0; i < data->pwm_num; i++) {
+               if (!(data->has_pwm & (1 << i)))
+                       continue;
+
+               for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
+                       data->fan_time[j][i] =
+                         nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
+               }
+
+               reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
+               /* Update only in matching mode or if never updated */
+               if (!data->target_temp[i] ||
+                   data->pwm_enable[i] == thermal_cruise)
+                       data->target_temp[i] = reg_t & data->target_temp_mask;
+               if (!data->target_speed[i] ||
+                   data->pwm_enable[i] == speed_cruise) {
+                       if (data->REG_TOLERANCE_H) {
+                               reg_t |= (nct6775_read_value(data,
+                                       data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
+                       }
+                       data->target_speed[i] = reg_t;
+               }
+
+               for (j = 0; j < data->auto_pwm_num; j++) {
+                       data->auto_pwm[i][j] =
+                         nct6775_read_value(data,
+                                            NCT6775_AUTO_PWM(data, i, j));
+                       data->auto_temp[i][j] =
+                         nct6775_read_value(data,
+                                            NCT6775_AUTO_TEMP(data, i, j));
+               }
+
+               /* critical auto_pwm temperature data */
+               data->auto_temp[i][data->auto_pwm_num] =
+                       nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
+
+               switch (data->kind) {
+               case nct6775:
+                       reg = nct6775_read_value(data,
+                                                NCT6775_REG_CRITICAL_ENAB[i]);
+                       data->auto_pwm[i][data->auto_pwm_num] =
+                                               (reg & 0x02) ? 0xff : 0x00;
+                       break;
+               case nct6776:
+                       data->auto_pwm[i][data->auto_pwm_num] = 0xff;
+                       break;
+               case nct6779:
+                       reg = nct6775_read_value(data,
+                                       NCT6779_REG_CRITICAL_PWM_ENABLE[i]);
+                       if (reg & 1)
+                               data->auto_pwm[i][data->auto_pwm_num] =
+                                 nct6775_read_value(data,
+                                       NCT6779_REG_CRITICAL_PWM[i]);
+                       else
+                               data->auto_pwm[i][data->auto_pwm_num] = 0xff;
+                       break;
+               }
+       }
+}
+
+static struct nct6775_data *nct6775_update_device(struct device *dev)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       int i, j;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+           || !data->valid) {
+               /* Fan clock dividers */
+               nct6775_update_fan_div_common(data);
+
+               /* Measured voltages and limits */
+               for (i = 0; i < data->in_num; i++) {
+                       if (!(data->have_in & (1 << i)))
+                               continue;
+
+                       data->in[i][0] = nct6775_read_value(data,
+                                                           data->REG_VIN[i]);
+                       data->in[i][1] = nct6775_read_value(data,
+                                         data->REG_IN_MINMAX[0][i]);
+                       data->in[i][2] = nct6775_read_value(data,
+                                         data->REG_IN_MINMAX[1][i]);
+               }
+
+               /* Measured fan speeds and limits */
+               for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
+                       u16 reg;
+
+                       if (!(data->has_fan & (1 << i)))
+                               continue;
+
+                       reg = nct6775_read_value(data, data->REG_FAN[i]);
+                       data->rpm[i] = data->fan_from_reg(reg,
+                                                         data->fan_div[i]);
+
+                       if (data->has_fan_min & (1 << i))
+                               data->fan_min[i] = nct6775_read_value(data,
+                                          data->REG_FAN_MIN[i]);
+                       data->fan_pulses[i] =
+                         nct6775_read_value(data, data->REG_FAN_PULSES[i]);
+
+                       nct6775_select_fan_div(dev, data, i, reg);
+               }
+
+               nct6775_update_pwm(dev);
+               nct6775_update_pwm_limits(dev);
+
+               /* Measured temperatures and limits */
+               for (i = 0; i < NUM_TEMP; i++) {
+                       if (!(data->have_temp & (1 << i)))
+                               continue;
+                       for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
+                               if (data->reg_temp[j][i])
+                                       data->temp[j][i]
+                                         = nct6775_read_temp(data,
+                                               data->reg_temp[j][i]);
+                       }
+                       if (!(data->have_temp_fixed & (1 << i)))
+                               continue;
+                       data->temp_offset[i]
+                         = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
+               }
+
+               data->alarms = 0;
+               for (i = 0; i < NUM_REG_ALARM; i++) {
+                       u8 alarm;
+                       if (!data->REG_ALARM[i])
+                               continue;
+                       alarm = nct6775_read_value(data, data->REG_ALARM[i]);
+                       data->alarms |= ((u64)alarm) << (i << 3);
+               }
+
+               data->last_updated = jiffies;
+               data->valid = true;
+       }
+
+       mutex_unlock(&data->update_lock);
+       return data;
+}
+
+/*
+ * Sysfs callback functions
+ */
+static ssize_t
+show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+       return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
+}
+
+static ssize_t
+store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
+            size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+       unsigned long val;
+       int err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+       mutex_lock(&data->update_lock);
+       data->in[nr][index] = in_to_reg(val, nr);
+       nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
+                           data->in[nr][index]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t
+show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = data->ALARM_BITS[sattr->index];
+       return sprintf(buf, "%u\n",
+                      (unsigned int)((data->alarms >> nr) & 0x01));
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in_reg, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in_reg, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in_reg, NULL, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in_reg, NULL, 3, 0);
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in_reg, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in_reg, NULL, 5, 0);
+static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in_reg, NULL, 6, 0);
+static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in_reg, NULL, 7, 0);
+static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in_reg, NULL, 8, 0);
+static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in_reg, NULL, 9, 0);
+static SENSOR_DEVICE_ATTR_2(in10_input, S_IRUGO, show_in_reg, NULL, 10, 0);
+static SENSOR_DEVICE_ATTR_2(in11_input, S_IRUGO, show_in_reg, NULL, 11, 0);
+static SENSOR_DEVICE_ATTR_2(in12_input, S_IRUGO, show_in_reg, NULL, 12, 0);
+static SENSOR_DEVICE_ATTR_2(in13_input, S_IRUGO, show_in_reg, NULL, 13, 0);
+static SENSOR_DEVICE_ATTR_2(in14_input, S_IRUGO, show_in_reg, NULL, 14, 0);
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(in14_alarm, S_IRUGO, show_alarm, NULL, 14);
+
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 0, 1);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 1, 1);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 2, 1);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 3, 1);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 4, 1);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 5, 1);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 6, 1);
+static SENSOR_DEVICE_ATTR_2(in7_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 7, 1);
+static SENSOR_DEVICE_ATTR_2(in8_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 8, 1);
+static SENSOR_DEVICE_ATTR_2(in9_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 9, 1);
+static SENSOR_DEVICE_ATTR_2(in10_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 10, 1);
+static SENSOR_DEVICE_ATTR_2(in11_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 11, 1);
+static SENSOR_DEVICE_ATTR_2(in12_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 12, 1);
+static SENSOR_DEVICE_ATTR_2(in13_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 13, 1);
+static SENSOR_DEVICE_ATTR_2(in14_min, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 14, 1);
+
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 0, 2);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 1, 2);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 2, 2);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 3, 2);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 4, 2);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 5, 2);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 6, 2);
+static SENSOR_DEVICE_ATTR_2(in7_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 7, 2);
+static SENSOR_DEVICE_ATTR_2(in8_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 8, 2);
+static SENSOR_DEVICE_ATTR_2(in9_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 9, 2);
+static SENSOR_DEVICE_ATTR_2(in10_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 10, 2);
+static SENSOR_DEVICE_ATTR_2(in11_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 11, 2);
+static SENSOR_DEVICE_ATTR_2(in12_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 12, 2);
+static SENSOR_DEVICE_ATTR_2(in13_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 13, 2);
+static SENSOR_DEVICE_ATTR_2(in14_max, S_IWUSR | S_IRUGO, show_in_reg,
+                           store_in_reg, 14, 2);
+
+static struct attribute *nct6775_attributes_in[15][5] = {
+       {
+               &sensor_dev_attr_in0_input.dev_attr.attr,
+               &sensor_dev_attr_in0_min.dev_attr.attr,
+               &sensor_dev_attr_in0_max.dev_attr.attr,
+               &sensor_dev_attr_in0_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in1_input.dev_attr.attr,
+               &sensor_dev_attr_in1_min.dev_attr.attr,
+               &sensor_dev_attr_in1_max.dev_attr.attr,
+               &sensor_dev_attr_in1_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in2_input.dev_attr.attr,
+               &sensor_dev_attr_in2_min.dev_attr.attr,
+               &sensor_dev_attr_in2_max.dev_attr.attr,
+               &sensor_dev_attr_in2_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in3_input.dev_attr.attr,
+               &sensor_dev_attr_in3_min.dev_attr.attr,
+               &sensor_dev_attr_in3_max.dev_attr.attr,
+               &sensor_dev_attr_in3_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in4_input.dev_attr.attr,
+               &sensor_dev_attr_in4_min.dev_attr.attr,
+               &sensor_dev_attr_in4_max.dev_attr.attr,
+               &sensor_dev_attr_in4_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in5_input.dev_attr.attr,
+               &sensor_dev_attr_in5_min.dev_attr.attr,
+               &sensor_dev_attr_in5_max.dev_attr.attr,
+               &sensor_dev_attr_in5_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in6_input.dev_attr.attr,
+               &sensor_dev_attr_in6_min.dev_attr.attr,
+               &sensor_dev_attr_in6_max.dev_attr.attr,
+               &sensor_dev_attr_in6_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in7_input.dev_attr.attr,
+               &sensor_dev_attr_in7_min.dev_attr.attr,
+               &sensor_dev_attr_in7_max.dev_attr.attr,
+               &sensor_dev_attr_in7_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in8_input.dev_attr.attr,
+               &sensor_dev_attr_in8_min.dev_attr.attr,
+               &sensor_dev_attr_in8_max.dev_attr.attr,
+               &sensor_dev_attr_in8_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in9_input.dev_attr.attr,
+               &sensor_dev_attr_in9_min.dev_attr.attr,
+               &sensor_dev_attr_in9_max.dev_attr.attr,
+               &sensor_dev_attr_in9_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in10_input.dev_attr.attr,
+               &sensor_dev_attr_in10_min.dev_attr.attr,
+               &sensor_dev_attr_in10_max.dev_attr.attr,
+               &sensor_dev_attr_in10_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in11_input.dev_attr.attr,
+               &sensor_dev_attr_in11_min.dev_attr.attr,
+               &sensor_dev_attr_in11_max.dev_attr.attr,
+               &sensor_dev_attr_in11_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in12_input.dev_attr.attr,
+               &sensor_dev_attr_in12_min.dev_attr.attr,
+               &sensor_dev_attr_in12_max.dev_attr.attr,
+               &sensor_dev_attr_in12_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in13_input.dev_attr.attr,
+               &sensor_dev_attr_in13_min.dev_attr.attr,
+               &sensor_dev_attr_in13_max.dev_attr.attr,
+               &sensor_dev_attr_in13_alarm.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_in14_input.dev_attr.attr,
+               &sensor_dev_attr_in14_min.dev_attr.attr,
+               &sensor_dev_attr_in14_max.dev_attr.attr,
+               &sensor_dev_attr_in14_alarm.dev_attr.attr,
+               NULL
+       },
+};
+
+static const struct attribute_group nct6775_group_in[15] = {
+       { .attrs = nct6775_attributes_in[0] },
+       { .attrs = nct6775_attributes_in[1] },
+       { .attrs = nct6775_attributes_in[2] },
+       { .attrs = nct6775_attributes_in[3] },
+       { .attrs = nct6775_attributes_in[4] },
+       { .attrs = nct6775_attributes_in[5] },
+       { .attrs = nct6775_attributes_in[6] },
+       { .attrs = nct6775_attributes_in[7] },
+       { .attrs = nct6775_attributes_in[8] },
+       { .attrs = nct6775_attributes_in[9] },
+       { .attrs = nct6775_attributes_in[10] },
+       { .attrs = nct6775_attributes_in[11] },
+       { .attrs = nct6775_attributes_in[12] },
+       { .attrs = nct6775_attributes_in[13] },
+       { .attrs = nct6775_attributes_in[14] },
+};
+
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       return sprintf(buf, "%d\n", data->rpm[nr]);
+}
+
+static ssize_t
+show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       return sprintf(buf, "%d\n",
+                      data->fan_from_reg_min(data->fan_min[nr],
+                                             data->fan_div[nr]));
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
+}
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+             const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       unsigned long val;
+       int err;
+       unsigned int reg;
+       u8 new_div;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       mutex_lock(&data->update_lock);
+       if (!data->has_fan_div) {
+               /* NCT6776F or NCT6779D; we know this is a 13 bit register */
+               if (!val) {
+                       val = 0xff1f;
+               } else {
+                       if (val > 1350000U)
+                               val = 135000U;
+                       val = 1350000U / val;
+                       val = (val & 0x1f) | ((val << 3) & 0xff00);
+               }
+               data->fan_min[nr] = val;
+               goto write_min; /* Leave fan divider alone */
+       }
+       if (!val) {
+               /* No min limit, alarm disabled */
+               data->fan_min[nr] = 255;
+               new_div = data->fan_div[nr]; /* No change */
+               dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
+               goto write_div;
+       }
+       reg = 1350000U / val;
+       if (reg >= 128 * 255) {
+               /*
+                * Speed below this value cannot possibly be represented,
+                * even with the highest divider (128)
+                */
+               data->fan_min[nr] = 254;
+               new_div = 7; /* 128 == (1 << 7) */
+               dev_warn(dev,
+                        "fan%u low limit %lu below minimum %u, set to minimum\n",
+                        nr + 1, val, data->fan_from_reg_min(254, 7));
+       } else if (!reg) {
+               /*
+                * Speed above this value cannot possibly be represented,
+                * even with the lowest divider (1)
+                */
+               data->fan_min[nr] = 1;
+               new_div = 0; /* 1 == (1 << 0) */
+               dev_warn(dev,
+                        "fan%u low limit %lu above maximum %u, set to maximum\n",
+                        nr + 1, val, data->fan_from_reg_min(1, 0));
+       } else {
+               /*
+                * Automatically pick the best divider, i.e. the one such
+                * that the min limit will correspond to a register value
+                * in the 96..192 range
+                */
+               new_div = 0;
+               while (reg > 192 && new_div < 7) {
+                       reg >>= 1;
+                       new_div++;
+               }
+               data->fan_min[nr] = reg;
+       }
+
+write_div:
+       /*
+        * Write both the fan clock divider (if it changed) and the new
+        * fan min (unconditionally)
+        */
+       if (new_div != data->fan_div[nr]) {
+               dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
+                       nr + 1, div_from_reg(data->fan_div[nr]),
+                       div_from_reg(new_div));
+               data->fan_div[nr] = new_div;
+               nct6775_write_fan_div_common(data, nr);
+               /* Give the chip time to sample a new speed value */
+               data->last_updated = jiffies;
+       }
+
+write_min:
+       nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t
+show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int p = data->fan_pulses[sattr->index];
+
+       return sprintf(buf, "%d\n", p ? : 4);
+}
+
+static ssize_t
+store_fan_pulses(struct device *dev, struct device_attribute *attr,
+                const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       unsigned long val;
+       int err;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       if (val > 4)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       data->fan_pulses[nr] = val & 3;
+       nct6775_write_value(data, data->REG_FAN_PULSES[nr], val & 3);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static struct sensor_device_attribute sda_fan_input[] = {
+       SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+       SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+       SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
+       SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
+       SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
+};
+
+static struct sensor_device_attribute sda_fan_alarm[] = {
+       SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE),
+       SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 1),
+       SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 2),
+       SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 3),
+       SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 4),
+};
+
+static struct sensor_device_attribute sda_fan_min[] = {
+       SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   store_fan_min, 0),
+       SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   store_fan_min, 1),
+       SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   store_fan_min, 2),
+       SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   store_fan_min, 3),
+       SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
+                   store_fan_min, 4),
+};
+
+static struct sensor_device_attribute sda_fan_pulses[] = {
+       SENSOR_ATTR(fan1_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
+                   store_fan_pulses, 0),
+       SENSOR_ATTR(fan2_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
+                   store_fan_pulses, 1),
+       SENSOR_ATTR(fan3_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
+                   store_fan_pulses, 2),
+       SENSOR_ATTR(fan4_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
+                   store_fan_pulses, 3),
+       SENSOR_ATTR(fan5_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
+                   store_fan_pulses, 4),
+};
+
+static struct sensor_device_attribute sda_fan_div[] = {
+       SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
+       SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
+       SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
+       SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
+       SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
+};
+
+static ssize_t
+show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
+}
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+
+       return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
+}
+
+static ssize_t
+store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
+          size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+       int err;
+       long val;
+
+       err = kstrtol(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       mutex_lock(&data->update_lock);
+       data->temp[index][nr] = LM75_TEMP_TO_REG(val);
+       nct6775_write_temp(data, data->reg_temp[index][nr],
+                          data->temp[index][nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t
+show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+       return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
+}
+
+static ssize_t
+store_temp_offset(struct device *dev, struct device_attribute *attr,
+                 const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       long val;
+       int err;
+
+       err = kstrtol(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+
+       mutex_lock(&data->update_lock);
+       data->temp_offset[nr] = val;
+       nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t
+show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
+}
+
+static ssize_t
+store_temp_type(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       unsigned long val;
+       int err;
+       u8 vbat, diode, bit;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       if (val != 1 && val != 3 && val != 4)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+
+       data->temp_type[nr] = val;
+       vbat = nct6775_read_value(data, data->REG_VBAT) & ~(0x02 << nr);
+       diode = nct6775_read_value(data, data->REG_DIODE) & ~(0x02 << nr);
+       bit = 0x02 << nr;
+       switch (val) {
+       case 1: /* CPU diode (diode, current mode) */
+               vbat |= bit;
+               diode |= bit;
+               break;
+       case 3: /* diode, voltage mode */
+               vbat |= bit;
+               break;
+       case 4: /* thermistor */
+               break;
+       }
+       nct6775_write_value(data, data->REG_VBAT, vbat);
+       nct6775_write_value(data, data->REG_DIODE, diode);
+
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static struct sensor_device_attribute_2 sda_temp_input[] = {
+       SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
+       SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0),
+       SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0),
+       SENSOR_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0),
+       SENSOR_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0),
+       SENSOR_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0),
+       SENSOR_ATTR_2(temp7_input, S_IRUGO, show_temp, NULL, 6, 0),
+       SENSOR_ATTR_2(temp8_input, S_IRUGO, show_temp, NULL, 7, 0),
+       SENSOR_ATTR_2(temp9_input, S_IRUGO, show_temp, NULL, 8, 0),
+       SENSOR_ATTR_2(temp10_input, S_IRUGO, show_temp, NULL, 9, 0),
+};
+
+static struct sensor_device_attribute sda_temp_label[] = {
+       SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
+       SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
+       SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
+       SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
+       SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
+       SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
+       SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
+       SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
+       SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
+       SENSOR_ATTR(temp10_label, S_IRUGO, show_temp_label, NULL, 9),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max[] = {
+       SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     0, 1),
+       SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     1, 1),
+       SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     2, 1),
+       SENSOR_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     3, 1),
+       SENSOR_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     4, 1),
+       SENSOR_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     5, 1),
+       SENSOR_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     6, 1),
+       SENSOR_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     7, 1),
+       SENSOR_ATTR_2(temp9_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     8, 1),
+       SENSOR_ATTR_2(temp10_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     9, 1),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
+       SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     0, 2),
+       SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     1, 2),
+       SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     2, 2),
+       SENSOR_ATTR_2(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     3, 2),
+       SENSOR_ATTR_2(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     4, 2),
+       SENSOR_ATTR_2(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     5, 2),
+       SENSOR_ATTR_2(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     6, 2),
+       SENSOR_ATTR_2(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     7, 2),
+       SENSOR_ATTR_2(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     8, 2),
+       SENSOR_ATTR_2(temp10_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     9, 2),
+};
+
+static struct sensor_device_attribute_2 sda_temp_crit[] = {
+       SENSOR_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     0, 3),
+       SENSOR_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     1, 3),
+       SENSOR_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     2, 3),
+       SENSOR_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     3, 3),
+       SENSOR_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     4, 3),
+       SENSOR_ATTR_2(temp6_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     5, 3),
+       SENSOR_ATTR_2(temp7_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     6, 3),
+       SENSOR_ATTR_2(temp8_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     7, 3),
+       SENSOR_ATTR_2(temp9_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     8, 3),
+       SENSOR_ATTR_2(temp10_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+                     9, 3),
+};
+
+static struct sensor_device_attribute sda_temp_offset[] = {
+       SENSOR_ATTR(temp1_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+                   store_temp_offset, 0),
+       SENSOR_ATTR(temp2_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+                   store_temp_offset, 1),
+       SENSOR_ATTR(temp3_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+                   store_temp_offset, 2),
+       SENSOR_ATTR(temp4_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+                   store_temp_offset, 3),
+       SENSOR_ATTR(temp5_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+                   store_temp_offset, 4),
+       SENSOR_ATTR(temp6_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+                   store_temp_offset, 5),
+};
+
+static struct sensor_device_attribute sda_temp_type[] = {
+       SENSOR_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type,
+                   store_temp_type, 0),
+       SENSOR_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
+                   store_temp_type, 1),
+       SENSOR_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
+                   store_temp_type, 2),
+       SENSOR_ATTR(temp4_type, S_IRUGO | S_IWUSR, show_temp_type,
+                   store_temp_type, 3),
+       SENSOR_ATTR(temp5_type, S_IRUGO | S_IWUSR, show_temp_type,
+                   store_temp_type, 4),
+       SENSOR_ATTR(temp6_type, S_IRUGO | S_IWUSR, show_temp_type,
+                   store_temp_type, 5),
+};
+
+static struct sensor_device_attribute sda_temp_alarm[] = {
+       SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL,
+                   TEMP_ALARM_BASE),
+       SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL,
+                   TEMP_ALARM_BASE + 1),
+       SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL,
+                   TEMP_ALARM_BASE + 2),
+       SENSOR_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL,
+                   TEMP_ALARM_BASE + 3),
+       SENSOR_ATTR(temp5_alarm, S_IRUGO, show_alarm, NULL,
+                   TEMP_ALARM_BASE + 4),
+       SENSOR_ATTR(temp6_alarm, S_IRUGO, show_alarm, NULL,
+                   TEMP_ALARM_BASE + 5),
+};
+
+#define NUM_TEMP_ALARM ARRAY_SIZE(sda_temp_alarm)
+
+static ssize_t
+show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+       return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
+}
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+              const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       unsigned long val;
+       int err;
+       u8 reg;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       if (val > 1)
+               return -EINVAL;
+
+       /* Setting DC mode is not supported for all chips/channels */
+       if (data->REG_PWM_MODE[nr] == 0) {
+               if (val)
+                       return -EINVAL;
+               return count;
+       }
+
+       mutex_lock(&data->update_lock);
+       data->pwm_mode[nr] = val;
+       reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
+       reg &= ~data->PWM_MODE_MASK[nr];
+       if (val)
+               reg |= data->PWM_MODE_MASK[nr];
+       nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+       int pwm;
+
+       /*
+        * For automatic fan control modes, show current pwm readings.
+        * Otherwise, show the configured value.
+        */
+       if (index == 0 && data->pwm_enable[nr] > manual)
+               pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
+       else
+               pwm = data->pwm[index][nr];
+
+       return sprintf(buf, "%d\n", pwm);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
+         size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+       unsigned long val;
+       int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
+       int maxval[7]
+         = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
+       int err;
+       u8 reg;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+       val = clamp_val(val, minval[index], maxval[index]);
+
+       mutex_lock(&data->update_lock);
+       data->pwm[index][nr] = val;
+       nct6775_write_value(data, data->REG_PWM[index][nr], val);
+       if (index == 2) { /* floor: disable if val == 0 */
+               reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
+               reg &= 0x7f;
+               if (val)
+                       reg |= 0x80;
+               nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
+       }
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+/* Returns 0 if OK, -EINVAL otherwise */
+static int check_trip_points(struct nct6775_data *data, int nr)
+{
+       int i;
+
+       for (i = 0; i < data->auto_pwm_num - 1; i++) {
+               if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
+                       return -EINVAL;
+       }
+       for (i = 0; i < data->auto_pwm_num - 1; i++) {
+               if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
+                       return -EINVAL;
+       }
+       /* validate critical temperature and pwm if enabled (pwm > 0) */
+       if (data->auto_pwm[nr][data->auto_pwm_num]) {
+               if (data->auto_temp[nr][data->auto_pwm_num - 1] >
+                               data->auto_temp[nr][data->auto_pwm_num] ||
+                   data->auto_pwm[nr][data->auto_pwm_num - 1] >
+                               data->auto_pwm[nr][data->auto_pwm_num])
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+static void pwm_update_registers(struct nct6775_data *data, int nr)
+{
+       u8 reg;
+
+       switch (data->pwm_enable[nr]) {
+       case off:
+       case manual:
+               break;
+       case speed_cruise:
+               reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
+               reg = (reg & ~data->tolerance_mask) |
+                 (data->target_speed_tolerance[nr] & data->tolerance_mask);
+               nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
+               nct6775_write_value(data, data->REG_TARGET[nr],
+                                   data->target_speed[nr] & 0xff);
+               if (data->REG_TOLERANCE_H) {
+                       reg = (data->target_speed[nr] >> 8) & 0x0f;
+                       reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
+                       nct6775_write_value(data,
+                                           data->REG_TOLERANCE_H[nr],
+                                           reg);
+               }
+               break;
+       case thermal_cruise:
+               nct6775_write_value(data, data->REG_TARGET[nr],
+                                   data->target_temp[nr]);
+               /* intentional */
+       default:
+               reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
+               reg = (reg & ~data->tolerance_mask) |
+                 data->temp_tolerance[0][nr];
+               nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
+               break;
+       }
+}
+
+static ssize_t
+show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+       return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *attr,
+                const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       unsigned long val;
+       int err;
+       u16 reg;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       if (val > sf4)
+               return -EINVAL;
+
+       if (val == sf3 && data->kind != nct6775)
+               return -EINVAL;
+
+       if (val == sf4 && check_trip_points(data, nr)) {
+               dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
+               dev_err(dev, "Adjust trip points and try again\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&data->update_lock);
+       data->pwm_enable[nr] = val;
+       if (val == off) {
+               /*
+                * turn off pwm control: select manual mode, set pwm to maximum
+                */
+               data->pwm[0][nr] = 255;
+               nct6775_write_value(data, data->REG_PWM[0][nr], 255);
+       }
+       pwm_update_registers(data, nr);
+       reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
+       reg &= 0x0f;
+       reg |= pwm_enable_to_reg(val) << 4;
+       nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t
+show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
+{
+       int i, sel = 0;
+
+       for (i = 0; i < NUM_TEMP; i++) {
+               if (!(data->have_temp & (1 << i)))
+                       continue;
+               if (src == data->temp_src[i]) {
+                       sel = i + 1;
+                       break;
+               }
+       }
+
+       return sprintf(buf, "%d\n", sel);
+}
+
+static ssize_t
+show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int index = sattr->index;
+
+       return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
+}
+
+static ssize_t
+store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
+                  const char *buf, size_t count)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       unsigned long val;
+       int err, reg, src;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+       if (val == 0 || val > NUM_TEMP)
+               return -EINVAL;
+       if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       src = data->temp_src[val - 1];
+       data->pwm_temp_sel[nr] = src;
+       reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
+       reg &= 0xe0;
+       reg |= src;
+       nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t
+show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int index = sattr->index;
+
+       return show_pwm_temp_sel_common(data, buf,
+                                       data->pwm_weight_temp_sel[index]);
+}
+
+static ssize_t
+store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       unsigned long val;
+       int err, reg, src;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+       if (val > NUM_TEMP)
+               return -EINVAL;
+       if (val && (!(data->have_temp & (1 << (val - 1))) ||
+                   !data->temp_src[val - 1]))
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       if (val) {
+               src = data->temp_src[val - 1];
+               data->pwm_weight_temp_sel[nr] = src;
+               reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
+               reg &= 0xe0;
+               reg |= (src | 0x80);
+               nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
+       } else {
+               data->pwm_weight_temp_sel[nr] = 0;
+               reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
+               reg &= 0x7f;
+               nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
+       }
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t
+show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+       return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
+}
+
+static ssize_t
+store_target_temp(struct device *dev, struct device_attribute *attr,
+                 const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       unsigned long val;
+       int err;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
+                       data->target_temp_mask);
+
+       mutex_lock(&data->update_lock);
+       data->target_temp[nr] = val;
+       pwm_update_registers(data, nr);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t
+show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+
+       return sprintf(buf, "%d\n",
+                      fan_from_reg16(data->target_speed[nr],
+                                     data->fan_div[nr]));
+}
+
+static ssize_t
+store_target_speed(struct device *dev, struct device_attribute *attr,
+                  const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       unsigned long val;
+       int err;
+       u16 speed;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       val = clamp_val(val, 0, 1350000U);
+       speed = fan_to_reg(val, data->fan_div[nr]);
+
+       mutex_lock(&data->update_lock);
+       data->target_speed[nr] = speed;
+       pwm_update_registers(data, nr);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t
+show_temp_tolerance(struct device *dev, struct device_attribute *attr,
+                   char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+
+       return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
+}
+
+static ssize_t
+store_temp_tolerance(struct device *dev, struct device_attribute *attr,
+                    const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+       unsigned long val;
+       int err;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       /* Limit tolerance as needed */
+       val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
+
+       mutex_lock(&data->update_lock);
+       data->temp_tolerance[index][nr] = val;
+       if (index)
+               pwm_update_registers(data, nr);
+       else
+               nct6775_write_value(data,
+                                   data->REG_CRITICAL_TEMP_TOLERANCE[nr],
+                                   val);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+/*
+ * Fan speed tolerance is a tricky beast, since the associated register is
+ * a tick counter, but the value is reported and configured as rpm.
+ * Compute resulting low and high rpm values and report the difference.
+ */
+static ssize_t
+show_speed_tolerance(struct device *dev, struct device_attribute *attr,
+                    char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
+       int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
+       int tolerance;
+
+       if (low <= 0)
+               low = 1;
+       if (high > 0xffff)
+               high = 0xffff;
+       if (high < low)
+               high = low;
+
+       tolerance = (fan_from_reg16(low, data->fan_div[nr])
+                    - fan_from_reg16(high, data->fan_div[nr])) / 2;
+
+       return sprintf(buf, "%d\n", tolerance);
+}
+
+static ssize_t
+store_speed_tolerance(struct device *dev, struct device_attribute *attr,
+                     const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       int nr = sattr->index;
+       unsigned long val;
+       int err;
+       int low, high;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       high = fan_from_reg16(data->target_speed[nr],
+                             data->fan_div[nr]) + val;
+       low = fan_from_reg16(data->target_speed[nr],
+                            data->fan_div[nr]) - val;
+       if (low <= 0)
+               low = 1;
+       if (high < low)
+               high = low;
+
+       val = (fan_to_reg(low, data->fan_div[nr]) -
+              fan_to_reg(high, data->fan_div[nr])) / 2;
+
+       /* Limit tolerance as needed */
+       val = clamp_val(val, 0, data->speed_tolerance_limit);
+
+       mutex_lock(&data->update_lock);
+       data->target_speed_tolerance[nr] = val;
+       pwm_update_registers(data, nr);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4, 0);
+
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+                         store_pwm_mode, 0);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+                         store_pwm_mode, 1);
+static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+                         store_pwm_mode, 2);
+static SENSOR_DEVICE_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+                         store_pwm_mode, 3);
+static SENSOR_DEVICE_ATTR(pwm5_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+                         store_pwm_mode, 4);
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+                         store_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+                         store_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+                         store_pwm_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+                         store_pwm_enable, 3);
+static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+                         store_pwm_enable, 4);
+
+static SENSOR_DEVICE_ATTR(pwm1_temp_sel, S_IWUSR | S_IRUGO,
+                           show_pwm_temp_sel, store_pwm_temp_sel, 0);
+static SENSOR_DEVICE_ATTR(pwm2_temp_sel, S_IWUSR | S_IRUGO,
+                           show_pwm_temp_sel, store_pwm_temp_sel, 1);
+static SENSOR_DEVICE_ATTR(pwm3_temp_sel, S_IWUSR | S_IRUGO,
+                           show_pwm_temp_sel, store_pwm_temp_sel, 2);
+static SENSOR_DEVICE_ATTR(pwm4_temp_sel, S_IWUSR | S_IRUGO,
+                           show_pwm_temp_sel, store_pwm_temp_sel, 3);
+static SENSOR_DEVICE_ATTR(pwm5_temp_sel, S_IWUSR | S_IRUGO,
+                           show_pwm_temp_sel, store_pwm_temp_sel, 4);
+
+static SENSOR_DEVICE_ATTR(pwm1_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
+                         store_target_temp, 0);
+static SENSOR_DEVICE_ATTR(pwm2_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
+                         store_target_temp, 1);
+static SENSOR_DEVICE_ATTR(pwm3_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
+                         store_target_temp, 2);
+static SENSOR_DEVICE_ATTR(pwm4_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
+                         store_target_temp, 3);
+static SENSOR_DEVICE_ATTR(pwm5_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
+                         store_target_temp, 4);
+
+static SENSOR_DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, show_target_speed,
+                         store_target_speed, 0);
+static SENSOR_DEVICE_ATTR(fan2_target, S_IWUSR | S_IRUGO, show_target_speed,
+                         store_target_speed, 1);
+static SENSOR_DEVICE_ATTR(fan3_target, S_IWUSR | S_IRUGO, show_target_speed,
+                         store_target_speed, 2);
+static SENSOR_DEVICE_ATTR(fan4_target, S_IWUSR | S_IRUGO, show_target_speed,
+                         store_target_speed, 3);
+static SENSOR_DEVICE_ATTR(fan5_target, S_IWUSR | S_IRUGO, show_target_speed,
+                         store_target_speed, 4);
+
+static SENSOR_DEVICE_ATTR(fan1_tolerance, S_IWUSR | S_IRUGO,
+                           show_speed_tolerance, store_speed_tolerance, 0);
+static SENSOR_DEVICE_ATTR(fan2_tolerance, S_IWUSR | S_IRUGO,
+                           show_speed_tolerance, store_speed_tolerance, 1);
+static SENSOR_DEVICE_ATTR(fan3_tolerance, S_IWUSR | S_IRUGO,
+                           show_speed_tolerance, store_speed_tolerance, 2);
+static SENSOR_DEVICE_ATTR(fan4_tolerance, S_IWUSR | S_IRUGO,
+                           show_speed_tolerance, store_speed_tolerance, 3);
+static SENSOR_DEVICE_ATTR(fan5_tolerance, S_IWUSR | S_IRUGO,
+                           show_speed_tolerance, store_speed_tolerance, 4);
+
+/* Smart Fan registers */
+
+static ssize_t
+show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+
+       return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
+}
+
+static ssize_t
+store_weight_temp(struct device *dev, struct device_attribute *attr,
+                 const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+       unsigned long val;
+       int err;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
+
+       mutex_lock(&data->update_lock);
+       data->weight_temp[index][nr] = val;
+       nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_weight_temp_sel, S_IWUSR | S_IRUGO,
+                           show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
+                           0);
+static SENSOR_DEVICE_ATTR(pwm2_weight_temp_sel, S_IWUSR | S_IRUGO,
+                           show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
+                           1);
+static SENSOR_DEVICE_ATTR(pwm3_weight_temp_sel, S_IWUSR | S_IRUGO,
+                           show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
+                           2);
+static SENSOR_DEVICE_ATTR(pwm4_weight_temp_sel, S_IWUSR | S_IRUGO,
+                           show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
+                           3);
+static SENSOR_DEVICE_ATTR(pwm5_weight_temp_sel, S_IWUSR | S_IRUGO,
+                           show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
+                           4);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 4, 0);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 4, 1);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step_base, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step_base, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step_base, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step_base, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 3, 2);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step_base, S_IWUSR | S_IRUGO,
+                           show_weight_temp, store_weight_temp, 4, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_duty_step, S_IWUSR | S_IRUGO,
+                           show_pwm, store_pwm, 0, 5);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_duty_step, S_IWUSR | S_IRUGO,
+                           show_pwm, store_pwm, 1, 5);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_duty_step, S_IWUSR | S_IRUGO,
+                           show_pwm, store_pwm, 2, 5);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_duty_step, S_IWUSR | S_IRUGO,
+                           show_pwm, store_pwm, 3, 5);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_duty_step, S_IWUSR | S_IRUGO,
+                           show_pwm, store_pwm, 4, 5);
+
+/* duty_base is not supported on all chips */
+static struct sensor_device_attribute_2 sda_weight_duty_base[] = {
+       SENSOR_ATTR_2(pwm1_weight_duty_base, S_IWUSR | S_IRUGO,
+                     show_pwm, store_pwm, 0, 6),
+       SENSOR_ATTR_2(pwm2_weight_duty_base, S_IWUSR | S_IRUGO,
+                     show_pwm, store_pwm, 1, 6),
+       SENSOR_ATTR_2(pwm3_weight_duty_base, S_IWUSR | S_IRUGO,
+                     show_pwm, store_pwm, 2, 6),
+       SENSOR_ATTR_2(pwm4_weight_duty_base, S_IWUSR | S_IRUGO,
+                     show_pwm, store_pwm, 3, 6),
+       SENSOR_ATTR_2(pwm5_weight_duty_base, S_IWUSR | S_IRUGO,
+                     show_pwm, store_pwm, 4, 6),
+};
+
+static ssize_t
+show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+
+       return sprintf(buf, "%d\n",
+                      step_time_from_reg(data->fan_time[index][nr],
+                                         data->pwm_mode[nr]));
+}
+
+static ssize_t
+store_fan_time(struct device *dev, struct device_attribute *attr,
+              const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+       unsigned long val;
+       int err;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       val = step_time_to_reg(val, data->pwm_mode[nr]);
+       mutex_lock(&data->update_lock);
+       data->fan_time[index][nr] = val;
+       nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t
+show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", data->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+                           store_fan_time, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+                           store_fan_time, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+                           store_fan_time, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+                           store_fan_time, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+                           store_fan_time, 4, 0);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+                           store_fan_time, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+                           store_fan_time, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+                           store_fan_time, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+                           store_fan_time, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+                           store_fan_time, 4, 1);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_step_down_time, S_IWUSR | S_IRUGO,
+                           show_fan_time, store_fan_time, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_step_down_time, S_IWUSR | S_IRUGO,
+                           show_fan_time, store_fan_time, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_step_down_time, S_IWUSR | S_IRUGO,
+                           show_fan_time, store_fan_time, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm4_step_down_time, S_IWUSR | S_IRUGO,
+                           show_fan_time, store_fan_time, 3, 2);
+static SENSOR_DEVICE_ATTR_2(pwm5_step_down_time, S_IWUSR | S_IRUGO,
+                           show_fan_time, store_fan_time, 4, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_start, S_IWUSR | S_IRUGO, show_pwm,
+                           store_pwm, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_start, S_IWUSR | S_IRUGO, show_pwm,
+                           store_pwm, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_start, S_IWUSR | S_IRUGO, show_pwm,
+                           store_pwm, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_start, S_IWUSR | S_IRUGO, show_pwm,
+                           store_pwm, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_start, S_IWUSR | S_IRUGO, show_pwm,
+                           store_pwm, 4, 1);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_floor, S_IWUSR | S_IRUGO, show_pwm,
+                           store_pwm, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_floor, S_IWUSR | S_IRUGO, show_pwm,
+                           store_pwm, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_floor, S_IWUSR | S_IRUGO, show_pwm,
+                           store_pwm, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm4_floor, S_IWUSR | S_IRUGO, show_pwm,
+                           store_pwm, 3, 2);
+static SENSOR_DEVICE_ATTR_2(pwm5_floor, S_IWUSR | S_IRUGO, show_pwm,
+                           store_pwm, 4, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_temp_tolerance, S_IWUSR | S_IRUGO,
+                           show_temp_tolerance, store_temp_tolerance, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_temp_tolerance, S_IWUSR | S_IRUGO,
+                           show_temp_tolerance, store_temp_tolerance, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_temp_tolerance, S_IWUSR | S_IRUGO,
+                           show_temp_tolerance, store_temp_tolerance, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4_temp_tolerance, S_IWUSR | S_IRUGO,
+                           show_temp_tolerance, store_temp_tolerance, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5_temp_tolerance, S_IWUSR | S_IRUGO,
+                           show_temp_tolerance, store_temp_tolerance, 4, 0);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_crit_temp_tolerance, S_IWUSR | S_IRUGO,
+                           show_temp_tolerance, store_temp_tolerance, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_crit_temp_tolerance, S_IWUSR | S_IRUGO,
+                           show_temp_tolerance, store_temp_tolerance, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_crit_temp_tolerance, S_IWUSR | S_IRUGO,
+                           show_temp_tolerance, store_temp_tolerance, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_crit_temp_tolerance, S_IWUSR | S_IRUGO,
+                           show_temp_tolerance, store_temp_tolerance, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_crit_temp_tolerance, S_IWUSR | S_IRUGO,
+                           show_temp_tolerance, store_temp_tolerance, 4, 1);
+
+/* pwm_max is not supported on all chips */
+static struct sensor_device_attribute_2 sda_pwm_max[] = {
+       SENSOR_ATTR_2(pwm1_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+                     0, 3),
+       SENSOR_ATTR_2(pwm2_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+                     1, 3),
+       SENSOR_ATTR_2(pwm3_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+                     2, 3),
+       SENSOR_ATTR_2(pwm4_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+                     3, 3),
+       SENSOR_ATTR_2(pwm5_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+                     4, 3),
+};
+
+/* pwm_step is not supported on all chips */
+static struct sensor_device_attribute_2 sda_pwm_step[] = {
+       SENSOR_ATTR_2(pwm1_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 4),
+       SENSOR_ATTR_2(pwm2_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1, 4),
+       SENSOR_ATTR_2(pwm3_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2, 4),
+       SENSOR_ATTR_2(pwm4_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3, 4),
+       SENSOR_ATTR_2(pwm5_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4, 4),
+};
+
+static struct attribute *nct6775_attributes_pwm[5][20] = {
+       {
+               &sensor_dev_attr_pwm1.dev_attr.attr,
+               &sensor_dev_attr_pwm1_mode.dev_attr.attr,
+               &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+               &sensor_dev_attr_pwm1_temp_sel.dev_attr.attr,
+               &sensor_dev_attr_pwm1_temp_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm1_crit_temp_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm1_target_temp.dev_attr.attr,
+               &sensor_dev_attr_fan1_target.dev_attr.attr,
+               &sensor_dev_attr_fan1_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm1_stop_time.dev_attr.attr,
+               &sensor_dev_attr_pwm1_step_up_time.dev_attr.attr,
+               &sensor_dev_attr_pwm1_step_down_time.dev_attr.attr,
+               &sensor_dev_attr_pwm1_start.dev_attr.attr,
+               &sensor_dev_attr_pwm1_floor.dev_attr.attr,
+               &sensor_dev_attr_pwm1_weight_temp_sel.dev_attr.attr,
+               &sensor_dev_attr_pwm1_weight_temp_step.dev_attr.attr,
+               &sensor_dev_attr_pwm1_weight_temp_step_tol.dev_attr.attr,
+               &sensor_dev_attr_pwm1_weight_temp_step_base.dev_attr.attr,
+               &sensor_dev_attr_pwm1_weight_duty_step.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_pwm2.dev_attr.attr,
+               &sensor_dev_attr_pwm2_mode.dev_attr.attr,
+               &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+               &sensor_dev_attr_pwm2_temp_sel.dev_attr.attr,
+               &sensor_dev_attr_pwm2_temp_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm2_crit_temp_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm2_target_temp.dev_attr.attr,
+               &sensor_dev_attr_fan2_target.dev_attr.attr,
+               &sensor_dev_attr_fan2_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm2_stop_time.dev_attr.attr,
+               &sensor_dev_attr_pwm2_step_up_time.dev_attr.attr,
+               &sensor_dev_attr_pwm2_step_down_time.dev_attr.attr,
+               &sensor_dev_attr_pwm2_start.dev_attr.attr,
+               &sensor_dev_attr_pwm2_floor.dev_attr.attr,
+               &sensor_dev_attr_pwm2_weight_temp_sel.dev_attr.attr,
+               &sensor_dev_attr_pwm2_weight_temp_step.dev_attr.attr,
+               &sensor_dev_attr_pwm2_weight_temp_step_tol.dev_attr.attr,
+               &sensor_dev_attr_pwm2_weight_temp_step_base.dev_attr.attr,
+               &sensor_dev_attr_pwm2_weight_duty_step.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_pwm3.dev_attr.attr,
+               &sensor_dev_attr_pwm3_mode.dev_attr.attr,
+               &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+               &sensor_dev_attr_pwm3_temp_sel.dev_attr.attr,
+               &sensor_dev_attr_pwm3_temp_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm3_crit_temp_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm3_target_temp.dev_attr.attr,
+               &sensor_dev_attr_fan3_target.dev_attr.attr,
+               &sensor_dev_attr_fan3_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm3_stop_time.dev_attr.attr,
+               &sensor_dev_attr_pwm3_step_up_time.dev_attr.attr,
+               &sensor_dev_attr_pwm3_step_down_time.dev_attr.attr,
+               &sensor_dev_attr_pwm3_start.dev_attr.attr,
+               &sensor_dev_attr_pwm3_floor.dev_attr.attr,
+               &sensor_dev_attr_pwm3_weight_temp_sel.dev_attr.attr,
+               &sensor_dev_attr_pwm3_weight_temp_step.dev_attr.attr,
+               &sensor_dev_attr_pwm3_weight_temp_step_tol.dev_attr.attr,
+               &sensor_dev_attr_pwm3_weight_temp_step_base.dev_attr.attr,
+               &sensor_dev_attr_pwm3_weight_duty_step.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_pwm4.dev_attr.attr,
+               &sensor_dev_attr_pwm4_mode.dev_attr.attr,
+               &sensor_dev_attr_pwm4_enable.dev_attr.attr,
+               &sensor_dev_attr_pwm4_temp_sel.dev_attr.attr,
+               &sensor_dev_attr_pwm4_temp_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm4_crit_temp_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm4_target_temp.dev_attr.attr,
+               &sensor_dev_attr_fan4_target.dev_attr.attr,
+               &sensor_dev_attr_fan4_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm4_stop_time.dev_attr.attr,
+               &sensor_dev_attr_pwm4_step_up_time.dev_attr.attr,
+               &sensor_dev_attr_pwm4_step_down_time.dev_attr.attr,
+               &sensor_dev_attr_pwm4_start.dev_attr.attr,
+               &sensor_dev_attr_pwm4_floor.dev_attr.attr,
+               &sensor_dev_attr_pwm4_weight_temp_sel.dev_attr.attr,
+               &sensor_dev_attr_pwm4_weight_temp_step.dev_attr.attr,
+               &sensor_dev_attr_pwm4_weight_temp_step_tol.dev_attr.attr,
+               &sensor_dev_attr_pwm4_weight_temp_step_base.dev_attr.attr,
+               &sensor_dev_attr_pwm4_weight_duty_step.dev_attr.attr,
+               NULL
+       },
+       {
+               &sensor_dev_attr_pwm5.dev_attr.attr,
+               &sensor_dev_attr_pwm5_mode.dev_attr.attr,
+               &sensor_dev_attr_pwm5_enable.dev_attr.attr,
+               &sensor_dev_attr_pwm5_temp_sel.dev_attr.attr,
+               &sensor_dev_attr_pwm5_temp_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm5_crit_temp_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm5_target_temp.dev_attr.attr,
+               &sensor_dev_attr_fan5_target.dev_attr.attr,
+               &sensor_dev_attr_fan5_tolerance.dev_attr.attr,
+               &sensor_dev_attr_pwm5_stop_time.dev_attr.attr,
+               &sensor_dev_attr_pwm5_step_up_time.dev_attr.attr,
+               &sensor_dev_attr_pwm5_step_down_time.dev_attr.attr,
+               &sensor_dev_attr_pwm5_start.dev_attr.attr,
+               &sensor_dev_attr_pwm5_floor.dev_attr.attr,
+               &sensor_dev_attr_pwm5_weight_temp_sel.dev_attr.attr,
+               &sensor_dev_attr_pwm5_weight_temp_step.dev_attr.attr,
+               &sensor_dev_attr_pwm5_weight_temp_step_tol.dev_attr.attr,
+               &sensor_dev_attr_pwm5_weight_temp_step_base.dev_attr.attr,
+               &sensor_dev_attr_pwm5_weight_duty_step.dev_attr.attr,
+               NULL
+       },
+};
+
+static const struct attribute_group nct6775_group_pwm[5] = {
+       { .attrs = nct6775_attributes_pwm[0] },
+       { .attrs = nct6775_attributes_pwm[1] },
+       { .attrs = nct6775_attributes_pwm[2] },
+       { .attrs = nct6775_attributes_pwm[3] },
+       { .attrs = nct6775_attributes_pwm[4] },
+};
+
+static ssize_t
+show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+       return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
+}
+
+static ssize_t
+store_auto_pwm(struct device *dev, struct device_attribute *attr,
+              const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int point = sattr->index;
+       unsigned long val;
+       int err;
+       u8 reg;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+       if (val > 255)
+               return -EINVAL;
+
+       if (point == data->auto_pwm_num) {
+               if (data->kind != nct6775 && !val)
+                       return -EINVAL;
+               if (data->kind != nct6779 && val)
+                       val = 0xff;
+       }
+
+       mutex_lock(&data->update_lock);
+       data->auto_pwm[nr][point] = val;
+       if (point < data->auto_pwm_num) {
+               nct6775_write_value(data,
+                                   NCT6775_AUTO_PWM(data, nr, point),
+                                   data->auto_pwm[nr][point]);
+       } else {
+               switch (data->kind) {
+               case nct6775:
+                       /* disable if needed (pwm == 0) */
+                       reg = nct6775_read_value(data,
+                                                NCT6775_REG_CRITICAL_ENAB[nr]);
+                       if (val)
+                               reg |= 0x02;
+                       else
+                               reg &= ~0x02;
+                       nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
+                                           reg);
+                       break;
+               case nct6776:
+                       break; /* always enabled, nothing to do */
+               case nct6779:
+                       nct6775_write_value(data, NCT6779_REG_CRITICAL_PWM[nr],
+                                           val);
+                       reg = nct6775_read_value(data,
+                                       NCT6779_REG_CRITICAL_PWM_ENABLE[nr]);
+                       if (val == 255)
+                               reg &= ~0x01;
+                       else
+                               reg |= 0x01;
+                       nct6775_write_value(data,
+                                           NCT6779_REG_CRITICAL_PWM_ENABLE[nr],
+                                           reg);
+                       break;
+               }
+       }
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t
+show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int point = sattr->index;
+
+       /*
+        * We don't know for sure if the temperature is signed or unsigned.
+        * Assume it is unsigned.
+        */
+       return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
+}
+
+static ssize_t
+store_auto_temp(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int point = sattr->index;
+       unsigned long val;
+       int err;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err)
+               return err;
+       if (val > 255000)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
+       if (point < data->auto_pwm_num) {
+               nct6775_write_value(data,
+                                   NCT6775_AUTO_TEMP(data, nr, point),
+                                   data->auto_temp[nr][point]);
+       } else {
+               nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
+                                   data->auto_temp[nr][point]);
+       }
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+/*
+ * The number of auto-point trip points is chip dependent.
+ * Need to check support while generating/removing attribute files.
+ */
+static struct sensor_device_attribute_2 sda_auto_pwm_arrays[] = {
+       SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 0, 0),
+       SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 0, 0),
+       SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 0, 1),
+       SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 0, 1),
+       SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 0, 2),
+       SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 0, 2),
+       SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 0, 3),
+       SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 0, 3),
+       SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 0, 4),
+       SENSOR_ATTR_2(pwm1_auto_point5_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 0, 4),
+       SENSOR_ATTR_2(pwm1_auto_point6_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 0, 5),
+       SENSOR_ATTR_2(pwm1_auto_point6_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 0, 5),
+       SENSOR_ATTR_2(pwm1_auto_point7_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 0, 6),
+       SENSOR_ATTR_2(pwm1_auto_point7_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 0, 6),
+
+       SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 1, 0),
+       SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 1, 0),
+       SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 1, 1),
+       SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 1, 1),
+       SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 1, 2),
+       SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 1, 2),
+       SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 1, 3),
+       SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 1, 3),
+       SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 1, 4),
+       SENSOR_ATTR_2(pwm2_auto_point5_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 1, 4),
+       SENSOR_ATTR_2(pwm2_auto_point6_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 1, 5),
+       SENSOR_ATTR_2(pwm2_auto_point6_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 1, 5),
+       SENSOR_ATTR_2(pwm2_auto_point7_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 1, 6),
+       SENSOR_ATTR_2(pwm2_auto_point7_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 1, 6),
+
+       SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 2, 0),
+       SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 2, 0),
+       SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 2, 1),
+       SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 2, 1),
+       SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 2, 2),
+       SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 2, 2),
+       SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 2, 3),
+       SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 2, 3),
+       SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 2, 4),
+       SENSOR_ATTR_2(pwm3_auto_point5_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 2, 4),
+       SENSOR_ATTR_2(pwm3_auto_point6_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 2, 5),
+       SENSOR_ATTR_2(pwm3_auto_point6_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 2, 5),
+       SENSOR_ATTR_2(pwm3_auto_point7_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 2, 6),
+       SENSOR_ATTR_2(pwm3_auto_point7_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 2, 6),
+
+       SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 3, 0),
+       SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 3, 0),
+       SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 3, 1),
+       SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 3, 1),
+       SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 3, 2),
+       SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 3, 2),
+       SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 3, 3),
+       SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 3, 3),
+       SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 3, 4),
+       SENSOR_ATTR_2(pwm4_auto_point5_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 3, 4),
+       SENSOR_ATTR_2(pwm4_auto_point6_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 3, 5),
+       SENSOR_ATTR_2(pwm4_auto_point6_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 3, 5),
+       SENSOR_ATTR_2(pwm4_auto_point7_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 3, 6),
+       SENSOR_ATTR_2(pwm4_auto_point7_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 3, 6),
+
+       SENSOR_ATTR_2(pwm5_auto_point1_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 4, 0),
+       SENSOR_ATTR_2(pwm5_auto_point1_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 4, 0),
+       SENSOR_ATTR_2(pwm5_auto_point2_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 4, 1),
+       SENSOR_ATTR_2(pwm5_auto_point2_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 4, 1),
+       SENSOR_ATTR_2(pwm5_auto_point3_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 4, 2),
+       SENSOR_ATTR_2(pwm5_auto_point3_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 4, 2),
+       SENSOR_ATTR_2(pwm5_auto_point4_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 4, 3),
+       SENSOR_ATTR_2(pwm5_auto_point4_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 4, 3),
+       SENSOR_ATTR_2(pwm5_auto_point5_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 4, 4),
+       SENSOR_ATTR_2(pwm5_auto_point5_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 4, 4),
+       SENSOR_ATTR_2(pwm5_auto_point6_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 4, 5),
+       SENSOR_ATTR_2(pwm5_auto_point6_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 4, 5),
+       SENSOR_ATTR_2(pwm5_auto_point7_pwm, S_IWUSR | S_IRUGO,
+                     show_auto_pwm, store_auto_pwm, 4, 6),
+       SENSOR_ATTR_2(pwm5_auto_point7_temp, S_IWUSR | S_IRUGO,
+                     show_auto_temp, store_auto_temp, 4, 6),
+};
+
+static ssize_t
+show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+/* Case open detection */
+
+static ssize_t
+clear_caseopen(struct device *dev, struct device_attribute *attr,
+              const char *buf, size_t count)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct nct6775_sio_data *sio_data = dev->platform_data;
+       int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
+       unsigned long val;
+       u8 reg;
+       int ret;
+
+       if (kstrtoul(buf, 10, &val) || val != 0)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+
+       /*
+        * Use CR registers to clear caseopen status.
+        * The CR registers are the same for all chips, and not all chips
+        * support clearing the caseopen status through "regular" registers.
+        */
+       ret = superio_enter(sio_data->sioreg);
+       if (ret) {
+               count = ret;
+               goto error;
+       }
+
+       superio_select(sio_data->sioreg, NCT6775_LD_ACPI);
+       reg = superio_inb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
+       reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
+       superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+       reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
+       superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+       superio_exit(sio_data->sioreg);
+
+       data->valid = false;    /* Force cache refresh */
+error:
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static struct sensor_device_attribute sda_caseopen[] = {
+       SENSOR_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
+                   clear_caseopen, INTRUSION_ALARM_BASE),
+       SENSOR_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
+                   clear_caseopen, INTRUSION_ALARM_BASE + 1),
+};
+
+/*
+ * Driver and device management
+ */
+
+static void nct6775_device_remove_files(struct device *dev)
+{
+       /*
+        * some entries in the following arrays may not have been used in
+        * device_create_file(), but device_remove_file() will ignore them
+        */
+       int i;
+       struct nct6775_data *data = dev_get_drvdata(dev);
+
+       for (i = 0; i < data->pwm_num; i++)
+               sysfs_remove_group(&dev->kobj, &nct6775_group_pwm[i]);
+
+       for (i = 0; i < ARRAY_SIZE(sda_pwm_max); i++)
+               device_remove_file(dev, &sda_pwm_max[i].dev_attr);
+
+       for (i = 0; i < ARRAY_SIZE(sda_pwm_step); i++)
+               device_remove_file(dev, &sda_pwm_step[i].dev_attr);
+
+       for (i = 0; i < ARRAY_SIZE(sda_weight_duty_base); i++)
+               device_remove_file(dev, &sda_weight_duty_base[i].dev_attr);
+
+       for (i = 0; i < ARRAY_SIZE(sda_auto_pwm_arrays); i++)
+               device_remove_file(dev, &sda_auto_pwm_arrays[i].dev_attr);
+
+       for (i = 0; i < data->in_num; i++)
+               sysfs_remove_group(&dev->kobj, &nct6775_group_in[i]);
+
+       for (i = 0; i < 5; i++) {
+               device_remove_file(dev, &sda_fan_input[i].dev_attr);
+               device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
+               device_remove_file(dev, &sda_fan_div[i].dev_attr);
+               device_remove_file(dev, &sda_fan_min[i].dev_attr);
+               device_remove_file(dev, &sda_fan_pulses[i].dev_attr);
+       }
+       for (i = 0; i < NUM_TEMP; i++) {
+               if (!(data->have_temp & (1 << i)))
+                       continue;
+               device_remove_file(dev, &sda_temp_input[i].dev_attr);
+               device_remove_file(dev, &sda_temp_label[i].dev_attr);
+               device_remove_file(dev, &sda_temp_max[i].dev_attr);
+               device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
+               device_remove_file(dev, &sda_temp_crit[i].dev_attr);
+               if (!(data->have_temp_fixed & (1 << i)))
+                       continue;
+               device_remove_file(dev, &sda_temp_type[i].dev_attr);
+               device_remove_file(dev, &sda_temp_offset[i].dev_attr);
+               if (i >= NUM_TEMP_ALARM)
+                       continue;
+               device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
+       }
+
+       device_remove_file(dev, &sda_caseopen[0].dev_attr);
+       device_remove_file(dev, &sda_caseopen[1].dev_attr);
+
+       device_remove_file(dev, &dev_attr_name);
+       device_remove_file(dev, &dev_attr_cpu0_vid);
+}
+
+/* Get the monitoring functions started */
+static inline void nct6775_init_device(struct nct6775_data *data)
+{
+       int i;
+       u8 tmp, diode;
+
+       /* Start monitoring if needed */
+       if (data->REG_CONFIG) {
+               tmp = nct6775_read_value(data, data->REG_CONFIG);
+               if (!(tmp & 0x01))
+                       nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
+       }
+
+       /* Enable temperature sensors if needed */
+       for (i = 0; i < NUM_TEMP; i++) {
+               if (!(data->have_temp & (1 << i)))
+                       continue;
+               if (!data->reg_temp_config[i])
+                       continue;
+               tmp = nct6775_read_value(data, data->reg_temp_config[i]);
+               if (tmp & 0x01)
+                       nct6775_write_value(data, data->reg_temp_config[i],
+                                           tmp & 0xfe);
+       }
+
+       /* Enable VBAT monitoring if needed */
+       tmp = nct6775_read_value(data, data->REG_VBAT);
+       if (!(tmp & 0x01))
+               nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
+
+       diode = nct6775_read_value(data, data->REG_DIODE);
+
+       for (i = 0; i < data->temp_fixed_num; i++) {
+               if (!(data->have_temp_fixed & (1 << i)))
+                       continue;
+               if ((tmp & (0x02 << i)))        /* diode */
+                       data->temp_type[i] = 3 - ((diode >> i) & 0x02);
+               else                            /* thermistor */
+                       data->temp_type[i] = 4;
+       }
+}
+
+static int
+nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data,
+                        struct nct6775_data *data)
+{
+       int regval;
+       bool fan3pin, fan3min, fan4pin, fan4min, fan5pin;
+       bool pwm3pin, pwm4pin, pwm5pin;
+       int ret;
+
+       ret = superio_enter(sio_data->sioreg);
+       if (ret)
+               return ret;
+
+       /* fan4 and fan5 share some pins with the GPIO and serial flash */
+       if (data->kind == nct6775) {
+               regval = superio_inb(sio_data->sioreg, 0x2c);
+
+               fan3pin = regval & (1 << 6);
+               fan3min = fan3pin;
+               pwm3pin = regval & (1 << 7);
+
+               /* On NCT6775, fan4 shares pins with the fdc interface */
+               fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
+               fan4min = 0;
+               fan5pin = 0;
+               pwm4pin = 0;
+               pwm5pin = 0;
+       } else if (data->kind == nct6776) {
+               bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80;
+
+               superio_select(sio_data->sioreg, NCT6775_LD_HWM);
+               regval = superio_inb(sio_data->sioreg, SIO_REG_ENABLE);
+
+               if (regval & 0x80)
+                       fan3pin = gpok;
+               else
+                       fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
+
+               if (regval & 0x40)
+                       fan4pin = gpok;
+               else
+                       fan4pin = superio_inb(sio_data->sioreg, 0x1C) & 0x01;
+
+               if (regval & 0x20)
+                       fan5pin = gpok;
+               else
+                       fan5pin = superio_inb(sio_data->sioreg, 0x1C) & 0x02;
+
+               fan4min = fan4pin;
+               fan3min = fan3pin;
+               pwm3pin = fan3pin;
+               pwm4pin = 0;
+               pwm5pin = 0;
+       } else {        /* NCT6779D */
+               regval = superio_inb(sio_data->sioreg, 0x1c);
+
+               fan3pin = !(regval & (1 << 5));
+               fan4pin = !(regval & (1 << 6));
+               fan5pin = !(regval & (1 << 7));
+
+               pwm3pin = !(regval & (1 << 0));
+               pwm4pin = !(regval & (1 << 1));
+               pwm5pin = !(regval & (1 << 2));
+
+               fan3min = fan3pin;
+               fan4min = fan4pin;
+       }
+
+       superio_exit(sio_data->sioreg);
+
+       data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
+       data->has_fan |= fan3pin << 2;
+       data->has_fan_min |= fan3min << 2;
+
+       data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
+       data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
+
+       data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) | (pwm5pin << 4);
+
+       return 0;
+}
+
+static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
+                            int *available, int *mask)
+{
+       int i;
+       u8 src;
+
+       for (i = 0; i < data->pwm_num && *available; i++) {
+               int index;
+
+               if (!regp[i])
+                       continue;
+               src = nct6775_read_value(data, regp[i]);
+               src &= 0x1f;
+               if (!src || (*mask & (1 << src)))
+                       continue;
+               if (src >= data->temp_label_num ||
+                   !strlen(data->temp_label[src]))
+                       continue;
+
+               index = __ffs(*available);
+               nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
+               *available &= ~(1 << index);
+               *mask |= 1 << src;
+       }
+}
+
+static int nct6775_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct nct6775_sio_data *sio_data = dev->platform_data;
+       struct nct6775_data *data;
+       struct resource *res;
+       int i, s, err = 0;
+       int src, mask, available;
+       const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
+       const u16 *reg_temp_alternate, *reg_temp_crit;
+       int num_reg_temp;
+       bool have_vid = false;
+       u8 cr2a;
+
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
+                                DRVNAME))
+               return -EBUSY;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->kind = sio_data->kind;
+       data->addr = res->start;
+       mutex_init(&data->update_lock);
+       data->name = nct6775_device_names[data->kind];
+       data->bank = 0xff;              /* Force initial bank selection */
+       platform_set_drvdata(pdev, data);
+
+       switch (data->kind) {
+       case nct6775:
+               data->in_num = 9;
+               data->pwm_num = 3;
+               data->auto_pwm_num = 6;
+               data->has_fan_div = true;
+               data->temp_fixed_num = 3;
+
+               data->ALARM_BITS = NCT6775_ALARM_BITS;
+
+               data->fan_from_reg = fan_from_reg16;
+               data->fan_from_reg_min = fan_from_reg8;
+               data->target_temp_mask = 0x7f;
+               data->tolerance_mask = 0x0f;
+               data->speed_tolerance_limit = 15;
+
+               data->temp_label = nct6775_temp_label;
+               data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
+
+               data->REG_CONFIG = NCT6775_REG_CONFIG;
+               data->REG_VBAT = NCT6775_REG_VBAT;
+               data->REG_DIODE = NCT6775_REG_DIODE;
+               data->REG_VIN = NCT6775_REG_IN;
+               data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+               data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+               data->REG_TARGET = NCT6775_REG_TARGET;
+               data->REG_FAN = NCT6775_REG_FAN;
+               data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+               data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
+               data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
+               data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+               data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+               data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+               data->REG_PWM[0] = NCT6775_REG_PWM;
+               data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+               data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+               data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
+               data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
+               data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+               data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+               data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
+               data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
+               data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+               data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+               data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+               data->REG_CRITICAL_TEMP_TOLERANCE
+                 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+               data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
+               data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+               data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+               data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
+               data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+               data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+               data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+               data->REG_ALARM = NCT6775_REG_ALARM;
+
+               reg_temp = NCT6775_REG_TEMP;
+               num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
+               reg_temp_over = NCT6775_REG_TEMP_OVER;
+               reg_temp_hyst = NCT6775_REG_TEMP_HYST;
+               reg_temp_config = NCT6775_REG_TEMP_CONFIG;
+               reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
+               reg_temp_crit = NCT6775_REG_TEMP_CRIT;
+
+               break;
+       case nct6776:
+               data->in_num = 9;
+               data->pwm_num = 3;
+               data->auto_pwm_num = 4;
+               data->has_fan_div = false;
+               data->temp_fixed_num = 3;
+
+               data->ALARM_BITS = NCT6776_ALARM_BITS;
+
+               data->fan_from_reg = fan_from_reg13;
+               data->fan_from_reg_min = fan_from_reg13;
+               data->target_temp_mask = 0xff;
+               data->tolerance_mask = 0x07;
+               data->speed_tolerance_limit = 63;
+
+               data->temp_label = nct6776_temp_label;
+               data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
+
+               data->REG_CONFIG = NCT6775_REG_CONFIG;
+               data->REG_VBAT = NCT6775_REG_VBAT;
+               data->REG_DIODE = NCT6775_REG_DIODE;
+               data->REG_VIN = NCT6775_REG_IN;
+               data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+               data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+               data->REG_TARGET = NCT6775_REG_TARGET;
+               data->REG_FAN = NCT6775_REG_FAN;
+               data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+               data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+               data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
+               data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+               data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+               data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+               data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
+               data->REG_PWM[0] = NCT6775_REG_PWM;
+               data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+               data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+               data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+               data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
+               data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+               data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+               data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+               data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+               data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+               data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+               data->REG_CRITICAL_TEMP_TOLERANCE
+                 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+               data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
+               data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+               data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+               data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
+               data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+               data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+               data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+               data->REG_ALARM = NCT6775_REG_ALARM;
+
+               reg_temp = NCT6775_REG_TEMP;
+               num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
+               reg_temp_over = NCT6775_REG_TEMP_OVER;
+               reg_temp_hyst = NCT6775_REG_TEMP_HYST;
+               reg_temp_config = NCT6776_REG_TEMP_CONFIG;
+               reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
+               reg_temp_crit = NCT6776_REG_TEMP_CRIT;
+
+               break;
+       case nct6779:
+               data->in_num = 15;
+               data->pwm_num = 5;
+               data->auto_pwm_num = 4;
+               data->has_fan_div = false;
+               data->temp_fixed_num = 6;
+
+               data->ALARM_BITS = NCT6779_ALARM_BITS;
+
+               data->fan_from_reg = fan_from_reg13;
+               data->fan_from_reg_min = fan_from_reg13;
+               data->target_temp_mask = 0xff;
+               data->tolerance_mask = 0x07;
+               data->speed_tolerance_limit = 63;
+
+               data->temp_label = nct6779_temp_label;
+               data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
+
+               data->REG_CONFIG = NCT6775_REG_CONFIG;
+               data->REG_VBAT = NCT6775_REG_VBAT;
+               data->REG_DIODE = NCT6775_REG_DIODE;
+               data->REG_VIN = NCT6779_REG_IN;
+               data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+               data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+               data->REG_TARGET = NCT6775_REG_TARGET;
+               data->REG_FAN = NCT6779_REG_FAN;
+               data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+               data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+               data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
+               data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+               data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+               data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+               data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
+               data->REG_PWM[0] = NCT6775_REG_PWM;
+               data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+               data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+               data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+               data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
+               data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+               data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+               data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+               data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+               data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+               data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+               data->REG_CRITICAL_TEMP_TOLERANCE
+                 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+               data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
+               data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+               data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+               data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
+               data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+               data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+               data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+               data->REG_ALARM = NCT6779_REG_ALARM;
+
+               reg_temp = NCT6779_REG_TEMP;
+               num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
+               reg_temp_over = NCT6779_REG_TEMP_OVER;
+               reg_temp_hyst = NCT6779_REG_TEMP_HYST;
+               reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+               reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
+               reg_temp_crit = NCT6779_REG_TEMP_CRIT;
+
+               break;
+       default:
+               return -ENODEV;
+       }
+       data->have_in = (1 << data->in_num) - 1;
+       data->have_temp = 0;
+
+       /*
+        * On some boards, not all available temperature sources are monitored,
+        * even though some of the monitoring registers are unused.
+        * Get list of unused monitoring registers, then detect if any fan
+        * controls are configured to use unmonitored temperature sources.
+        * If so, assign the unmonitored temperature sources to available
+        * monitoring registers.
+        */
+       mask = 0;
+       available = 0;
+       for (i = 0; i < num_reg_temp; i++) {
+               if (reg_temp[i] == 0)
+                       continue;
+
+               src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
+               if (!src || (mask & (1 << src)))
+                       available |= 1 << i;
+
+               mask |= 1 << src;
+       }
+
+       /*
+        * Now find unmonitored temperature registers and enable monitoring
+        * if additional monitoring registers are available.
+        */
+       add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
+       add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
+
+       mask = 0;
+       s = NUM_TEMP_FIXED;     /* First dynamic temperature attribute */
+       for (i = 0; i < num_reg_temp; i++) {
+               if (reg_temp[i] == 0)
+                       continue;
+
+               src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
+               if (!src || (mask & (1 << src)))
+                       continue;
+
+               if (src >= data->temp_label_num ||
+                   !strlen(data->temp_label[src])) {
+                       dev_info(dev,
+                                "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
+                                src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
+                       continue;
+               }
+
+               mask |= 1 << src;
+
+               /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
+               if (src <= data->temp_fixed_num) {
+                       data->have_temp |= 1 << (src - 1);
+                       data->have_temp_fixed |= 1 << (src - 1);
+                       data->reg_temp[0][src - 1] = reg_temp[i];
+                       data->reg_temp[1][src - 1] = reg_temp_over[i];
+                       data->reg_temp[2][src - 1] = reg_temp_hyst[i];
+                       data->reg_temp_config[src - 1] = reg_temp_config[i];
+                       data->temp_src[src - 1] = src;
+                       continue;
+               }
+
+               if (s >= NUM_TEMP)
+                       continue;
+
+               /* Use dynamic index for other sources */
+               data->have_temp |= 1 << s;
+               data->reg_temp[0][s] = reg_temp[i];
+               data->reg_temp[1][s] = reg_temp_over[i];
+               data->reg_temp[2][s] = reg_temp_hyst[i];
+               data->reg_temp_config[s] = reg_temp_config[i];
+               if (reg_temp_crit[src - 1])
+                       data->reg_temp[3][s] = reg_temp_crit[src - 1];
+
+               data->temp_src[s] = src;
+               s++;
+       }
+
+#ifdef USE_ALTERNATE
+       /*
+        * Go through the list of alternate temp registers and enable
+        * if possible.
+        * The temperature is already monitored if the respective bit in <mask>
+        * is set.
+        */
+       for (i = 0; i < data->temp_label_num - 1; i++) {
+               if (!reg_temp_alternate[i])
+                       continue;
+               if (mask & (1 << (i + 1)))
+                       continue;
+               if (i < data->temp_fixed_num) {
+                       if (data->have_temp & (1 << i))
+                               continue;
+                       data->have_temp |= 1 << i;
+                       data->have_temp_fixed |= 1 << i;
+                       data->reg_temp[0][i] = reg_temp_alternate[i];
+                       data->reg_temp[1][i] = reg_temp_over[i];
+                       data->reg_temp[2][i] = reg_temp_hyst[i];
+                       data->temp_src[i] = i + 1;
+                       continue;
+               }
+
+               if (s >= NUM_TEMP)      /* Abort if no more space */
+                       break;
+
+               data->have_temp |= 1 << s;
+               data->reg_temp[0][s] = reg_temp_alternate[i];
+               data->temp_src[s] = i + 1;
+               s++;
+       }
+#endif /* USE_ALTERNATE */
+
+       /* Initialize the chip */
+       nct6775_init_device(data);
+
+       err = superio_enter(sio_data->sioreg);
+       if (err)
+               return err;
+
+       cr2a = superio_inb(sio_data->sioreg, 0x2a);
+       switch (data->kind) {
+       case nct6775:
+               have_vid = (cr2a & 0x40);
+               break;
+       case nct6776:
+               have_vid = (cr2a & 0x60) == 0x40;
+               break;
+       case nct6779:
+               break;
+       }
+
+       /*
+        * Read VID value
+        * We can get the VID input values directly at logical device D 0xe3.
+        */
+       if (have_vid) {
+               superio_select(sio_data->sioreg, NCT6775_LD_VID);
+               data->vid = superio_inb(sio_data->sioreg, 0xe3);
+               data->vrm = vid_which_vrm();
+       }
+
+       if (fan_debounce) {
+               u8 tmp;
+
+               superio_select(sio_data->sioreg, NCT6775_LD_HWM);
+               tmp = superio_inb(sio_data->sioreg,
+                                 NCT6775_REG_CR_FAN_DEBOUNCE);
+               switch (data->kind) {
+               case nct6775:
+                       tmp |= 0x1e;
+                       break;
+               case nct6776:
+               case nct6779:
+                       tmp |= 0x3e;
+                       break;
+               }
+               superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
+                            tmp);
+               dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
+                        data->name);
+       }
+
+       superio_exit(sio_data->sioreg);
+
+       if (have_vid) {
+               err = device_create_file(dev, &dev_attr_cpu0_vid);
+               if (err)
+                       return err;
+       }
+
+       err = nct6775_check_fan_inputs(sio_data, data);
+       if (err)
+               goto exit_remove;
+
+       /* Read fan clock dividers immediately */
+       nct6775_init_fan_common(dev, data);
+
+       /* Register sysfs hooks */
+       for (i = 0; i < data->pwm_num; i++) {
+               if (!(data->has_pwm & (1 << i)))
+                       continue;
+
+               err = sysfs_create_group(&dev->kobj, &nct6775_group_pwm[i]);
+               if (err)
+                       goto exit_remove;
+
+               if (data->REG_PWM[3]) {
+                       err = device_create_file(dev,
+                                       &sda_pwm_max[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+               }
+               if (data->REG_PWM[4]) {
+                       err = device_create_file(dev,
+                                       &sda_pwm_step[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+               }
+               if (data->REG_PWM[6]) {
+                       err = device_create_file(dev,
+                                       &sda_weight_duty_base[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+               }
+       }
+       for (i = 0; i < ARRAY_SIZE(sda_auto_pwm_arrays); i++) {
+               struct sensor_device_attribute_2 *attr =
+                       &sda_auto_pwm_arrays[i];
+
+               if (!(data->has_pwm & (1 << attr->nr)))
+                       continue;
+               if (attr->index > data->auto_pwm_num)
+                       continue;
+               err = device_create_file(dev, &attr->dev_attr);
+               if (err)
+                       goto exit_remove;
+       }
+
+       for (i = 0; i < data->in_num; i++) {
+               if (!(data->have_in & (1 << i)))
+                       continue;
+               err = sysfs_create_group(&dev->kobj, &nct6775_group_in[i]);
+               if (err)
+                       goto exit_remove;
+       }
+
+       for (i = 0; i < 5; i++) {
+               if (data->has_fan & (1 << i)) {
+                       err = device_create_file(dev,
+                                                &sda_fan_input[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+                       err = device_create_file(dev,
+                                                &sda_fan_alarm[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+                       if (data->kind != nct6776 &&
+                           data->kind != nct6779) {
+                               err = device_create_file(dev,
+                                               &sda_fan_div[i].dev_attr);
+                               if (err)
+                                       goto exit_remove;
+                       }
+                       if (data->has_fan_min & (1 << i)) {
+                               err = device_create_file(dev,
+                                               &sda_fan_min[i].dev_attr);
+                               if (err)
+                                       goto exit_remove;
+                       }
+                       err = device_create_file(dev,
+                                               &sda_fan_pulses[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+               }
+       }
+
+       for (i = 0; i < NUM_TEMP; i++) {
+               if (!(data->have_temp & (1 << i)))
+                       continue;
+               err = device_create_file(dev, &sda_temp_input[i].dev_attr);
+               if (err)
+                       goto exit_remove;
+               if (data->temp_label) {
+                       err = device_create_file(dev,
+                                                &sda_temp_label[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+               }
+               if (data->reg_temp[1][i]) {
+                       err = device_create_file(dev,
+                                                &sda_temp_max[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+               }
+               if (data->reg_temp[2][i]) {
+                       err = device_create_file(dev,
+                                       &sda_temp_max_hyst[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+               }
+               if (data->reg_temp[3][i]) {
+                       err = device_create_file(dev,
+                                                &sda_temp_crit[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+               }
+               if (!(data->have_temp_fixed & (1 << i)))
+                       continue;
+               err = device_create_file(dev, &sda_temp_type[i].dev_attr);
+               if (err)
+                       goto exit_remove;
+               err = device_create_file(dev, &sda_temp_offset[i].dev_attr);
+               if (err)
+                       goto exit_remove;
+               if (i >= NUM_TEMP_ALARM ||
+                   data->ALARM_BITS[TEMP_ALARM_BASE + i] < 0)
+                       continue;
+               err = device_create_file(dev, &sda_temp_alarm[i].dev_attr);
+               if (err)
+                       goto exit_remove;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(sda_caseopen); i++) {
+               if (data->ALARM_BITS[INTRUSION_ALARM_BASE + i] < 0)
+                       continue;
+               err = device_create_file(dev, &sda_caseopen[i].dev_attr);
+               if (err)
+                       goto exit_remove;
+       }
+
+       err = device_create_file(dev, &dev_attr_name);
+       if (err)
+               goto exit_remove;
+
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove;
+       }
+
+       return 0;
+
+exit_remove:
+       nct6775_device_remove_files(dev);
+       return err;
+}
+
+static int nct6775_remove(struct platform_device *pdev)
+{
+       struct nct6775_data *data = platform_get_drvdata(pdev);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       nct6775_device_remove_files(&pdev->dev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int nct6775_suspend(struct device *dev)
+{
+       struct nct6775_data *data = nct6775_update_device(dev);
+       struct nct6775_sio_data *sio_data = dev->platform_data;
+
+       mutex_lock(&data->update_lock);
+       data->vbat = nct6775_read_value(data, data->REG_VBAT);
+       if (sio_data->kind == nct6775) {
+               data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
+               data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
+       }
+       mutex_unlock(&data->update_lock);
+
+       return 0;
+}
+
+static int nct6775_resume(struct device *dev)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       struct nct6775_sio_data *sio_data = dev->platform_data;
+       int i, j;
+
+       mutex_lock(&data->update_lock);
+       data->bank = 0xff;              /* Force initial bank selection */
+
+       /* Restore limits */
+       for (i = 0; i < data->in_num; i++) {
+               if (!(data->have_in & (1 << i)))
+                       continue;
+
+               nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
+                                   data->in[i][1]);
+               nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
+                                   data->in[i][2]);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
+               if (!(data->has_fan_min & (1 << i)))
+                       continue;
+
+               nct6775_write_value(data, data->REG_FAN_MIN[i],
+                                   data->fan_min[i]);
+       }
+
+       for (i = 0; i < NUM_TEMP; i++) {
+               if (!(data->have_temp & (1 << i)))
+                       continue;
+
+               for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
+                       if (data->reg_temp[j][i])
+                               nct6775_write_temp(data, data->reg_temp[j][i],
+                                                  data->temp[j][i]);
+       }
+
+       /* Restore other settings */
+       nct6775_write_value(data, data->REG_VBAT, data->vbat);
+       if (sio_data->kind == nct6775) {
+               nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
+               nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
+       }
+
+       /* Force re-reading all values */
+       data->valid = false;
+       mutex_unlock(&data->update_lock);
+
+       return 0;
+}
+
+static const struct dev_pm_ops nct6775_dev_pm_ops = {
+       .suspend = nct6775_suspend,
+       .resume = nct6775_resume,
+};
+
+#define NCT6775_DEV_PM_OPS     (&nct6775_dev_pm_ops)
+#else
+#define NCT6775_DEV_PM_OPS     NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver nct6775_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = DRVNAME,
+               .pm     = NCT6775_DEV_PM_OPS,
+       },
+       .probe          = nct6775_probe,
+       .remove         = nct6775_remove,
+};
+
+static const char * const nct6775_sio_names[] __initconst = {
+       "NCT6775F",
+       "NCT6776D/F",
+       "NCT6779D",
+};
+
+/* nct6775_find() looks for a '627 in the Super-I/O config space */
+static int __init nct6775_find(int sioaddr, unsigned short *addr,
+                              struct nct6775_sio_data *sio_data)
+{
+       u16 val;
+       int err;
+
+       err = superio_enter(sioaddr);
+       if (err)
+               return err;
+
+       if (force_id)
+               val = force_id;
+       else
+               val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
+                   | superio_inb(sioaddr, SIO_REG_DEVID + 1);
+       switch (val & SIO_ID_MASK) {
+       case SIO_NCT6775_ID:
+               sio_data->kind = nct6775;
+               break;
+       case SIO_NCT6776_ID:
+               sio_data->kind = nct6776;
+               break;
+       case SIO_NCT6779_ID:
+               sio_data->kind = nct6779;
+               break;
+       default:
+               if (val != 0xffff)
+                       pr_debug("unsupported chip ID: 0x%04x\n", val);
+               superio_exit(sioaddr);
+               return -ENODEV;
+       }
+
+       /* We have a known chip, find the HWM I/O address */
+       superio_select(sioaddr, NCT6775_LD_HWM);
+       val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
+           | superio_inb(sioaddr, SIO_REG_ADDR + 1);
+       *addr = val & IOREGION_ALIGNMENT;
+       if (*addr == 0) {
+               pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
+               superio_exit(sioaddr);
+               return -ENODEV;
+       }
+
+       /* Activate logical device if needed */
+       val = superio_inb(sioaddr, SIO_REG_ENABLE);
+       if (!(val & 0x01)) {
+               pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
+               superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
+       }
+
+       superio_exit(sioaddr);
+       pr_info("Found %s or compatible chip at %#x\n",
+               nct6775_sio_names[sio_data->kind], *addr);
+       sio_data->sioreg = sioaddr;
+
+       return 0;
+}
+
+/*
+ * when Super-I/O functions move to a separate file, the Super-I/O
+ * bus will manage the lifetime of the device and this module will only keep
+ * track of the nct6775 driver. But since we platform_device_alloc(), we
+ * must keep track of the device
+ */
+static struct platform_device *pdev;
+
+static int __init sensors_nct6775_init(void)
+{
+       int err;
+       unsigned short address;
+       struct resource res;
+       struct nct6775_sio_data sio_data;
+
+       /*
+        * initialize sio_data->kind and sio_data->sioreg.
+        *
+        * when Super-I/O functions move to a separate file, the Super-I/O
+        * driver will probe 0x2e and 0x4e and auto-detect the presence of a
+        * nct6775 hardware monitor, and call probe()
+        */
+       if (nct6775_find(0x2e, &address, &sio_data) &&
+           nct6775_find(0x4e, &address, &sio_data))
+               return -ENODEV;
+
+       err = platform_driver_register(&nct6775_driver);
+       if (err)
+               goto exit;
+
+       pdev = platform_device_alloc(DRVNAME, address);
+       if (!pdev) {
+               err = -ENOMEM;
+               pr_err("Device allocation failed\n");
+               goto exit_unregister;
+       }
+
+       err = platform_device_add_data(pdev, &sio_data,
+                                      sizeof(struct nct6775_sio_data));
+       if (err) {
+               pr_err("Platform data allocation failed\n");
+               goto exit_device_put;
+       }
+
+       memset(&res, 0, sizeof(res));
+       res.name = DRVNAME;
+       res.start = address + IOREGION_OFFSET;
+       res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+       res.flags = IORESOURCE_IO;
+
+       err = acpi_check_resource_conflict(&res);
+       if (err)
+               goto exit_device_put;
+
+       err = platform_device_add_resources(pdev, &res, 1);
+       if (err) {
+               pr_err("Device resource addition failed (%d)\n", err);
+               goto exit_device_put;
+       }
+
+       /* platform_device_add calls probe() */
+       err = platform_device_add(pdev);
+       if (err) {
+               pr_err("Device addition failed (%d)\n", err);
+               goto exit_device_put;
+       }
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(pdev);
+exit_unregister:
+       platform_driver_unregister(&nct6775_driver);
+exit:
+       return err;
+}
+
+static void __exit sensors_nct6775_exit(void)
+{
+       platform_device_unregister(pdev);
+       platform_driver_unregister(&nct6775_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("NCT6775F/NCT6776F/NCT6779D driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_nct6775_init);
+module_exit(sensors_nct6775_exit);
index b5f63f9..d6d640a 100644 (file)
 #include <linux/math64.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/platform_data/ntc_thermistor.h>
 
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/consumer.h>
+
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 
 struct ntc_compensation {
-       int             temp_C;
+       int             temp_c;
        unsigned int    ohm;
 };
 
+static const struct platform_device_id ntc_thermistor_id[] = {
+       { "ncp15wb473", TYPE_NCPXXWB473 },
+       { "ncp18wb473", TYPE_NCPXXWB473 },
+       { "ncp21wb473", TYPE_NCPXXWB473 },
+       { "ncp03wb473", TYPE_NCPXXWB473 },
+       { "ncp15wl333", TYPE_NCPXXWL333 },
+       { },
+};
+
 /*
  * A compensation table should be sorted by the values of .ohm
  * in descending order.
@@ -44,76 +60,76 @@ struct ntc_compensation {
  * Thermistors Datasheet
  */
 static const struct ntc_compensation ncpXXwb473[] = {
-       { .temp_C       = -40, .ohm     = 1747920 },
-       { .temp_C       = -35, .ohm     = 1245428 },
-       { .temp_C       = -30, .ohm     = 898485 },
-       { .temp_C       = -25, .ohm     = 655802 },
-       { .temp_C       = -20, .ohm     = 483954 },
-       { .temp_C       = -15, .ohm     = 360850 },
-       { .temp_C       = -10, .ohm     = 271697 },
-       { .temp_C       = -5, .ohm      = 206463 },
-       { .temp_C       = 0, .ohm       = 158214 },
-       { .temp_C       = 5, .ohm       = 122259 },
-       { .temp_C       = 10, .ohm      = 95227 },
-       { .temp_C       = 15, .ohm      = 74730 },
-       { .temp_C       = 20, .ohm      = 59065 },
-       { .temp_C       = 25, .ohm      = 47000 },
-       { .temp_C       = 30, .ohm      = 37643 },
-       { .temp_C       = 35, .ohm      = 30334 },
-       { .temp_C       = 40, .ohm      = 24591 },
-       { .temp_C       = 45, .ohm      = 20048 },
-       { .temp_C       = 50, .ohm      = 16433 },
-       { .temp_C       = 55, .ohm      = 13539 },
-       { .temp_C       = 60, .ohm      = 11209 },
-       { .temp_C       = 65, .ohm      = 9328 },
-       { .temp_C       = 70, .ohm      = 7798 },
-       { .temp_C       = 75, .ohm      = 6544 },
-       { .temp_C       = 80, .ohm      = 5518 },
-       { .temp_C       = 85, .ohm      = 4674 },
-       { .temp_C       = 90, .ohm      = 3972 },
-       { .temp_C       = 95, .ohm      = 3388 },
-       { .temp_C       = 100, .ohm     = 2902 },
-       { .temp_C       = 105, .ohm     = 2494 },
-       { .temp_C       = 110, .ohm     = 2150 },
-       { .temp_C       = 115, .ohm     = 1860 },
-       { .temp_C       = 120, .ohm     = 1615 },
-       { .temp_C       = 125, .ohm     = 1406 },
+       { .temp_c       = -40, .ohm     = 1747920 },
+       { .temp_c       = -35, .ohm     = 1245428 },
+       { .temp_c       = -30, .ohm     = 898485 },
+       { .temp_c       = -25, .ohm     = 655802 },
+       { .temp_c       = -20, .ohm     = 483954 },
+       { .temp_c       = -15, .ohm     = 360850 },
+       { .temp_c       = -10, .ohm     = 271697 },
+       { .temp_c       = -5, .ohm      = 206463 },
+       { .temp_c       = 0, .ohm       = 158214 },
+       { .temp_c       = 5, .ohm       = 122259 },
+       { .temp_c       = 10, .ohm      = 95227 },
+       { .temp_c       = 15, .ohm      = 74730 },
+       { .temp_c       = 20, .ohm      = 59065 },
+       { .temp_c       = 25, .ohm      = 47000 },
+       { .temp_c       = 30, .ohm      = 37643 },
+       { .temp_c       = 35, .ohm      = 30334 },
+       { .temp_c       = 40, .ohm      = 24591 },
+       { .temp_c       = 45, .ohm      = 20048 },
+       { .temp_c       = 50, .ohm      = 16433 },
+       { .temp_c       = 55, .ohm      = 13539 },
+       { .temp_c       = 60, .ohm      = 11209 },
+       { .temp_c       = 65, .ohm      = 9328 },
+       { .temp_c       = 70, .ohm      = 7798 },
+       { .temp_c       = 75, .ohm      = 6544 },
+       { .temp_c       = 80, .ohm      = 5518 },
+       { .temp_c       = 85, .ohm      = 4674 },
+       { .temp_c       = 90, .ohm      = 3972 },
+       { .temp_c       = 95, .ohm      = 3388 },
+       { .temp_c       = 100, .ohm     = 2902 },
+       { .temp_c       = 105, .ohm     = 2494 },
+       { .temp_c       = 110, .ohm     = 2150 },
+       { .temp_c       = 115, .ohm     = 1860 },
+       { .temp_c       = 120, .ohm     = 1615 },
+       { .temp_c       = 125, .ohm     = 1406 },
 };
 static const struct ntc_compensation ncpXXwl333[] = {
-       { .temp_C       = -40, .ohm     = 1610154 },
-       { .temp_C       = -35, .ohm     = 1130850 },
-       { .temp_C       = -30, .ohm     = 802609 },
-       { .temp_C       = -25, .ohm     = 575385 },
-       { .temp_C       = -20, .ohm     = 416464 },
-       { .temp_C       = -15, .ohm     = 304219 },
-       { .temp_C       = -10, .ohm     = 224193 },
-       { .temp_C       = -5, .ohm      = 166623 },
-       { .temp_C       = 0, .ohm       = 124850 },
-       { .temp_C       = 5, .ohm       = 94287 },
-       { .temp_C       = 10, .ohm      = 71747 },
-       { .temp_C       = 15, .ohm      = 54996 },
-       { .temp_C       = 20, .ohm      = 42455 },
-       { .temp_C       = 25, .ohm      = 33000 },
-       { .temp_C       = 30, .ohm      = 25822 },
-       { .temp_C       = 35, .ohm      = 20335 },
-       { .temp_C       = 40, .ohm      = 16115 },
-       { .temp_C       = 45, .ohm      = 12849 },
-       { .temp_C       = 50, .ohm      = 10306 },
-       { .temp_C       = 55, .ohm      = 8314 },
-       { .temp_C       = 60, .ohm      = 6746 },
-       { .temp_C       = 65, .ohm      = 5503 },
-       { .temp_C       = 70, .ohm      = 4513 },
-       { .temp_C       = 75, .ohm      = 3721 },
-       { .temp_C       = 80, .ohm      = 3084 },
-       { .temp_C       = 85, .ohm      = 2569 },
-       { .temp_C       = 90, .ohm      = 2151 },
-       { .temp_C       = 95, .ohm      = 1809 },
-       { .temp_C       = 100, .ohm     = 1529 },
-       { .temp_C       = 105, .ohm     = 1299 },
-       { .temp_C       = 110, .ohm     = 1108 },
-       { .temp_C       = 115, .ohm     = 949 },
-       { .temp_C       = 120, .ohm     = 817 },
-       { .temp_C       = 125, .ohm     = 707 },
+       { .temp_c       = -40, .ohm     = 1610154 },
+       { .temp_c       = -35, .ohm     = 1130850 },
+       { .temp_c       = -30, .ohm     = 802609 },
+       { .temp_c       = -25, .ohm     = 575385 },
+       { .temp_c       = -20, .ohm     = 416464 },
+       { .temp_c       = -15, .ohm     = 304219 },
+       { .temp_c       = -10, .ohm     = 224193 },
+       { .temp_c       = -5, .ohm      = 166623 },
+       { .temp_c       = 0, .ohm       = 124850 },
+       { .temp_c       = 5, .ohm       = 94287 },
+       { .temp_c       = 10, .ohm      = 71747 },
+       { .temp_c       = 15, .ohm      = 54996 },
+       { .temp_c       = 20, .ohm      = 42455 },
+       { .temp_c       = 25, .ohm      = 33000 },
+       { .temp_c       = 30, .ohm      = 25822 },
+       { .temp_c       = 35, .ohm      = 20335 },
+       { .temp_c       = 40, .ohm      = 16115 },
+       { .temp_c       = 45, .ohm      = 12849 },
+       { .temp_c       = 50, .ohm      = 10306 },
+       { .temp_c       = 55, .ohm      = 8314 },
+       { .temp_c       = 60, .ohm      = 6746 },
+       { .temp_c       = 65, .ohm      = 5503 },
+       { .temp_c       = 70, .ohm      = 4513 },
+       { .temp_c       = 75, .ohm      = 3721 },
+       { .temp_c       = 80, .ohm      = 3084 },
+       { .temp_c       = 85, .ohm      = 2569 },
+       { .temp_c       = 90, .ohm      = 2151 },
+       { .temp_c       = 95, .ohm      = 1809 },
+       { .temp_c       = 100, .ohm     = 1529 },
+       { .temp_c       = 105, .ohm     = 1299 },
+       { .temp_c       = 110, .ohm     = 1108 },
+       { .temp_c       = 115, .ohm     = 949 },
+       { .temp_c       = 120, .ohm     = 817 },
+       { .temp_c       = 125, .ohm     = 707 },
 };
 
 struct ntc_data {
@@ -125,6 +141,92 @@ struct ntc_data {
        char name[PLATFORM_NAME_SIZE];
 };
 
+#ifdef CONFIG_OF
+static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
+{
+       struct iio_channel *channel = pdata->chan;
+       unsigned int result;
+       int val, ret;
+
+       ret = iio_read_channel_raw(channel, &val);
+       if (ret < 0) {
+               pr_err("read channel() error: %d\n", ret);
+               return ret;
+       }
+
+       /* unit: mV */
+       result = pdata->pullup_uv * val;
+       result >>= 12;
+
+       return result;
+}
+
+static const struct of_device_id ntc_match[] = {
+       { .compatible = "ntc,ncp15wb473",
+               .data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
+       { .compatible = "ntc,ncp18wb473",
+               .data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
+       { .compatible = "ntc,ncp21wb473",
+               .data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
+       { .compatible = "ntc,ncp03wb473",
+               .data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
+       { .compatible = "ntc,ncp15wl333",
+               .data = &ntc_thermistor_id[TYPE_NCPXXWL333] },
+       { },
+};
+MODULE_DEVICE_TABLE(of, ntc_match);
+
+static struct ntc_thermistor_platform_data *
+ntc_thermistor_parse_dt(struct platform_device *pdev)
+{
+       struct iio_channel *chan;
+       struct device_node *np = pdev->dev.of_node;
+       struct ntc_thermistor_platform_data *pdata;
+
+       if (!np)
+               return NULL;
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       chan = iio_channel_get(&pdev->dev, NULL);
+       if (IS_ERR(chan))
+               return ERR_CAST(chan);
+
+       if (of_property_read_u32(np, "pullup-uv", &pdata->pullup_uv))
+               return ERR_PTR(-ENODEV);
+       if (of_property_read_u32(np, "pullup-ohm", &pdata->pullup_ohm))
+               return ERR_PTR(-ENODEV);
+       if (of_property_read_u32(np, "pulldown-ohm", &pdata->pulldown_ohm))
+               return ERR_PTR(-ENODEV);
+
+       if (of_find_property(np, "connected-positive", NULL))
+               pdata->connect = NTC_CONNECTED_POSITIVE;
+       else /* status change should be possible if not always on. */
+               pdata->connect = NTC_CONNECTED_GROUND;
+
+       pdata->chan = chan;
+       pdata->read_uv = ntc_adc_iio_read;
+
+       return pdata;
+}
+static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
+{
+       if (pdata->chan)
+               iio_channel_release(pdata->chan);
+}
+#else
+static struct ntc_thermistor_platform_data *
+ntc_thermistor_parse_dt(struct platform_device *pdev)
+{
+       return NULL;
+}
+
+static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
+{ }
+#endif
+
 static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
 {
        if (divisor == 0 && dividend == 0)
@@ -134,37 +236,37 @@ static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
        return div64_u64(dividend, divisor);
 }
 
-static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uV)
+static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uv)
 {
        struct ntc_thermistor_platform_data *pdata = data->pdata;
-       u64 mV = uV / 1000;
-       u64 pmV = pdata->pullup_uV / 1000;
-       u64 N, puO, pdO;
-       puO = pdata->pullup_ohm;
-       pdO = pdata->pulldown_ohm;
+       u64 mv = uv / 1000;
+       u64 pmv = pdata->pullup_uv / 1000;
+       u64 n, puo, pdo;
+       puo = pdata->pullup_ohm;
+       pdo = pdata->pulldown_ohm;
 
-       if (mV == 0) {
+       if (mv == 0) {
                if (pdata->connect == NTC_CONNECTED_POSITIVE)
                        return INT_MAX;
                return 0;
        }
-       if (mV >= pmV)
+       if (mv >= pmv)
                return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
                        0 : INT_MAX;
 
-       if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0)
-               N = div64_u64_safe(pdO * (pmV - mV), mV);
-       else if (pdata->connect == NTC_CONNECTED_GROUND && pdO == 0)
-               N = div64_u64_safe(puO * mV, pmV - mV);
+       if (pdata->connect == NTC_CONNECTED_POSITIVE && puo == 0)
+               n = div64_u64_safe(pdo * (pmv - mv), mv);
+       else if (pdata->connect == NTC_CONNECTED_GROUND && pdo == 0)
+               n = div64_u64_safe(puo * mv, pmv - mv);
        else if (pdata->connect == NTC_CONNECTED_POSITIVE)
-               N = div64_u64_safe(pdO * puO * (pmV - mV),
-                               puO * mV - pdO * (pmV - mV));
+               n = div64_u64_safe(pdo * puo * (pmv - mv),
+                               puo * mv - pdo * (pmv - mv));
        else
-               N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV);
+               n = div64_u64_safe(pdo * puo * mv, pdo * (pmv - mv) - puo * mv);
 
-       if (N > INT_MAX)
-               N = INT_MAX;
-       return N;
+       if (n > INT_MAX)
+               n = INT_MAX;
+       return n;
 }
 
 static void lookup_comp(struct ntc_data *data, unsigned int ohm,
@@ -233,7 +335,7 @@ static void lookup_comp(struct ntc_data *data, unsigned int ohm,
                *i_high = end - 1;
 }
 
-static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
+static int get_temp_mc(struct ntc_data *data, unsigned int ohm)
 {
        int low, high;
        int temp;
@@ -241,10 +343,10 @@ static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
        lookup_comp(data, ohm, &low, &high);
        if (low == high) {
                /* Unable to use linear approximation */
-               temp = data->comp[low].temp_C * 1000;
+               temp = data->comp[low].temp_c * 1000;
        } else {
-               temp = data->comp[low].temp_C * 1000 +
-                       ((data->comp[high].temp_C - data->comp[low].temp_C) *
+               temp = data->comp[low].temp_c * 1000 +
+                       ((data->comp[high].temp_c - data->comp[low].temp_c) *
                         1000 * ((int)ohm - (int)data->comp[low].ohm)) /
                        ((int)data->comp[high].ohm - (int)data->comp[low].ohm);
        }
@@ -253,16 +355,16 @@ static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
 
 static int ntc_thermistor_get_ohm(struct ntc_data *data)
 {
-       int read_uV;
+       int read_uv;
 
        if (data->pdata->read_ohm)
                return data->pdata->read_ohm();
 
-       if (data->pdata->read_uV) {
-               read_uV = data->pdata->read_uV();
-               if (read_uV < 0)
-                       return read_uV;
-               return get_ohm_of_thermistor(data, read_uV);
+       if (data->pdata->read_uv) {
+               read_uv = data->pdata->read_uv(data->pdata);
+               if (read_uv < 0)
+                       return read_uv;
+               return get_ohm_of_thermistor(data, read_uv);
        }
        return -EINVAL;
 }
@@ -291,7 +393,7 @@ static ssize_t ntc_show_temp(struct device *dev,
        if (ohm < 0)
                return ohm;
 
-       return sprintf(buf, "%d\n", get_temp_mC(data, ohm));
+       return sprintf(buf, "%d\n", get_temp_mc(data, ohm));
 }
 
 static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
@@ -311,9 +413,18 @@ static const struct attribute_group ntc_attr_group = {
 
 static int ntc_thermistor_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *of_id =
+                       of_match_device(of_match_ptr(ntc_match), &pdev->dev);
+       const struct platform_device_id *pdev_id;
+       struct ntc_thermistor_platform_data *pdata;
        struct ntc_data *data;
-       struct ntc_thermistor_platform_data *pdata = pdev->dev.platform_data;
-       int ret = 0;
+       int ret;
+
+       pdata = ntc_thermistor_parse_dt(pdev);
+       if (IS_ERR(pdata))
+               return PTR_ERR(pdata);
+       else if (pdata == NULL)
+               pdata = pdev->dev.platform_data;
 
        if (!pdata) {
                dev_err(&pdev->dev, "No platform init data supplied.\n");
@@ -321,19 +432,19 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
        }
 
        /* Either one of the two is required. */
-       if (!pdata->read_uV && !pdata->read_ohm) {
+       if (!pdata->read_uv && !pdata->read_ohm) {
                dev_err(&pdev->dev,
-                       "Both read_uV and read_ohm missing. Need either one of the two.\n");
+                       "Both read_uv and read_ohm missing. Need either one of the two.\n");
                return -EINVAL;
        }
 
-       if (pdata->read_uV && pdata->read_ohm) {
+       if (pdata->read_uv && pdata->read_ohm) {
                dev_warn(&pdev->dev,
-                        "Only one of read_uV and read_ohm is needed; ignoring read_uV.\n");
-               pdata->read_uV = NULL;
+                        "Only one of read_uv and read_ohm is needed; ignoring read_uv.\n");
+               pdata->read_uv = NULL;
        }
 
-       if (pdata->read_uV && (pdata->pullup_uV == 0 ||
+       if (pdata->read_uv && (pdata->pullup_uv == 0 ||
                                (pdata->pullup_ohm == 0 && pdata->connect ==
                                 NTC_CONNECTED_GROUND) ||
                                (pdata->pulldown_ohm == 0 && pdata->connect ==
@@ -341,7 +452,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
                                (pdata->connect != NTC_CONNECTED_POSITIVE &&
                                 pdata->connect != NTC_CONNECTED_GROUND))) {
                dev_err(&pdev->dev,
-                       "Required data to use read_uV not supplied.\n");
+                       "Required data to use read_uv not supplied.\n");
                return -EINVAL;
        }
 
@@ -349,11 +460,13 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
        if (!data)
                return -ENOMEM;
 
+       pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
+
        data->dev = &pdev->dev;
        data->pdata = pdata;
-       strlcpy(data->name, pdev->id_entry->name, sizeof(data->name));
+       strlcpy(data->name, pdev_id->name, sizeof(data->name));
 
-       switch (pdev->id_entry->driver_data) {
+       switch (pdev_id->driver_data) {
        case TYPE_NCPXXWB473:
                data->comp = ncpXXwb473;
                data->n_comp = ARRAY_SIZE(ncpXXwb473);
@@ -364,8 +477,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
                break;
        default:
                dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
-                               pdev->id_entry->driver_data,
-                               pdev->id_entry->name);
+                               pdev_id->driver_data, pdev_id->name);
                return -EINVAL;
        }
 
@@ -384,39 +496,34 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
                goto err_after_sysfs;
        }
 
-       dev_info(&pdev->dev, "Thermistor %s:%d (type: %s/%lu) successfully probed.\n",
-                       pdev->name, pdev->id, pdev->id_entry->name,
-                       pdev->id_entry->driver_data);
+       dev_info(&pdev->dev, "Thermistor type: %s successfully probed.\n",
+                                                               pdev->name);
+
        return 0;
 err_after_sysfs:
        sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
+       ntc_iio_channel_release(pdata);
        return ret;
 }
 
 static int ntc_thermistor_remove(struct platform_device *pdev)
 {
        struct ntc_data *data = platform_get_drvdata(pdev);
+       struct ntc_thermistor_platform_data *pdata = data->pdata;
 
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
+       ntc_iio_channel_release(pdata);
        platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
 
-static const struct platform_device_id ntc_thermistor_id[] = {
-       { "ncp15wb473", TYPE_NCPXXWB473 },
-       { "ncp18wb473", TYPE_NCPXXWB473 },
-       { "ncp21wb473", TYPE_NCPXXWB473 },
-       { "ncp03wb473", TYPE_NCPXXWB473 },
-       { "ncp15wl333", TYPE_NCPXXWL333 },
-       { },
-};
-
 static struct platform_driver ntc_thermistor_driver = {
        .driver = {
                .name = "ntc-thermistor",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(ntc_match),
        },
        .probe = ntc_thermistor_probe,
        .remove = ntc_thermistor_remove,
index e35856b..aa615ba 100644 (file)
@@ -1190,8 +1190,7 @@ static int __init pc87360_find(int sioaddr, u8 *devid,
                                confreg[3] = superio_inb(sioaddr, 0x25);
 
                                if (confreg[2] & 0x40) {
-                                       pr_info("Using thermistors for "
-                                               "temperature monitoring\n");
+                                       pr_info("Using thermistors for temperature monitoring\n");
                                }
                                if (confreg[3] & 0xE0) {
                                        pr_info("VID inputs routed (mode %u)\n",
@@ -1271,9 +1270,9 @@ static int pc87360_probe(struct platform_device *pdev)
                if (data->address[i]
                 && !devm_request_region(dev, extra_isa[i], PC87360_EXTENT,
                                         pc87360_driver.driver.name)) {
-                       dev_err(dev, "Region 0x%x-0x%x already "
-                               "in use!\n", extra_isa[i],
-                               extra_isa[i]+PC87360_EXTENT-1);
+                       dev_err(dev,
+                               "Region 0x%x-0x%x already in use!\n",
+                               extra_isa[i], extra_isa[i]+PC87360_EXTENT-1);
                        return -EBUSY;
                }
        }
@@ -1435,8 +1434,8 @@ static void pc87360_init_device(struct platform_device *pdev,
        if (init >= 2 && data->innr) {
                reg = pc87360_read_value(data, LD_IN, NO_BANK,
                                         PC87365_REG_IN_CONVRATE);
-               dev_info(&pdev->dev, "VLM conversion set to "
-                        "1s period, 160us delay\n");
+               dev_info(&pdev->dev,
+                        "VLM conversion set to 1s period, 160us delay\n");
                pc87360_write_value(data, LD_IN, NO_BANK,
                                    PC87365_REG_IN_CONVRATE,
                                    (reg & 0xC0) | 0x11);
@@ -1450,8 +1449,8 @@ static void pc87360_init_device(struct platform_device *pdev,
                if (init >= init_in[i]) {
                        /* Forcibly enable voltage channel */
                        if (!(reg & CHAN_ENA)) {
-                               dev_dbg(&pdev->dev, "Forcibly "
-                                       "enabling in%d\n", i);
+                               dev_dbg(&pdev->dev, "Forcibly enabling in%d\n",
+                                       i);
                                pc87360_write_value(data, LD_IN, i,
                                                    PC87365_REG_IN_STATUS,
                                                    (reg & 0x68) | 0x87);
@@ -1575,8 +1574,8 @@ static void pc87360_autodiv(struct device *dev, int nr)
                        data->fan_status[nr] += 0x20;
                        data->fan_min[nr] >>= 1;
                        data->fan[nr] >>= 1;
-                       dev_dbg(dev, "Increasing "
-                               "clock divider to %d for fan %d\n",
+                       dev_dbg(dev,
+                               "Increasing clock divider to %d for fan %d\n",
                                FAN_DIV_FROM_REG(data->fan_status[nr]), nr + 1);
                }
        } else {
@@ -1587,8 +1586,8 @@ static void pc87360_autodiv(struct device *dev, int nr)
                        data->fan_status[nr] -= 0x20;
                        data->fan_min[nr] <<= 1;
                        data->fan[nr] <<= 1;
-                       dev_dbg(dev, "Decreasing "
-                               "clock divider to %d for fan %d\n",
+                       dev_dbg(dev,
+                               "Decreasing clock divider to %d for fan %d\n",
                                FAN_DIV_FROM_REG(data->fan_status[nr]),
                                nr + 1);
                }
index 6086ad0..ea60686 100644 (file)
@@ -627,8 +627,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute
        pc87427_readall_pwm(data, nr);
        mode = data->pwm_enable[nr] & PWM_ENABLE_MODE_MASK;
        if (mode != PWM_MODE_MANUAL && mode != PWM_MODE_OFF) {
-               dev_notice(dev, "Can't set PWM%d duty cycle while not in "
-                          "manual mode\n", nr + 1);
+               dev_notice(dev,
+                          "Can't set PWM%d duty cycle while not in manual mode\n",
+                          nr + 1);
                mutex_unlock(&data->lock);
                return -EPERM;
        }
@@ -1245,16 +1246,16 @@ static int __init pc87427_find(int sioaddr, struct pc87427_sio_data *sio_data)
 
                val = superio_inb(sioaddr, SIOREG_MAP);
                if (val & 0x01) {
-                       pr_warn("Logical device 0x%02x is memory-mapped, "
-                               "can't use\n", logdev[i]);
+                       pr_warn("Logical device 0x%02x is memory-mapped, can't use\n",
+                               logdev[i]);
                        continue;
                }
 
                val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8)
                    | superio_inb(sioaddr, SIOREG_IOBASE + 1);
                if (!val) {
-                       pr_info("I/O base address not set for logical device "
-                               "0x%02x\n", logdev[i]);
+                       pr_info("I/O base address not set for logical device 0x%02x\n",
+                               logdev[i]);
                        continue;
                }
                sio_data->address[i] = val;
index 4f9eb0a..39cc63e 100644 (file)
@@ -42,17 +42,17 @@ config SENSORS_LM25066
        default n
        help
          If you say yes here you get hardware monitoring support for National
-         Semiconductor LM25066, LM5064, and LM5066.
+         Semiconductor LM25056, LM25066, LM5064, and LM5066.
 
          This driver can also be built as a module. If so, the module will
          be called lm25066.
 
 config SENSORS_LTC2978
-       tristate "Linear Technologies LTC2978 and LTC3880"
+       tristate "Linear Technologies LTC2974, LTC2978, LTC3880, and LTC3883"
        default n
        help
          If you say yes here you get hardware monitoring support for Linear
-         Technology LTC2978 and LTC3880.
+         Technology LTC2974, LTC2978, LTC3880, and LTC3883.
 
          This driver can also be built as a module. If so, the module will
          be called ltc2978.
index c299392..6a9d6ed 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * Hardware monitoring driver for LM25066 / LM5064 / LM5066
+ * Hardware monitoring driver for LM25056 / LM25066 / LM5064 / LM5066
  *
  * Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2013 Guenter Roeck
  *
  * 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
@@ -26,7 +27,7 @@
 #include <linux/i2c.h>
 #include "pmbus.h"
 
-enum chips { lm25066, lm5064, lm5066 };
+enum chips { lm25056, lm25066, lm5064, lm5066 };
 
 #define LM25066_READ_VAUX              0xd0
 #define LM25066_MFR_READ_IIN           0xd1
@@ -43,6 +44,138 @@ enum chips { lm25066, lm5064, lm5066 };
 
 #define LM25066_DEV_SETUP_CL           (1 << 4)        /* Current limit */
 
+/* LM25056 only */
+
+#define LM25056_VAUX_OV_WARN_LIMIT     0xe3
+#define LM25056_VAUX_UV_WARN_LIMIT     0xe4
+
+#define LM25056_MFR_STS_VAUX_OV_WARN   (1 << 1)
+#define LM25056_MFR_STS_VAUX_UV_WARN   (1 << 0)
+
+struct __coeff {
+       short m, b, R;
+};
+
+#define PSC_CURRENT_IN_L       (PSC_NUM_CLASSES)
+#define PSC_POWER_L            (PSC_NUM_CLASSES + 1)
+
+static struct __coeff lm25066_coeff[4][PSC_NUM_CLASSES + 2] = {
+       [lm25056] = {
+               [PSC_VOLTAGE_IN] = {
+                       .m = 16296,
+                       .R = -2,
+               },
+               [PSC_CURRENT_IN] = {
+                       .m = 13797,
+                       .R = -2,
+               },
+               [PSC_CURRENT_IN_L] = {
+                       .m = 6726,
+                       .R = -2,
+               },
+               [PSC_POWER] = {
+                       .m = 5501,
+                       .R = -3,
+               },
+               [PSC_POWER_L] = {
+                       .m = 26882,
+                       .R = -4,
+               },
+               [PSC_TEMPERATURE] = {
+                       .m = 1580,
+                       .b = -14500,
+                       .R = -2,
+               },
+       },
+       [lm25066] = {
+               [PSC_VOLTAGE_IN] = {
+                       .m = 22070,
+                       .R = -2,
+               },
+               [PSC_VOLTAGE_OUT] = {
+                       .m = 22070,
+                       .R = -2,
+               },
+               [PSC_CURRENT_IN] = {
+                       .m = 13661,
+                       .R = -2,
+               },
+               [PSC_CURRENT_IN_L] = {
+                       .m = 6852,
+                       .R = -2,
+               },
+               [PSC_POWER] = {
+                       .m = 736,
+                       .R = -2,
+               },
+               [PSC_POWER_L] = {
+                       .m = 369,
+                       .R = -2,
+               },
+               [PSC_TEMPERATURE] = {
+                       .m = 16,
+               },
+       },
+       [lm5064] = {
+               [PSC_VOLTAGE_IN] = {
+                       .m = 4611,
+                       .R = -2,
+               },
+               [PSC_VOLTAGE_OUT] = {
+                       .m = 4621,
+                       .R = -2,
+               },
+               [PSC_CURRENT_IN] = {
+                       .m = 10742,
+                       .R = -2,
+               },
+               [PSC_CURRENT_IN_L] = {
+                       .m = 5456,
+                       .R = -2,
+               },
+               [PSC_POWER] = {
+                       .m = 1204,
+                       .R = -3,
+               },
+               [PSC_POWER_L] = {
+                       .m = 612,
+                       .R = -3,
+               },
+               [PSC_TEMPERATURE] = {
+                       .m = 16,
+               },
+       },
+       [lm5066] = {
+               [PSC_VOLTAGE_IN] = {
+                       .m = 4587,
+                       .R = -2,
+               },
+               [PSC_VOLTAGE_OUT] = {
+                       .m = 4587,
+                       .R = -2,
+               },
+               [PSC_CURRENT_IN] = {
+                       .m = 10753,
+                       .R = -2,
+               },
+               [PSC_CURRENT_IN_L] = {
+                       .m = 5405,
+                       .R = -2,
+               },
+               [PSC_POWER] = {
+                       .m = 1204,
+                       .R = -3,
+               },
+               [PSC_POWER_L] = {
+                       .m = 605,
+                       .R = -3,
+               },
+               [PSC_TEMPERATURE] = {
+                       .m = 16,
+               },
+       },
+};
+
 struct lm25066_data {
        int id;
        struct pmbus_driver_info info;
@@ -56,42 +189,31 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
        const struct lm25066_data *data = to_lm25066_data(info);
        int ret;
 
-       if (page > 1)
-               return -ENXIO;
-
-       /* Map READ_VAUX into READ_VOUT register on page 1 */
-       if (page == 1) {
-               switch (reg) {
-               case PMBUS_READ_VOUT:
-                       ret = pmbus_read_word_data(client, 0,
-                                                  LM25066_READ_VAUX);
-                       if (ret < 0)
-                               break;
-                       /* Adjust returned value to match VOUT coefficients */
-                       switch (data->id) {
-                       case lm25066:
-                               /* VOUT: 4.54 mV VAUX: 283.2 uV LSB */
-                               ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
-                               break;
-                       case lm5064:
-                               /* VOUT: 4.53 mV VAUX: 700 uV LSB */
-                               ret = DIV_ROUND_CLOSEST(ret * 70, 453);
-                               break;
-                       case lm5066:
-                               /* VOUT: 2.18 mV VAUX: 725 uV LSB */
-                               ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
-                               break;
-                       }
+       switch (reg) {
+       case PMBUS_VIRT_READ_VMON:
+               ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX);
+               if (ret < 0)
+                       break;
+               /* Adjust returned value to match VIN coefficients */
+               switch (data->id) {
+               case lm25056:
+                       /* VIN: 6.14 mV VAUX: 293 uV LSB */
+                       ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
                        break;
-               default:
-                       /* No other valid registers on page 1 */
-                       ret = -ENXIO;
+               case lm25066:
+                       /* VIN: 4.54 mV VAUX: 283.2 uV LSB */
+                       ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
+                       break;
+               case lm5064:
+                       /* VIN: 4.53 mV VAUX: 700 uV LSB */
+                       ret = DIV_ROUND_CLOSEST(ret * 70, 453);
+                       break;
+               case lm5066:
+                       /* VIN: 2.18 mV VAUX: 725 uV LSB */
+                       ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
                        break;
                }
-               goto done;
-       }
-
-       switch (reg) {
+               break;
        case PMBUS_READ_IIN:
                ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
                break;
@@ -128,7 +250,58 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
                ret = -ENODATA;
                break;
        }
-done:
+       return ret;
+}
+
+static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+               ret = pmbus_read_word_data(client, 0,
+                                          LM25056_VAUX_UV_WARN_LIMIT);
+               if (ret < 0)
+                       break;
+               /* Adjust returned value to match VIN coefficients */
+               ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
+               break;
+       case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+               ret = pmbus_read_word_data(client, 0,
+                                          LM25056_VAUX_OV_WARN_LIMIT);
+               if (ret < 0)
+                       break;
+               /* Adjust returned value to match VIN coefficients */
+               ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
+               break;
+       default:
+               ret = lm25066_read_word_data(client, page, reg);
+               break;
+       }
+       return ret;
+}
+
+static int lm25056_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+       int ret, s;
+
+       switch (reg) {
+       case PMBUS_VIRT_STATUS_VMON:
+               ret = pmbus_read_byte_data(client, 0,
+                                          PMBUS_STATUS_MFR_SPECIFIC);
+               if (ret < 0)
+                       break;
+               s = 0;
+               if (ret & LM25056_MFR_STS_VAUX_UV_WARN)
+                       s |= PB_VOLTAGE_UV_WARNING;
+               if (ret & LM25056_MFR_STS_VAUX_OV_WARN)
+                       s |= PB_VOLTAGE_OV_WARNING;
+               ret = s;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
        return ret;
 }
 
@@ -137,19 +310,45 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
 {
        int ret;
 
-       if (page > 1)
-               return -ENXIO;
-
        switch (reg) {
+       case PMBUS_VOUT_UV_WARN_LIMIT:
+       case PMBUS_OT_FAULT_LIMIT:
+       case PMBUS_OT_WARN_LIMIT:
+       case PMBUS_VIN_UV_WARN_LIMIT:
+       case PMBUS_VIN_OV_WARN_LIMIT:
+               word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
+               ret = pmbus_write_word_data(client, 0, reg, word);
+               pmbus_clear_cache(client);
+               break;
        case PMBUS_IIN_OC_WARN_LIMIT:
+               word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
                ret = pmbus_write_word_data(client, 0,
                                            LM25066_MFR_IIN_OC_WARN_LIMIT,
                                            word);
+               pmbus_clear_cache(client);
                break;
        case PMBUS_PIN_OP_WARN_LIMIT:
+               word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
                ret = pmbus_write_word_data(client, 0,
                                            LM25066_MFR_PIN_OP_WARN_LIMIT,
                                            word);
+               pmbus_clear_cache(client);
+               break;
+       case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+               /* Adjust from VIN coefficients (for LM25056) */
+               word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
+               word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
+               ret = pmbus_write_word_data(client, 0,
+                                           LM25056_VAUX_UV_WARN_LIMIT, word);
+               pmbus_clear_cache(client);
+               break;
+       case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+               /* Adjust from VIN coefficients (for LM25056) */
+               word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
+               word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
+               ret = pmbus_write_word_data(client, 0,
+                                           LM25056_VAUX_OV_WARN_LIMIT, word);
+               pmbus_clear_cache(client);
                break;
        case PMBUS_VIRT_RESET_PIN_HISTORY:
                ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK);
@@ -161,23 +360,13 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
        return ret;
 }
 
-static int lm25066_write_byte(struct i2c_client *client, int page, u8 value)
-{
-       if (page > 1)
-               return -ENXIO;
-
-       if (page <= 0)
-               return pmbus_write_byte(client, page, value);
-
-       return 0;
-}
-
 static int lm25066_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
        int config;
        struct lm25066_data *data;
        struct pmbus_driver_info *info;
+       struct __coeff *coeff;
 
        if (!i2c_check_functionality(client->adapter,
                                     I2C_FUNC_SMBUS_READ_BYTE_DATA))
@@ -195,107 +384,54 @@ static int lm25066_probe(struct i2c_client *client,
        data->id = id->driver_data;
        info = &data->info;
 
-       info->pages = 2;
+       info->pages = 1;
        info->format[PSC_VOLTAGE_IN] = direct;
        info->format[PSC_VOLTAGE_OUT] = direct;
        info->format[PSC_CURRENT_IN] = direct;
        info->format[PSC_TEMPERATURE] = direct;
        info->format[PSC_POWER] = direct;
 
-       info->m[PSC_TEMPERATURE] = 16;
-       info->b[PSC_TEMPERATURE] = 0;
-       info->R[PSC_TEMPERATURE] = 0;
-
-       info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT
-         | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN
-         | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
-       info->func[1] = PMBUS_HAVE_VOUT;
-
-       info->read_word_data = lm25066_read_word_data;
+       info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VMON
+         | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT
+         | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+
+       if (data->id == lm25056) {
+               info->func[0] |= PMBUS_HAVE_STATUS_VMON;
+               info->read_word_data = lm25056_read_word_data;
+               info->read_byte_data = lm25056_read_byte_data;
+       } else {
+               info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+               info->read_word_data = lm25066_read_word_data;
+       }
        info->write_word_data = lm25066_write_word_data;
-       info->write_byte = lm25066_write_byte;
-
-       switch (id->driver_data) {
-       case lm25066:
-               info->m[PSC_VOLTAGE_IN] = 22070;
-               info->b[PSC_VOLTAGE_IN] = 0;
-               info->R[PSC_VOLTAGE_IN] = -2;
-               info->m[PSC_VOLTAGE_OUT] = 22070;
-               info->b[PSC_VOLTAGE_OUT] = 0;
-               info->R[PSC_VOLTAGE_OUT] = -2;
-
-               if (config & LM25066_DEV_SETUP_CL) {
-                       info->m[PSC_CURRENT_IN] = 6852;
-                       info->b[PSC_CURRENT_IN] = 0;
-                       info->R[PSC_CURRENT_IN] = -2;
-                       info->m[PSC_POWER] = 369;
-                       info->b[PSC_POWER] = 0;
-                       info->R[PSC_POWER] = -2;
-               } else {
-                       info->m[PSC_CURRENT_IN] = 13661;
-                       info->b[PSC_CURRENT_IN] = 0;
-                       info->R[PSC_CURRENT_IN] = -2;
-                       info->m[PSC_POWER] = 736;
-                       info->b[PSC_POWER] = 0;
-                       info->R[PSC_POWER] = -2;
-               }
-               break;
-       case lm5064:
-               info->m[PSC_VOLTAGE_IN] = 22075;
-               info->b[PSC_VOLTAGE_IN] = 0;
-               info->R[PSC_VOLTAGE_IN] = -2;
-               info->m[PSC_VOLTAGE_OUT] = 22075;
-               info->b[PSC_VOLTAGE_OUT] = 0;
-               info->R[PSC_VOLTAGE_OUT] = -2;
-
-               if (config & LM25066_DEV_SETUP_CL) {
-                       info->m[PSC_CURRENT_IN] = 6713;
-                       info->b[PSC_CURRENT_IN] = 0;
-                       info->R[PSC_CURRENT_IN] = -2;
-                       info->m[PSC_POWER] = 3619;
-                       info->b[PSC_POWER] = 0;
-                       info->R[PSC_POWER] = -3;
-               } else {
-                       info->m[PSC_CURRENT_IN] = 13426;
-                       info->b[PSC_CURRENT_IN] = 0;
-                       info->R[PSC_CURRENT_IN] = -2;
-                       info->m[PSC_POWER] = 7238;
-                       info->b[PSC_POWER] = 0;
-                       info->R[PSC_POWER] = -3;
-               }
-               break;
-       case lm5066:
-               info->m[PSC_VOLTAGE_IN] = 4587;
-               info->b[PSC_VOLTAGE_IN] = 0;
-               info->R[PSC_VOLTAGE_IN] = -2;
-               info->m[PSC_VOLTAGE_OUT] = 4587;
-               info->b[PSC_VOLTAGE_OUT] = 0;
-               info->R[PSC_VOLTAGE_OUT] = -2;
-
-               if (config & LM25066_DEV_SETUP_CL) {
-                       info->m[PSC_CURRENT_IN] = 10753;
-                       info->b[PSC_CURRENT_IN] = 0;
-                       info->R[PSC_CURRENT_IN] = -2;
-                       info->m[PSC_POWER] = 1204;
-                       info->b[PSC_POWER] = 0;
-                       info->R[PSC_POWER] = -3;
-               } else {
-                       info->m[PSC_CURRENT_IN] = 5405;
-                       info->b[PSC_CURRENT_IN] = 0;
-                       info->R[PSC_CURRENT_IN] = -2;
-                       info->m[PSC_POWER] = 605;
-                       info->b[PSC_POWER] = 0;
-                       info->R[PSC_POWER] = -3;
-               }
-               break;
-       default:
-               return -ENODEV;
+
+       coeff = &lm25066_coeff[data->id][0];
+       info->m[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].m;
+       info->b[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].b;
+       info->R[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].R;
+       info->m[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].m;
+       info->b[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].b;
+       info->R[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].R;
+       info->m[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].m;
+       info->b[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].b;
+       info->R[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].R;
+       info->b[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].b;
+       info->R[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].R;
+       info->b[PSC_POWER] = coeff[PSC_POWER].b;
+       info->R[PSC_POWER] = coeff[PSC_POWER].R;
+       if (config & LM25066_DEV_SETUP_CL) {
+               info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN_L].m;
+               info->m[PSC_POWER] = coeff[PSC_POWER_L].m;
+       } else {
+               info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].m;
+               info->m[PSC_POWER] = coeff[PSC_POWER].m;
        }
 
        return pmbus_do_probe(client, id, info);
 }
 
 static const struct i2c_device_id lm25066_id[] = {
+       {"lm25056", lm25056},
        {"lm25066", lm25066},
        {"lm5064", lm5064},
        {"lm5066", lm5066},
@@ -317,5 +453,5 @@ static struct i2c_driver lm25066_driver = {
 module_i2c_driver(lm25066_driver);
 
 MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for LM25066/LM5064/LM5066");
+MODULE_DESCRIPTION("PMBus driver for LM25056/LM25066/LM5064/LM5066");
 MODULE_LICENSE("GPL");
index 6d61307..586a89e 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * Hardware monitoring driver for LTC2978 and LTC3880
+ * Hardware monitoring driver for LTC2974, LTC2978, LTC3880, and LTC3883
  *
  * Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2013 Guenter Roeck
  *
  * 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
 #include <linux/i2c.h>
 #include "pmbus.h"
 
-enum chips { ltc2978, ltc3880 };
+enum chips { ltc2974, ltc2978, ltc3880, ltc3883 };
 
-/* LTC2978 and LTC3880 */
+/* Common for all chips */
 #define LTC2978_MFR_VOUT_PEAK          0xdd
 #define LTC2978_MFR_VIN_PEAK           0xde
 #define LTC2978_MFR_TEMPERATURE_PEAK   0xdf
 #define LTC2978_MFR_SPECIAL_ID         0xe7
 
-/* LTC2978 only */
+/* LTC2974 and LTC2978 */
 #define LTC2978_MFR_VOUT_MIN           0xfb
 #define LTC2978_MFR_VIN_MIN            0xfc
 #define LTC2978_MFR_TEMPERATURE_MIN    0xfd
 
-/* LTC3880 only */
+/* LTC2974 only */
+#define LTC2974_MFR_IOUT_PEAK          0xd7
+#define LTC2974_MFR_IOUT_MIN           0xd8
+
+/* LTC3880 and LTC3883 */
 #define LTC3880_MFR_IOUT_PEAK          0xd7
 #define LTC3880_MFR_CLEAR_PEAKS                0xe3
 #define LTC3880_MFR_TEMPERATURE2_PEAK  0xf4
 
+/* LTC3883 only */
+#define LTC3883_MFR_IIN_PEAK           0xe1
+
+#define LTC2974_ID                     0x0212
 #define LTC2978_ID_REV1                        0x0121
 #define LTC2978_ID_REV2                        0x0122
 #define LTC3880_ID                     0x4000
 #define LTC3880_ID_MASK                        0xff00
+#define LTC3883_ID                     0x4300
+#define LTC3883_ID_MASK                        0xff00
+
+#define LTC2974_NUM_PAGES              4
+#define LTC2978_NUM_PAGES              8
+#define LTC3880_NUM_PAGES              2
+#define LTC3883_NUM_PAGES              1
 
 /*
  * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
@@ -56,13 +72,15 @@ enum chips { ltc2978, ltc3880 };
  * internal cache of measured peak data, which is only cleared if an explicit
  * "clear peak" command is executed for the sensor in question.
  */
+
 struct ltc2978_data {
        enum chips id;
-       int vin_min, vin_max;
-       int temp_min, temp_max[2];
-       int vout_min[8], vout_max[8];
-       int iout_max[2];
-       int temp2_max;
+       u16 vin_min, vin_max;
+       u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES];
+       u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES];
+       u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES];
+       u16 iin_max;
+       u16 temp2_max;
        struct pmbus_driver_info info;
 };
 
@@ -167,9 +185,9 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
                                           LTC2978_MFR_TEMPERATURE_MIN);
                if (ret >= 0) {
                        if (lin11_to_val(ret)
-                           < lin11_to_val(data->temp_min))
-                               data->temp_min = ret;
-                       ret = data->temp_min;
+                           < lin11_to_val(data->temp_min[page]))
+                               data->temp_min[page] = ret;
+                       ret = data->temp_min[page];
                }
                break;
        case PMBUS_VIRT_READ_IOUT_MAX:
@@ -185,6 +203,41 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
        return ret;
 }
 
+static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+       struct ltc2978_data *data = to_ltc2978_data(info);
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_IOUT_MAX:
+               ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_PEAK);
+               if (ret >= 0) {
+                       if (lin11_to_val(ret)
+                           > lin11_to_val(data->iout_max[page]))
+                               data->iout_max[page] = ret;
+                       ret = data->iout_max[page];
+               }
+               break;
+       case PMBUS_VIRT_READ_IOUT_MIN:
+               ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_MIN);
+               if (ret >= 0) {
+                       if (lin11_to_val(ret)
+                           < lin11_to_val(data->iout_min[page]))
+                               data->iout_min[page] = ret;
+                       ret = data->iout_min[page];
+               }
+               break;
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = ltc2978_read_word_data(client, page, reg);
+               break;
+       }
+       return ret;
+}
+
 static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
@@ -226,15 +279,41 @@ static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
        return ret;
 }
 
+static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+       struct ltc2978_data *data = to_ltc2978_data(info);
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_IIN_MAX:
+               ret = pmbus_read_word_data(client, page, LTC3883_MFR_IIN_PEAK);
+               if (ret >= 0) {
+                       if (lin11_to_val(ret)
+                           > lin11_to_val(data->iin_max))
+                               data->iin_max = ret;
+                       ret = data->iin_max;
+               }
+               break;
+       case PMBUS_VIRT_RESET_IIN_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = ltc3880_read_word_data(client, page, reg);
+               break;
+       }
+       return ret;
+}
+
 static int ltc2978_clear_peaks(struct i2c_client *client, int page,
                               enum chips id)
 {
        int ret;
 
-       if (id == ltc2978)
-               ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
-       else
+       if (id == ltc3880 || id == ltc3883)
                ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
+       else
+               ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
 
        return ret;
 }
@@ -247,8 +326,13 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
        int ret;
 
        switch (reg) {
+       case PMBUS_VIRT_RESET_IIN_HISTORY:
+               data->iin_max = 0x7c00;
+               ret = ltc2978_clear_peaks(client, page, data->id);
+               break;
        case PMBUS_VIRT_RESET_IOUT_HISTORY:
                data->iout_max[page] = 0x7c00;
+               data->iout_min[page] = 0xfbff;
                ret = ltc2978_clear_peaks(client, page, data->id);
                break;
        case PMBUS_VIRT_RESET_TEMP2_HISTORY:
@@ -266,7 +350,7 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
                ret = ltc2978_clear_peaks(client, page, data->id);
                break;
        case PMBUS_VIRT_RESET_TEMP_HISTORY:
-               data->temp_min = 0x7bff;
+               data->temp_min[page] = 0x7bff;
                data->temp_max[page] = 0x7c00;
                ret = ltc2978_clear_peaks(client, page, data->id);
                break;
@@ -278,8 +362,10 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
 }
 
 static const struct i2c_device_id ltc2978_id[] = {
+       {"ltc2974", ltc2974},
        {"ltc2978", ltc2978},
        {"ltc3880", ltc3880},
+       {"ltc3883", ltc3883},
        {}
 };
 MODULE_DEVICE_TABLE(i2c, ltc2978_id);
@@ -304,10 +390,14 @@ static int ltc2978_probe(struct i2c_client *client,
        if (chip_id < 0)
                return chip_id;
 
-       if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
+       if (chip_id == LTC2974_ID) {
+               data->id = ltc2974;
+       } else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
                data->id = ltc2978;
        } else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) {
                data->id = ltc3880;
+       } else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) {
+               data->id = ltc3883;
        } else {
                dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
                return -ENODEV;
@@ -323,26 +413,45 @@ static int ltc2978_probe(struct i2c_client *client,
 
        data->vin_min = 0x7bff;
        data->vin_max = 0x7c00;
-       data->temp_min = 0x7bff;
+       for (i = 0; i < ARRAY_SIZE(data->vout_min); i++)
+               data->vout_min[i] = 0xffff;
+       for (i = 0; i < ARRAY_SIZE(data->iout_min); i++)
+               data->iout_min[i] = 0xfbff;
+       for (i = 0; i < ARRAY_SIZE(data->iout_max); i++)
+               data->iout_max[i] = 0x7c00;
+       for (i = 0; i < ARRAY_SIZE(data->temp_min); i++)
+               data->temp_min[i] = 0x7bff;
        for (i = 0; i < ARRAY_SIZE(data->temp_max); i++)
                data->temp_max[i] = 0x7c00;
        data->temp2_max = 0x7c00;
 
        switch (data->id) {
+       case ltc2974:
+               info->read_word_data = ltc2974_read_word_data;
+               info->pages = LTC2974_NUM_PAGES;
+               info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
+                 | PMBUS_HAVE_TEMP2;
+               for (i = 0; i < info->pages; i++) {
+                       info->func[i] |= PMBUS_HAVE_VOUT
+                         | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
+                         | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
+                         | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+               }
+               break;
        case ltc2978:
                info->read_word_data = ltc2978_read_word_data;
-               info->pages = 8;
+               info->pages = LTC2978_NUM_PAGES;
                info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
                  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
                  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
-               for (i = 1; i < 8; i++) {
+               for (i = 1; i < LTC2978_NUM_PAGES; i++) {
                        info->func[i] = PMBUS_HAVE_VOUT
                          | PMBUS_HAVE_STATUS_VOUT;
                }
                break;
        case ltc3880:
                info->read_word_data = ltc3880_read_word_data;
-               info->pages = 2;
+               info->pages = LTC3880_NUM_PAGES;
                info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
                  | PMBUS_HAVE_STATUS_INPUT
                  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
@@ -353,15 +462,20 @@ static int ltc2978_probe(struct i2c_client *client,
                  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
                  | PMBUS_HAVE_POUT
                  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
-               data->iout_max[0] = 0x7c00;
-               data->iout_max[1] = 0x7c00;
+               break;
+       case ltc3883:
+               info->read_word_data = ltc3883_read_word_data;
+               info->pages = LTC3883_NUM_PAGES;
+               info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
+                 | PMBUS_HAVE_STATUS_INPUT
+                 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+                 | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
+                 | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
                break;
        default:
                return -ENODEV;
        }
-       for (i = 0; i < info->pages; i++)
-               data->vout_min[i] = 0xffff;
-
        return pmbus_do_probe(client, id, info);
 }
 
@@ -378,5 +492,5 @@ static struct i2c_driver ltc2978_driver = {
 module_i2c_driver(ltc2978_driver);
 
 MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880");
+MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, and LTC3883");
 MODULE_LICENSE("GPL");
index ff2ae02..a9f7e80 100644 (file)
@@ -107,17 +107,14 @@ static ssize_t s3c_hwmon_show_raw(struct device *dev,
        return  (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret);
 }
 
-#define DEF_ADC_ATTR(x)        \
-       static SENSOR_DEVICE_ATTR(adc##x##_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, x)
-
-DEF_ADC_ATTR(0);
-DEF_ADC_ATTR(1);
-DEF_ADC_ATTR(2);
-DEF_ADC_ATTR(3);
-DEF_ADC_ATTR(4);
-DEF_ADC_ATTR(5);
-DEF_ADC_ATTR(6);
-DEF_ADC_ATTR(7);
+static SENSOR_DEVICE_ATTR(adc0_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 0);
+static SENSOR_DEVICE_ATTR(adc1_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 1);
+static SENSOR_DEVICE_ATTR(adc2_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 2);
+static SENSOR_DEVICE_ATTR(adc3_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 3);
+static SENSOR_DEVICE_ATTR(adc4_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 4);
+static SENSOR_DEVICE_ATTR(adc5_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 5);
+static SENSOR_DEVICE_ATTR(adc6_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 6);
+static SENSOR_DEVICE_ATTR(adc7_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 7);
 
 static struct attribute *s3c_hwmon_attrs[9] = {
        &sensor_dev_attr_adc0_raw.dev_attr.attr,
index d00b30a..7386819 100644 (file)
@@ -161,8 +161,8 @@ static int sch56xx_send_cmd(u16 addr, u8 cmd, u16 reg, u8 v)
                        break;
        }
        if (i == max_busy_polls + max_lazy_polls) {
-               pr_err("Max retries exceeded reading virtual "
-                      "register 0x%04hx (%d)\n", reg, 1);
+               pr_err("Max retries exceeded reading virtual register 0x%04hx (%d)\n",
+                      reg, 1);
                return -EIO;
        }
 
@@ -178,12 +178,12 @@ static int sch56xx_send_cmd(u16 addr, u8 cmd, u16 reg, u8 v)
                        break;
 
                if (i == 0)
-                       pr_warn("EC reports: 0x%02x reading virtual register "
-                               "0x%04hx\n", (unsigned int)val, reg);
+                       pr_warn("EC reports: 0x%02x reading virtual register 0x%04hx\n",
+                               (unsigned int)val, reg);
        }
        if (i == max_busy_polls) {
-               pr_err("Max retries exceeded reading virtual "
-                      "register 0x%04hx (%d)\n", reg, 2);
+               pr_err("Max retries exceeded reading virtual register 0x%04hx (%d)\n",
+                      reg, 2);
                return -EIO;
        }
 
index c35847a..1404e63 100644 (file)
@@ -456,8 +456,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
                data->fan_div[nr] = 3;
                break;
        default:
-               dev_err(dev, "fan_div value %ld not "
-                       "supported. Choose one of 1, 2, 4 or 8!\n", val);
+               dev_err(dev,
+                       "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
+                       val);
                mutex_unlock(&data->update_lock);
                return -EINVAL;
        }
index 4b59eb5..db288db 100644 (file)
@@ -41,8 +41,8 @@ enum chips { thmc50, adm1022 };
 static unsigned short adm1022_temp3[16];
 static unsigned int adm1022_temp3_num;
 module_param_array(adm1022_temp3, ushort, &adm1022_temp3_num, 0);
-MODULE_PARM_DESC(adm1022_temp3, "List of adapter,address pairs "
-                       "to enable 3rd temperature (ADM1022 only)");
+MODULE_PARM_DESC(adm1022_temp3,
+                "List of adapter,address pairs to enable 3rd temperature (ADM1022 only)");
 
 /* Many THMC50 constants specified below */
 
@@ -312,8 +312,7 @@ static int thmc50_detect(struct i2c_client *client,
        const char *type_name;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-               pr_debug("thmc50: detect failed, "
-                        "smbus byte data not supported!\n");
+               pr_debug("thmc50: detect failed, smbus byte data not supported!\n");
                return -ENODEV;
        }
 
index 523dd89..d7b47ab 100644 (file)
@@ -155,8 +155,8 @@ static int tmp102_probe(struct i2c_client *client,
 
        if (!i2c_check_functionality(client->adapter,
                                     I2C_FUNC_SMBUS_WORD_DATA)) {
-               dev_err(&client->dev, "adapter doesn't support SMBus word "
-                       "transactions\n");
+               dev_err(&client->dev,
+                       "adapter doesn't support SMBus word transactions\n");
                return -ENODEV;
        }
 
index c85f696..a478454 100644 (file)
@@ -5,6 +5,9 @@
  * Gabriel Konat, Sander Leget, Wouter Willems
  * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de>
  *
+ * Cleanup and support for TMP431 and TMP432 by Guenter Roeck
+ * Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net>
+ *
  * 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
@@ -30,6 +33,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
@@ -40,9 +44,9 @@
 #include <linux/sysfs.h>
 
 /* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
 
-enum chips { tmp401, tmp411 };
+enum chips { tmp401, tmp411, tmp431, tmp432 };
 
 /*
  * The TMP401 registers, note some registers have different addresses for
@@ -54,42 +58,84 @@ enum chips { tmp401, tmp411 };
 #define TMP401_CONVERSION_RATE_READ            0x04
 #define TMP401_CONVERSION_RATE_WRITE           0x0A
 #define TMP401_TEMP_CRIT_HYST                  0x21
-#define TMP401_CONSECUTIVE_ALERT               0x22
 #define TMP401_MANUFACTURER_ID_REG             0xFE
 #define TMP401_DEVICE_ID_REG                   0xFF
-#define TMP411_N_FACTOR_REG                    0x18
-
-static const u8 TMP401_TEMP_MSB[2]                     = { 0x00, 0x01 };
-static const u8 TMP401_TEMP_LSB[2]                     = { 0x15, 0x10 };
-static const u8 TMP401_TEMP_LOW_LIMIT_MSB_READ[2]      = { 0x06, 0x08 };
-static const u8 TMP401_TEMP_LOW_LIMIT_MSB_WRITE[2]     = { 0x0C, 0x0E };
-static const u8 TMP401_TEMP_LOW_LIMIT_LSB[2]           = { 0x17, 0x14 };
-static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_READ[2]     = { 0x05, 0x07 };
-static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[2]    = { 0x0B, 0x0D };
-static const u8 TMP401_TEMP_HIGH_LIMIT_LSB[2]          = { 0x16, 0x13 };
-/* These are called the THERM limit / hysteresis / mask in the datasheet */
-static const u8 TMP401_TEMP_CRIT_LIMIT[2]              = { 0x20, 0x19 };
-
-static const u8 TMP411_TEMP_LOWEST_MSB[2]              = { 0x30, 0x34 };
-static const u8 TMP411_TEMP_LOWEST_LSB[2]              = { 0x31, 0x35 };
-static const u8 TMP411_TEMP_HIGHEST_MSB[2]             = { 0x32, 0x36 };
-static const u8 TMP411_TEMP_HIGHEST_LSB[2]             = { 0x33, 0x37 };
+
+static const u8 TMP401_TEMP_MSB_READ[6][2] = {
+       { 0x00, 0x01 }, /* temp */
+       { 0x06, 0x08 }, /* low limit */
+       { 0x05, 0x07 }, /* high limit */
+       { 0x20, 0x19 }, /* therm (crit) limit */
+       { 0x30, 0x34 }, /* lowest */
+       { 0x32, 0x36 }, /* highest */
+};
+
+static const u8 TMP401_TEMP_MSB_WRITE[6][2] = {
+       { 0, 0 },       /* temp (unused) */
+       { 0x0C, 0x0E }, /* low limit */
+       { 0x0B, 0x0D }, /* high limit */
+       { 0x20, 0x19 }, /* therm (crit) limit */
+       { 0x30, 0x34 }, /* lowest */
+       { 0x32, 0x36 }, /* highest */
+};
+
+static const u8 TMP401_TEMP_LSB[6][2] = {
+       { 0x15, 0x10 }, /* temp */
+       { 0x17, 0x14 }, /* low limit */
+       { 0x16, 0x13 }, /* high limit */
+       { 0, 0 },       /* therm (crit) limit (unused) */
+       { 0x31, 0x35 }, /* lowest */
+       { 0x33, 0x37 }, /* highest */
+};
+
+static const u8 TMP432_TEMP_MSB_READ[4][3] = {
+       { 0x00, 0x01, 0x23 },   /* temp */
+       { 0x06, 0x08, 0x16 },   /* low limit */
+       { 0x05, 0x07, 0x15 },   /* high limit */
+       { 0x20, 0x19, 0x1A },   /* therm (crit) limit */
+};
+
+static const u8 TMP432_TEMP_MSB_WRITE[4][3] = {
+       { 0, 0, 0 },            /* temp  - unused */
+       { 0x0C, 0x0E, 0x16 },   /* low limit */
+       { 0x0B, 0x0D, 0x15 },   /* high limit */
+       { 0x20, 0x19, 0x1A },   /* therm (crit) limit */
+};
+
+static const u8 TMP432_TEMP_LSB[3][3] = {
+       { 0x29, 0x10, 0x24 },   /* temp */
+       { 0x3E, 0x14, 0x18 },   /* low limit */
+       { 0x3D, 0x13, 0x17 },   /* high limit */
+};
+
+/* [0] = fault, [1] = low, [2] = high, [3] = therm/crit */
+static const u8 TMP432_STATUS_REG[] = {
+       0x1b, 0x36, 0x35, 0x37 };
 
 /* Flags */
-#define TMP401_CONFIG_RANGE            0x04
-#define TMP401_CONFIG_SHUTDOWN         0x40
-#define TMP401_STATUS_LOCAL_CRIT               0x01
-#define TMP401_STATUS_REMOTE_CRIT              0x02
-#define TMP401_STATUS_REMOTE_OPEN              0x04
-#define TMP401_STATUS_REMOTE_LOW               0x08
-#define TMP401_STATUS_REMOTE_HIGH              0x10
-#define TMP401_STATUS_LOCAL_LOW                0x20
-#define TMP401_STATUS_LOCAL_HIGH               0x40
+#define TMP401_CONFIG_RANGE                    BIT(2)
+#define TMP401_CONFIG_SHUTDOWN                 BIT(6)
+#define TMP401_STATUS_LOCAL_CRIT               BIT(0)
+#define TMP401_STATUS_REMOTE_CRIT              BIT(1)
+#define TMP401_STATUS_REMOTE_OPEN              BIT(2)
+#define TMP401_STATUS_REMOTE_LOW               BIT(3)
+#define TMP401_STATUS_REMOTE_HIGH              BIT(4)
+#define TMP401_STATUS_LOCAL_LOW                        BIT(5)
+#define TMP401_STATUS_LOCAL_HIGH               BIT(6)
+
+/* On TMP432, each status has its own register */
+#define TMP432_STATUS_LOCAL                    BIT(0)
+#define TMP432_STATUS_REMOTE1                  BIT(1)
+#define TMP432_STATUS_REMOTE2                  BIT(2)
 
 /* Manufacturer / Device ID's */
 #define TMP401_MANUFACTURER_ID                 0x55
 #define TMP401_DEVICE_ID                       0x11
-#define TMP411_DEVICE_ID                       0x12
+#define TMP411A_DEVICE_ID                      0x12
+#define TMP411B_DEVICE_ID                      0x13
+#define TMP411C_DEVICE_ID                      0x10
+#define TMP431_DEVICE_ID                       0x31
+#define TMP432_DEVICE_ID                       0x32
 
 /*
  * Driver data (common to all clients)
@@ -98,6 +144,8 @@ static const u8 TMP411_TEMP_HIGHEST_LSB[2]           = { 0x33, 0x37 };
 static const struct i2c_device_id tmp401_id[] = {
        { "tmp401", tmp401 },
        { "tmp411", tmp411 },
+       { "tmp431", tmp431 },
+       { "tmp432", tmp432 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, tmp401_id);
@@ -113,16 +161,13 @@ struct tmp401_data {
        unsigned long last_updated; /* in jiffies */
        enum chips kind;
 
+       unsigned int update_interval;   /* in milliseconds */
+
        /* register values */
-       u8 status;
+       u8 status[4];
        u8 config;
-       u16 temp[2];
-       u16 temp_low[2];
-       u16 temp_high[2];
-       u8 temp_crit[2];
+       u16 temp[6][3];
        u8 temp_crit_hyst;
-       u16 temp_lowest[2];
-       u16 temp_highest[2];
 };
 
 /*
@@ -136,31 +181,10 @@ static int tmp401_register_to_temp(u16 reg, u8 config)
        if (config & TMP401_CONFIG_RANGE)
                temp -= 64 * 256;
 
-       return (temp * 625 + 80) / 160;
-}
-
-static u16 tmp401_temp_to_register(long temp, u8 config)
-{
-       if (config & TMP401_CONFIG_RANGE) {
-               temp = clamp_val(temp, -64000, 191000);
-               temp += 64000;
-       } else
-               temp = clamp_val(temp, 0, 127000);
-
-       return (temp * 160 + 312) / 625;
-}
-
-static int tmp401_crit_register_to_temp(u8 reg, u8 config)
-{
-       int temp = reg;
-
-       if (config & TMP401_CONFIG_RANGE)
-               temp -= 64;
-
-       return temp * 1000;
+       return DIV_ROUND_CLOSEST(temp * 125, 32);
 }
 
-static u8 tmp401_crit_temp_to_register(long temp, u8 config)
+static u16 tmp401_temp_to_register(long temp, u8 config, int zbits)
 {
        if (config & TMP401_CONFIG_RANGE) {
                temp = clamp_val(temp, -64000, 191000);
@@ -168,113 +192,127 @@ static u8 tmp401_crit_temp_to_register(long temp, u8 config)
        } else
                temp = clamp_val(temp, 0, 127000);
 
-       return (temp + 500) / 1000;
+       return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits;
 }
 
-static struct tmp401_data *tmp401_update_device_reg16(
-       struct i2c_client *client, struct tmp401_data *data)
+static int tmp401_update_device_reg16(struct i2c_client *client,
+                                     struct tmp401_data *data)
 {
-       int i;
-
-       for (i = 0; i < 2; i++) {
-               /*
-                * High byte must be read first immediately followed
-                * by the low byte
-                */
-               data->temp[i] = i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_MSB[i]) << 8;
-               data->temp[i] |= i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_LSB[i]);
-               data->temp_low[i] = i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8;
-               data->temp_low[i] |= i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_LOW_LIMIT_LSB[i]);
-               data->temp_high[i] = i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8;
-               data->temp_high[i] |= i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_HIGH_LIMIT_LSB[i]);
-               data->temp_crit[i] = i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_CRIT_LIMIT[i]);
-
-               if (data->kind == tmp411) {
-                       data->temp_lowest[i] = i2c_smbus_read_byte_data(client,
-                               TMP411_TEMP_LOWEST_MSB[i]) << 8;
-                       data->temp_lowest[i] |= i2c_smbus_read_byte_data(
-                               client, TMP411_TEMP_LOWEST_LSB[i]);
-
-                       data->temp_highest[i] = i2c_smbus_read_byte_data(
-                               client, TMP411_TEMP_HIGHEST_MSB[i]) << 8;
-                       data->temp_highest[i] |= i2c_smbus_read_byte_data(
-                               client, TMP411_TEMP_HIGHEST_LSB[i]);
+       int i, j, val;
+       int num_regs = data->kind == tmp411 ? 6 : 4;
+       int num_sensors = data->kind == tmp432 ? 3 : 2;
+
+       for (i = 0; i < num_sensors; i++) {             /* local / r1 / r2 */
+               for (j = 0; j < num_regs; j++) {        /* temp / low / ... */
+                       u8 regaddr;
+                       /*
+                        * High byte must be read first immediately followed
+                        * by the low byte
+                        */
+                       regaddr = data->kind == tmp432 ?
+                                               TMP432_TEMP_MSB_READ[j][i] :
+                                               TMP401_TEMP_MSB_READ[j][i];
+                       val = i2c_smbus_read_byte_data(client, regaddr);
+                       if (val < 0)
+                               return val;
+                       data->temp[j][i] = val << 8;
+                       if (j == 3)             /* crit is msb only */
+                               continue;
+                       regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[j][i]
+                                                      : TMP401_TEMP_LSB[j][i];
+                       val = i2c_smbus_read_byte_data(client, regaddr);
+                       if (val < 0)
+                               return val;
+                       data->temp[j][i] |= val;
                }
        }
-       return data;
+       return 0;
 }
 
 static struct tmp401_data *tmp401_update_device(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct tmp401_data *data = i2c_get_clientdata(client);
+       struct tmp401_data *ret = data;
+       int i, val;
+       unsigned long next_update;
 
        mutex_lock(&data->update_lock);
 
-       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
-               data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS);
-               data->config = i2c_smbus_read_byte_data(client,
-                                               TMP401_CONFIG_READ);
-               tmp401_update_device_reg16(client, data);
+       next_update = data->last_updated +
+                     msecs_to_jiffies(data->update_interval) + 1;
+       if (time_after(jiffies, next_update) || !data->valid) {
+               if (data->kind != tmp432) {
+                       /*
+                        * The driver uses the TMP432 status format internally.
+                        * Convert status to TMP432 format for other chips.
+                        */
+                       val = i2c_smbus_read_byte_data(client, TMP401_STATUS);
+                       if (val < 0) {
+                               ret = ERR_PTR(val);
+                               goto abort;
+                       }
+                       data->status[0] =
+                         (val & TMP401_STATUS_REMOTE_OPEN) >> 1;
+                       data->status[1] =
+                         ((val & TMP401_STATUS_REMOTE_LOW) >> 2) |
+                         ((val & TMP401_STATUS_LOCAL_LOW) >> 5);
+                       data->status[2] =
+                         ((val & TMP401_STATUS_REMOTE_HIGH) >> 3) |
+                         ((val & TMP401_STATUS_LOCAL_HIGH) >> 6);
+                       data->status[3] = val & (TMP401_STATUS_LOCAL_CRIT
+                                               | TMP401_STATUS_REMOTE_CRIT);
+               } else {
+                       for (i = 0; i < ARRAY_SIZE(data->status); i++) {
+                               val = i2c_smbus_read_byte_data(client,
+                                                       TMP432_STATUS_REG[i]);
+                               if (val < 0) {
+                                       ret = ERR_PTR(val);
+                                       goto abort;
+                               }
+                               data->status[i] = val;
+                       }
+               }
 
-               data->temp_crit_hyst = i2c_smbus_read_byte_data(client,
-                                               TMP401_TEMP_CRIT_HYST);
+               val = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
+               if (val < 0) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->config = val;
+               val = tmp401_update_device_reg16(client, data);
+               if (val < 0) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               val = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST);
+               if (val < 0) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->temp_crit_hyst = val;
 
                data->last_updated = jiffies;
                data->valid = 1;
        }
 
+abort:
        mutex_unlock(&data->update_lock);
-
-       return data;
-}
-
-static ssize_t show_temp_value(struct device *dev,
-       struct device_attribute *devattr, char *buf)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
-
-       return sprintf(buf, "%d\n",
-               tmp401_register_to_temp(data->temp[index], data->config));
-}
-
-static ssize_t show_temp_min(struct device *dev,
-       struct device_attribute *devattr, char *buf)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
-
-       return sprintf(buf, "%d\n",
-               tmp401_register_to_temp(data->temp_low[index], data->config));
+       return ret;
 }
 
-static ssize_t show_temp_max(struct device *dev,
-       struct device_attribute *devattr, char *buf)
+static ssize_t show_temp(struct device *dev,
+                        struct device_attribute *devattr, char *buf)
 {
-       int index = to_sensor_dev_attr(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int index = to_sensor_dev_attr_2(devattr)->index;
        struct tmp401_data *data = tmp401_update_device(dev);
 
-       return sprintf(buf, "%d\n",
-               tmp401_register_to_temp(data->temp_high[index], data->config));
-}
-
-static ssize_t show_temp_crit(struct device *dev,
-       struct device_attribute *devattr, char *buf)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
 
        return sprintf(buf, "%d\n",
-                       tmp401_crit_register_to_temp(data->temp_crit[index],
-                                                       data->config));
+               tmp401_register_to_temp(data->temp[nr][index], data->config));
 }
 
 static ssize_t show_temp_crit_hyst(struct device *dev,
@@ -283,122 +321,60 @@ static ssize_t show_temp_crit_hyst(struct device *dev,
        int temp, index = to_sensor_dev_attr(devattr)->index;
        struct tmp401_data *data = tmp401_update_device(dev);
 
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
        mutex_lock(&data->update_lock);
-       temp = tmp401_crit_register_to_temp(data->temp_crit[index],
-                                               data->config);
+       temp = tmp401_register_to_temp(data->temp[3][index], data->config);
        temp -= data->temp_crit_hyst * 1000;
        mutex_unlock(&data->update_lock);
 
        return sprintf(buf, "%d\n", temp);
 }
 
-static ssize_t show_temp_lowest(struct device *dev,
-       struct device_attribute *devattr, char *buf)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
-
-       return sprintf(buf, "%d\n",
-               tmp401_register_to_temp(data->temp_lowest[index],
-                                       data->config));
-}
-
-static ssize_t show_temp_highest(struct device *dev,
-       struct device_attribute *devattr, char *buf)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
-
-       return sprintf(buf, "%d\n",
-               tmp401_register_to_temp(data->temp_highest[index],
-                                       data->config));
-}
-
 static ssize_t show_status(struct device *dev,
        struct device_attribute *devattr, char *buf)
 {
-       int mask = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
-
-       if (data->status & mask)
-               return sprintf(buf, "1\n");
-       else
-               return sprintf(buf, "0\n");
-}
-
-static ssize_t store_temp_min(struct device *dev, struct device_attribute
-       *devattr, const char *buf, size_t count)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int mask = to_sensor_dev_attr_2(devattr)->index;
        struct tmp401_data *data = tmp401_update_device(dev);
-       long val;
-       u16 reg;
-
-       if (kstrtol(buf, 10, &val))
-               return -EINVAL;
-
-       reg = tmp401_temp_to_register(val, data->config);
-
-       mutex_lock(&data->update_lock);
-
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP401_TEMP_LOW_LIMIT_MSB_WRITE[index], reg >> 8);
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP401_TEMP_LOW_LIMIT_LSB[index], reg & 0xFF);
-
-       data->temp_low[index] = reg;
 
-       mutex_unlock(&data->update_lock);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
 
-       return count;
+       return sprintf(buf, "%d\n", !!(data->status[nr] & mask));
 }
 
-static ssize_t store_temp_max(struct device *dev, struct device_attribute
-       *devattr, const char *buf, size_t count)
+static ssize_t store_temp(struct device *dev, struct device_attribute *devattr,
+                         const char *buf, size_t count)
 {
-       int index = to_sensor_dev_attr(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int index = to_sensor_dev_attr_2(devattr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
        struct tmp401_data *data = tmp401_update_device(dev);
        long val;
        u16 reg;
+       u8 regaddr;
 
-       if (kstrtol(buf, 10, &val))
-               return -EINVAL;
-
-       reg = tmp401_temp_to_register(val, data->config);
-
-       mutex_lock(&data->update_lock);
-
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[index], reg >> 8);
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP401_TEMP_HIGH_LIMIT_LSB[index], reg & 0xFF);
-
-       data->temp_high[index] = reg;
-
-       mutex_unlock(&data->update_lock);
-
-       return count;
-}
-
-static ssize_t store_temp_crit(struct device *dev, struct device_attribute
-       *devattr, const char *buf, size_t count)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
-       long val;
-       u8 reg;
+       if (IS_ERR(data))
+               return PTR_ERR(data);
 
        if (kstrtol(buf, 10, &val))
                return -EINVAL;
 
-       reg = tmp401_crit_temp_to_register(val, data->config);
+       reg = tmp401_temp_to_register(val, data->config, nr == 3 ? 8 : 4);
 
        mutex_lock(&data->update_lock);
 
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP401_TEMP_CRIT_LIMIT[index], reg);
-
-       data->temp_crit[index] = reg;
+       regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_WRITE[nr][index]
+                                      : TMP401_TEMP_MSB_WRITE[nr][index];
+       i2c_smbus_write_byte_data(client, regaddr, reg >> 8);
+       if (nr != 3) {
+               regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[nr][index]
+                                              : TMP401_TEMP_LSB[nr][index];
+               i2c_smbus_write_byte_data(client, regaddr, reg & 0xFF);
+       }
+       data->temp[nr][index] = reg;
 
        mutex_unlock(&data->update_lock);
 
@@ -413,6 +389,9 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
        long val;
        u8 reg;
 
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
        if (kstrtol(buf, 10, &val))
                return -EINVAL;
 
@@ -422,13 +401,12 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
                val = clamp_val(val, 0, 127000);
 
        mutex_lock(&data->update_lock);
-       temp = tmp401_crit_register_to_temp(data->temp_crit[index],
-                                               data->config);
+       temp = tmp401_register_to_temp(data->temp[3][index], data->config);
        val = clamp_val(val, temp - 255000, temp);
        reg = ((temp - val) + 500) / 1000;
 
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP401_TEMP_CRIT_HYST, reg);
+       i2c_smbus_write_byte_data(to_i2c_client(dev), TMP401_TEMP_CRIT_HYST,
+                                 reg);
 
        data->temp_crit_hyst = reg;
 
@@ -445,54 +423,130 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
 static ssize_t reset_temp_history(struct device *dev,
        struct device_attribute *devattr, const char *buf, size_t count)
 {
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tmp401_data *data = i2c_get_clientdata(client);
        long val;
 
        if (kstrtol(buf, 10, &val))
                return -EINVAL;
 
        if (val != 1) {
-               dev_err(dev, "temp_reset_history value %ld not"
-                       " supported. Use 1 to reset the history!\n", val);
+               dev_err(dev,
+                       "temp_reset_history value %ld not supported. Use 1 to reset the history!\n",
+                       val);
                return -EINVAL;
        }
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP411_TEMP_LOWEST_MSB[0], val);
+       mutex_lock(&data->update_lock);
+       i2c_smbus_write_byte_data(client, TMP401_TEMP_MSB_WRITE[5][0], val);
+       data->valid = 0;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_update_interval(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tmp401_data *data = i2c_get_clientdata(client);
+
+       return sprintf(buf, "%u\n", data->update_interval);
+}
+
+static ssize_t set_update_interval(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tmp401_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+       int err, rate;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err)
+               return err;
+
+       /*
+        * For valid rates, interval can be calculated as
+        *      interval = (1 << (7 - rate)) * 125;
+        * Rounded rate is therefore
+        *      rate = 7 - __fls(interval * 4 / (125 * 3));
+        * Use clamp_val() to avoid overflows, and to ensure valid input
+        * for __fls.
+        */
+       val = clamp_val(val, 125, 16000);
+       rate = 7 - __fls(val * 4 / (125 * 3));
+       mutex_lock(&data->update_lock);
+       i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, rate);
+       data->update_interval = (1 << (7 - rate)) * 125;
+       mutex_unlock(&data->update_lock);
 
        return count;
 }
 
-static struct sensor_device_attribute tmp401_attr[] = {
-       SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0),
-       SENSOR_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
-                   store_temp_min, 0),
-       SENSOR_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
-                   store_temp_max, 0),
-       SENSOR_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit,
-                   store_temp_crit, 0),
-       SENSOR_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_crit_hyst,
-                   store_temp_crit_hyst, 0),
-       SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_LOCAL_LOW),
-       SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_LOCAL_HIGH),
-       SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_LOCAL_CRIT),
-       SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1),
-       SENSOR_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
-                   store_temp_min, 1),
-       SENSOR_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
-                   store_temp_max, 1),
-       SENSOR_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit,
-                   store_temp_crit, 1),
-       SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
-       SENSOR_ATTR(temp2_fault, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_REMOTE_OPEN),
-       SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_REMOTE_LOW),
-       SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_REMOTE_HIGH),
-       SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_REMOTE_CRIT),
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 3, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
+                         show_temp_crit_hyst, store_temp_crit_hyst, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_status, NULL,
+                           1, TMP432_STATUS_LOCAL);
+static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_status, NULL,
+                           2, TMP432_STATUS_LOCAL);
+static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_status, NULL,
+                           3, TMP432_STATUS_LOCAL);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 1, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 3, 1);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst,
+                         NULL, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_status, NULL,
+                           0, TMP432_STATUS_REMOTE1);
+static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_status, NULL,
+                           1, TMP432_STATUS_REMOTE1);
+static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_status, NULL,
+                           2, TMP432_STATUS_REMOTE1);
+static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_status, NULL,
+                           3, TMP432_STATUS_REMOTE1);
+
+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
+                  set_update_interval);
+
+static struct attribute *tmp401_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+
+       &dev_attr_update_interval.attr,
+
+       NULL
+};
+
+static const struct attribute_group tmp401_group = {
+       .attrs = tmp401_attributes,
 };
 
 /*
@@ -502,12 +556,60 @@ static struct sensor_device_attribute tmp401_attr[] = {
  * minimum and maximum register reset for both the local
  * and remote channels.
  */
-static struct sensor_device_attribute tmp411_attr[] = {
-       SENSOR_ATTR(temp1_highest, S_IRUGO, show_temp_highest, NULL, 0),
-       SENSOR_ATTR(temp1_lowest, S_IRUGO, show_temp_lowest, NULL, 0),
-       SENSOR_ATTR(temp2_highest, S_IRUGO, show_temp_highest, NULL, 1),
-       SENSOR_ATTR(temp2_lowest, S_IRUGO, show_temp_lowest, NULL, 1),
-       SENSOR_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, 0),
+static SENSOR_DEVICE_ATTR_2(temp1_lowest, S_IRUGO, show_temp, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_highest, S_IRUGO, show_temp, NULL, 5, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_lowest, S_IRUGO, show_temp, NULL, 4, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_highest, S_IRUGO, show_temp, NULL, 5, 1);
+static SENSOR_DEVICE_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history,
+                         0);
+
+static struct attribute *tmp411_attributes[] = {
+       &sensor_dev_attr_temp1_highest.dev_attr.attr,
+       &sensor_dev_attr_temp1_lowest.dev_attr.attr,
+       &sensor_dev_attr_temp2_highest.dev_attr.attr,
+       &sensor_dev_attr_temp2_lowest.dev_attr.attr,
+       &sensor_dev_attr_temp_reset_history.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group tmp411_group = {
+       .attrs = tmp411_attributes,
+};
+
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 1, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 2, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 3, 2);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst,
+                         NULL, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_status, NULL,
+                           0, TMP432_STATUS_REMOTE2);
+static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_status, NULL,
+                           1, TMP432_STATUS_REMOTE2);
+static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_status, NULL,
+                           2, TMP432_STATUS_REMOTE2);
+static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_status, NULL,
+                           3, TMP432_STATUS_REMOTE2);
+
+static struct attribute *tmp432_attributes[] = {
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
+       &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+
+       NULL
+};
+
+static const struct attribute_group tmp432_group = {
+       .attrs = tmp432_attributes,
 };
 
 /*
@@ -517,9 +619,11 @@ static struct sensor_device_attribute tmp411_attr[] = {
 static void tmp401_init_client(struct i2c_client *client)
 {
        int config, config_orig;
+       struct tmp401_data *data = i2c_get_clientdata(client);
 
        /* Set the conversion rate to 2 Hz */
        i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5);
+       data->update_interval = 500;
 
        /* Start conversions (disable shutdown if necessary) */
        config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
@@ -554,11 +658,35 @@ static int tmp401_detect(struct i2c_client *client,
 
        switch (reg) {
        case TMP401_DEVICE_ID:
+               if (client->addr != 0x4c)
+                       return -ENODEV;
                kind = tmp401;
                break;
-       case TMP411_DEVICE_ID:
+       case TMP411A_DEVICE_ID:
+               if (client->addr != 0x4c)
+                       return -ENODEV;
+               kind = tmp411;
+               break;
+       case TMP411B_DEVICE_ID:
+               if (client->addr != 0x4d)
+                       return -ENODEV;
                kind = tmp411;
                break;
+       case TMP411C_DEVICE_ID:
+               if (client->addr != 0x4e)
+                       return -ENODEV;
+               kind = tmp411;
+               break;
+       case TMP431_DEVICE_ID:
+               if (client->addr == 0x4e)
+                       return -ENODEV;
+               kind = tmp431;
+               break;
+       case TMP432_DEVICE_ID:
+               if (client->addr == 0x4e)
+                       return -ENODEV;
+               kind = tmp432;
+               break;
        default:
                return -ENODEV;
        }
@@ -579,20 +707,19 @@ static int tmp401_detect(struct i2c_client *client,
 
 static int tmp401_remove(struct i2c_client *client)
 {
+       struct device *dev = &client->dev;
        struct tmp401_data *data = i2c_get_clientdata(client);
-       int i;
 
        if (data->hwmon_dev)
                hwmon_device_unregister(data->hwmon_dev);
 
-       for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++)
-               device_remove_file(&client->dev, &tmp401_attr[i].dev_attr);
+       sysfs_remove_group(&dev->kobj, &tmp401_group);
 
-       if (data->kind == tmp411) {
-               for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
-                       device_remove_file(&client->dev,
-                                          &tmp411_attr[i].dev_attr);
-       }
+       if (data->kind == tmp411)
+               sysfs_remove_group(&dev->kobj, &tmp411_group);
+
+       if (data->kind == tmp432)
+               sysfs_remove_group(&dev->kobj, &tmp432_group);
 
        return 0;
 }
@@ -600,12 +727,12 @@ static int tmp401_remove(struct i2c_client *client)
 static int tmp401_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
-       int i, err = 0;
+       struct device *dev = &client->dev;
+       int err;
        struct tmp401_data *data;
-       const char *names[] = { "TMP401", "TMP411" };
+       const char *names[] = { "TMP401", "TMP411", "TMP431", "TMP432" };
 
-       data = devm_kzalloc(&client->dev, sizeof(struct tmp401_data),
-                           GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -617,31 +744,32 @@ static int tmp401_probe(struct i2c_client *client,
        tmp401_init_client(client);
 
        /* Register sysfs hooks */
-       for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) {
-               err = device_create_file(&client->dev,
-                                        &tmp401_attr[i].dev_attr);
+       err = sysfs_create_group(&dev->kobj, &tmp401_group);
+       if (err)
+               return err;
+
+       /* Register additional tmp411 sysfs hooks */
+       if (data->kind == tmp411) {
+               err = sysfs_create_group(&dev->kobj, &tmp411_group);
                if (err)
                        goto exit_remove;
        }
 
-       /* Register additional tmp411 sysfs hooks */
-       if (data->kind == tmp411) {
-               for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) {
-                       err = device_create_file(&client->dev,
-                                                &tmp411_attr[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
+       /* Register additional tmp432 sysfs hooks */
+       if (data->kind == tmp432) {
+               err = sysfs_create_group(&dev->kobj, &tmp432_group);
+               if (err)
+                       goto exit_remove;
        }
 
-       data->hwmon_dev = hwmon_device_register(&client->dev);
+       data->hwmon_dev = hwmon_device_register(dev);
        if (IS_ERR(data->hwmon_dev)) {
                err = PTR_ERR(data->hwmon_dev);
                data->hwmon_dev = NULL;
                goto exit_remove;
        }
 
-       dev_info(&client->dev, "Detected TI %s chip\n", names[data->kind]);
+       dev_info(dev, "Detected TI %s chip\n", names[data->kind]);
 
        return 0;
 
index 6a8ded2..964c1d6 100644 (file)
@@ -208,8 +208,8 @@ static int tmp421_init_client(struct i2c_client *client)
        /* Start conversions (disable shutdown if necessary) */
        config = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
        if (config < 0) {
-               dev_err(&client->dev, "Could not read configuration"
-                        " register (%d)\n", config);
+               dev_err(&client->dev,
+                       "Could not read configuration register (%d)\n", config);
                return -ENODEV;
        }
 
@@ -322,6 +322,5 @@ static struct i2c_driver tmp421_driver = {
 module_i2c_driver(tmp421_driver);
 
 MODULE_AUTHOR("Andre Prendel <andre.prendel@gmx.de>");
-MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor"
-                  " driver");
+MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor driver");
 MODULE_LICENSE("GPL");
index 3123b30..c9dcce8 100644 (file)
@@ -125,7 +125,7 @@ static const u8 VIA686A_REG_TEMP_HYST[]     = { 0x3a, 0x3e, 0x1e };
  * (These conversions were contributed by Jonathan Teh Soon Yew
  * <j.teh@iname.com>)
  */
-static inline u8 IN_TO_REG(long val, int inNum)
+static inline u8 IN_TO_REG(long val, int in_num)
 {
        /*
         * To avoid floating point, we multiply constants by 10 (100 for +12V).
@@ -134,29 +134,29 @@ static inline u8 IN_TO_REG(long val, int inNum)
         * by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
         * for the constants.
         */
-       if (inNum <= 1)
+       if (in_num <= 1)
                return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255);
-       else if (inNum == 2)
+       else if (in_num == 2)
                return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255);
-       else if (inNum == 3)
+       else if (in_num == 3)
                return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255);
        else
                return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0,
                                      255);
 }
 
-static inline long IN_FROM_REG(u8 val, int inNum)
+static inline long IN_FROM_REG(u8 val, int in_num)
 {
        /*
         * To avoid floating point, we multiply constants by 10 (100 for +12V).
         * We also multiply them by 1000 because we want 0.001V/bit for the
         * output value. Rounding is done.
         */
-       if (inNum <= 1)
+       if (in_num <= 1)
                return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
-       else if (inNum == 2)
+       else if (in_num == 2)
                return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
-       else if (inNum == 3)
+       else if (in_num == 3)
                return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
        else
                return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
@@ -210,10 +210,10 @@ static inline u8 FAN_TO_REG(long rpm, int div)
  * VIA register values 0-255.  I *10 before rounding, so we get tenth-degree
  * precision.  (I could have done all 1024 values for our 10-bit readings,
  * but the function is very linear in the useful range (0-80 deg C), so
- * we'll just use linear interpolation for 10-bit readings.)  So, tempLUT
+ * we'll just use linear interpolation for 10-bit readings.)  So, temp_lut
  * is the temp at via register values 0-255:
  */
-static const s16 tempLUT[] = {
+static const s16 temp_lut[] = {
        -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
        -503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
        -362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
@@ -261,7 +261,7 @@ static const s16 tempLUT[] = {
  * - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
  * Note that n=161:
  */
-static const u8 viaLUT[] = {
+static const u8 via_lut[] = {
        12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
        23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
        41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
@@ -284,26 +284,26 @@ static const u8 viaLUT[] = {
  */
 static inline u8 TEMP_TO_REG(long val)
 {
-       return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
+       return via_lut[val <= -50000 ? 0 : val >= 110000 ? 160 :
                      (val < 0 ? val - 500 : val + 500) / 1000 + 50];
 }
 
 /* for 8-bit temperature hyst and over registers */
-#define TEMP_FROM_REG(val)     ((long)tempLUT[val] * 100)
+#define TEMP_FROM_REG(val)     ((long)temp_lut[val] * 100)
 
 /* for 10-bit temperature readings */
 static inline long TEMP_FROM_REG10(u16 val)
 {
-       u16 eightBits = val >> 2;
-       u16 twoBits = val & 3;
+       u16 eight_bits = val >> 2;
+       u16 two_bits = val & 3;
 
        /* no interpolation for these */
-       if (twoBits == 0 || eightBits == 255)
-               return TEMP_FROM_REG(eightBits);
+       if (two_bits == 0 || eight_bits == 255)
+               return TEMP_FROM_REG(eight_bits);
 
        /* do some linear interpolation */
-       return (tempLUT[eightBits] * (4 - twoBits) +
-               tempLUT[eightBits + 1] * twoBits) * 25;
+       return (temp_lut[eight_bits] * (4 - two_bits) +
+               temp_lut[eight_bits + 1] * two_bits) * 25;
 }
 
 #define DIV_FROM_REG(val) (1 << (val))
@@ -889,8 +889,8 @@ static int via686a_pci_probe(struct pci_dev *dev,
 
        address = val & ~(VIA686A_EXTENT - 1);
        if (address == 0) {
-               dev_err(&dev->dev, "base address not set - upgrade BIOS "
-                       "or use force_addr=0xaddr\n");
+               dev_err(&dev->dev,
+                       "base address not set - upgrade BIOS or use force_addr=0xaddr\n");
                return -ENODEV;
        }
 
@@ -899,8 +899,9 @@ static int via686a_pci_probe(struct pci_dev *dev,
                return -ENODEV;
        if (!(val & 0x0001)) {
                if (!force_addr) {
-                       dev_warn(&dev->dev, "Sensors disabled, enable "
-                                "with force_addr=0x%x\n", address);
+                       dev_warn(&dev->dev,
+                                "Sensors disabled, enable with force_addr=0x%x\n",
+                                address);
                        return -ENODEV;
                }
 
index dcc62f8..6b2f1a4 100644 (file)
@@ -571,8 +571,9 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
                        break;
                default:
                        count = -EINVAL;
-                       dev_warn(dev, "fan div value %ld not supported. "
-                                "Choose one of 1, 2, 4, or 8.\n", val);
+                       dev_warn(dev,
+                                "fan div value %ld not supported. Choose one of 1, 2, 4, or 8.\n",
+                                val);
                        goto EXIT;
                }
                vt1211_write8(data, VT1211_REG_FAN_DIV,
@@ -674,8 +675,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                        break;
                default:
                        count = -EINVAL;
-                       dev_warn(dev, "pwm mode %ld not supported. "
-                                "Choose one of 0 or 2.\n", val);
+                       dev_warn(dev,
+                                "pwm mode %ld not supported. Choose one of 0 or 2.\n",
+                                val);
                        goto EXIT;
                }
                vt1211_write8(data, VT1211_REG_PWM_CTL,
@@ -700,8 +702,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
        case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
                if (val < 1 || val > 7) {
                        count = -EINVAL;
-                       dev_warn(dev, "temp channel %ld not supported. "
-                                "Choose a value between 1 and 7.\n", val);
+                       dev_warn(dev,
+                                "temp channel %ld not supported. Choose a value between 1 and 7.\n",
+                                val);
                        goto EXIT;
                }
                if (!ISTEMP(val - 1, data->uch_config)) {
@@ -1325,15 +1328,15 @@ static int __init vt1211_init(void)
 
        if ((uch_config < -1) || (uch_config > 31)) {
                err = -EINVAL;
-               pr_warn("Invalid UCH configuration %d. "
-                       "Choose a value between 0 and 31.\n", uch_config);
+               pr_warn("Invalid UCH configuration %d. Choose a value between 0 and 31.\n",
+                       uch_config);
                goto EXIT;
        }
 
        if ((int_mode < -1) || (int_mode > 0)) {
                err = -EINVAL;
-               pr_warn("Invalid interrupt mode %d. "
-                       "Only mode 0 is supported.\n", int_mode);
+               pr_warn("Invalid interrupt mode %d. Only mode 0 is supported.\n",
+                       int_mode);
                goto EXIT;
        }
 
index 988a2a7..0e70178 100644 (file)
@@ -573,8 +573,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
                data->fan_div[nr] = 3;
                break;
        default:
-               dev_err(dev, "fan_div value %ld not supported. "
-                       "Choose one of 1, 2, 4 or 8!\n", val);
+               dev_err(dev,
+                       "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
+                       val);
                mutex_unlock(&data->update_lock);
                return -EINVAL;
        }
index 0a89211..0160272 100644 (file)
@@ -840,8 +840,8 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
                            && (reg >= 0xff || (sio_data->kind == nct6775
                                                && reg == 0x00))
                            && data->fan_div[i] < 0x07) {
-                               dev_dbg(dev, "Increasing fan%d "
-                                       "clock divider from %u to %u\n",
+                               dev_dbg(dev,
+                                       "Increasing fan%d clock divider from %u to %u\n",
                                        i + 1, div_from_reg(data->fan_div[i]),
                                        div_from_reg(data->fan_div[i] + 1));
                                data->fan_div[i]++;
@@ -1110,9 +1110,9 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
                 */
                data->fan_min[nr] = 254;
                new_div = 7; /* 128 == (1 << 7) */
-               dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
-                        "minimum\n", nr + 1, val,
-                        data->fan_from_reg_min(254, 7));
+               dev_warn(dev,
+                        "fan%u low limit %lu below minimum %u, set to minimum\n",
+                        nr + 1, val, data->fan_from_reg_min(254, 7));
        } else if (!reg) {
                /*
                 * Speed above this value cannot possibly be represented,
@@ -1120,9 +1120,9 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
                 */
                data->fan_min[nr] = 1;
                new_div = 0; /* 1 == (1 << 0) */
-               dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
-                        "maximum\n", nr + 1, val,
-                        data->fan_from_reg_min(1, 0));
+               dev_warn(dev,
+                        "fan%u low limit %lu above maximum %u, set to maximum\n",
+                        nr + 1, val, data->fan_from_reg_min(1, 0));
        } else {
                /*
                 * Automatically pick the best divider, i.e. the one such
@@ -2396,15 +2396,15 @@ static int w83627ehf_probe(struct platform_device *pdev)
                                en_vrm10 = superio_inb(sio_data->sioreg,
                                                       SIO_REG_EN_VRM10);
                                if ((en_vrm10 & 0x08) && data->vrm == 90) {
-                                       dev_warn(dev, "Setting VID input "
-                                                "voltage to TTL\n");
+                                       dev_warn(dev,
+                                                "Setting VID input voltage to TTL\n");
                                        superio_outb(sio_data->sioreg,
                                                     SIO_REG_EN_VRM10,
                                                     en_vrm10 & ~0x08);
                                } else if (!(en_vrm10 & 0x08)
                                           && data->vrm == 100) {
-                                       dev_warn(dev, "Setting VID input "
-                                                "voltage to VRM10\n");
+                                       dev_warn(dev,
+                                                "Setting VID input voltage to VRM10\n");
                                        superio_outb(sio_data->sioreg,
                                                     SIO_REG_EN_VRM10,
                                                     en_vrm10 | 0x08);
@@ -2420,8 +2420,8 @@ static int w83627ehf_probe(struct platform_device *pdev)
                        if (err)
                                goto exit_release;
                } else {
-                       dev_info(dev, "VID pins in output mode, CPU VID not "
-                                "available\n");
+                       dev_info(dev,
+                                "VID pins in output mode, CPU VID not available\n");
                }
        }
 
@@ -2795,8 +2795,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
        /* Activate logical device if needed */
        val = superio_inb(sioaddr, SIO_REG_ENABLE);
        if (!(val & 0x01)) {
-               pr_warn("Forcibly enabling Super-I/O. "
-                       "Sensor is probably unusable.\n");
+               pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
                superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
        }
 
index aeec5b1..f9d5139 100644 (file)
@@ -64,8 +64,8 @@ enum chips { w83781d, w83782d, w83783s, as99127f };
 /* Insmod parameters */
 static unsigned short force_subclients[4];
 module_param_array(force_subclients, short, NULL, 0);
-MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
-                   "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+MODULE_PARM_DESC(force_subclients,
+                "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
 
 static bool reset;
 module_param(reset, bool, 0);
@@ -826,8 +826,9 @@ store_sensor(struct device *dev, struct device_attribute *da,
                data->sens[nr] = val;
                break;
        case W83781D_DEFAULT_BETA:
-               dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
-                        "instead\n", W83781D_DEFAULT_BETA);
+               dev_warn(dev,
+                        "Sensor type %d is deprecated, please use 4 instead\n",
+                        W83781D_DEFAULT_BETA);
                /* fall through */
        case 4:         /* thermistor */
                tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
@@ -874,8 +875,8 @@ w83781d_detect_subclients(struct i2c_client *new_client)
                for (i = 2; i <= 3; i++) {
                        if (force_subclients[i] < 0x48 ||
                            force_subclients[i] > 0x4f) {
-                               dev_err(&new_client->dev, "Invalid subclient "
-                                       "address %d; must be 0x48-0x4f\n",
+                               dev_err(&new_client->dev,
+                                       "Invalid subclient address %d; must be 0x48-0x4f\n",
                                        force_subclients[i]);
                                err = -EINVAL;
                                goto ERROR_SC_1;
@@ -910,9 +911,9 @@ w83781d_detect_subclients(struct i2c_client *new_client)
        for (i = 0; i < num_sc; i++) {
                data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
                if (!data->lm75[i]) {
-                       dev_err(&new_client->dev, "Subclient %d "
-                               "registration at address 0x%x "
-                               "failed.\n", i, sc_addr[i]);
+                       dev_err(&new_client->dev,
+                               "Subclient %d registration at address 0x%x failed.\n",
+                               i, sc_addr[i]);
                        err = -ENOMEM;
                        if (i == 1)
                                goto ERROR_SC_3;
@@ -1176,8 +1177,9 @@ w83781d_detect(struct i2c_client *client, struct i2c_board_info *info)
                goto err_nodev;
 
        if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
-               dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
-                       "be the same as ISA device\n", address);
+               dev_dbg(&adapter->dev,
+                       "Device at 0x%02x appears to be the same as ISA device\n",
+                       address);
                goto err_nodev;
        }
 
@@ -1367,8 +1369,8 @@ w83781d_init_device(struct device *dev)
                 * as I see very little reason why this would be needed at
                 * all.
                 */
-               dev_info(dev, "If reset=1 solved a problem you were "
-                        "having, please report!\n");
+               dev_info(dev,
+                        "If reset=1 solved a problem you were having, please report!\n");
 
                /* save these registers */
                i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
@@ -1425,8 +1427,8 @@ w83781d_init_device(struct device *dev)
                /* Enable temp2 */
                tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
                if (tmp & 0x01) {
-                       dev_warn(dev, "Enabling temp2, readings "
-                                "might not make sense\n");
+                       dev_warn(dev,
+                                "Enabling temp2, readings might not make sense\n");
                        w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
                                tmp & 0xfe);
                }
@@ -1436,8 +1438,8 @@ w83781d_init_device(struct device *dev)
                        tmp = w83781d_read_value(data,
                                W83781D_REG_TEMP3_CONFIG);
                        if (tmp & 0x01) {
-                               dev_warn(dev, "Enabling temp3, "
-                                        "readings might not make sense\n");
+                               dev_warn(dev,
+                                        "Enabling temp3, readings might not make sense\n");
                                w83781d_write_value(data,
                                        W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
                        }
index 38ddddd..a3feee3 100644 (file)
@@ -56,8 +56,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
 
 static unsigned short force_subclients[4];
 module_param_array(force_subclients, short, NULL, 0);
-MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
-                       "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+MODULE_PARM_DESC(force_subclients,
+                "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
 
 static bool reset;
 module_param(reset, bool, 0);
index 5cb83dd..0b80489 100644 (file)
@@ -54,8 +54,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
 
 static unsigned short force_subclients[4];
 module_param_array(force_subclients, short, NULL, 0);
-MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
-                       "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+MODULE_PARM_DESC(force_subclients,
+                "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
 
 static bool init;
 module_param(init, bool, 0);
@@ -951,8 +951,8 @@ w83792d_detect_subclients(struct i2c_client *new_client)
                for (i = 2; i <= 3; i++) {
                        if (force_subclients[i] < 0x48 ||
                            force_subclients[i] > 0x4f) {
-                               dev_err(&new_client->dev, "invalid subclient "
-                                       "address %d; must be 0x48-0x4f\n",
+                               dev_err(&new_client->dev,
+                                       "invalid subclient address %d; must be 0x48-0x4f\n",
                                        force_subclients[i]);
                                err = -ENODEV;
                                goto ERROR_SC_0;
@@ -969,8 +969,9 @@ w83792d_detect_subclients(struct i2c_client *new_client)
        if (!(val & 0x80)) {
                if ((data->lm75[0] != NULL) &&
                        ((val & 0x7) == ((val >> 4) & 0x7))) {
-                       dev_err(&new_client->dev, "duplicate addresses 0x%x, "
-                               "use force_subclient\n", data->lm75[0]->addr);
+                       dev_err(&new_client->dev,
+                               "duplicate addresses 0x%x, use force_subclient\n",
+                               data->lm75[0]->addr);
                        err = -ENODEV;
                        goto ERROR_SC_1;
                }
index 6604275..b0c30a5 100644 (file)
@@ -59,8 +59,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
 
 static unsigned short force_subclients[4];
 module_param_array(force_subclients, short, NULL, 0);
-MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
-                      "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+MODULE_PARM_DESC(force_subclients,
+                "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
 
 static bool reset;
 module_param(reset, bool, 0);
@@ -1921,8 +1921,8 @@ static int w83793_probe(struct i2c_client *client,
        }
        if (i == ARRAY_SIZE(watchdog_minors)) {
                data->watchdog_miscdev.minor = 0;
-               dev_warn(&client->dev, "Couldn't register watchdog chardev "
-                       "(due to no free minor)\n");
+               dev_warn(&client->dev,
+                        "Couldn't register watchdog chardev (due to no free minor)\n");
        }
 
        mutex_unlock(&watchdog_data_mutex);
index e226096..908209d 100644 (file)
@@ -2120,11 +2120,12 @@ static void w83795_check_dynamic_in_limits(struct i2c_client *client)
                                           &w83795_in[i][3].dev_attr.attr,
                                           S_IRUGO);
                if (err_max || err_min)
-                       dev_warn(&client->dev, "Failed to set in%d limits "
-                                "read-only (%d, %d)\n", i, err_max, err_min);
+                       dev_warn(&client->dev,
+                                "Failed to set in%d limits read-only (%d, %d)\n",
+                                i, err_max, err_min);
                else
-                       dev_info(&client->dev, "in%d limits set dynamically "
-                                "from VID\n", i);
+                       dev_info(&client->dev,
+                                "in%d limits set dynamically from VID\n", i);
        }
 }
 
index 5d66750..1a38dd7 100644 (file)
@@ -465,6 +465,7 @@ static const struct x86_cpu_id intel_idle_ids[] = {
        ICPU(0x3c, idle_cpu_hsw),
        ICPU(0x3f, idle_cpu_hsw),
        ICPU(0x45, idle_cpu_hsw),
+       ICPU(0x46, idle_cpu_hsw),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
index 1daa979..0bfd8cf 100644 (file)
@@ -359,7 +359,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
                case 0x802: /* Intuos4 General Pen */
                case 0x804: /* Intuos4 Marker Pen */
                case 0x40802: /* Intuos4 Classic Pen */
-               case 0x18803: /* DTH2242 Grip Pen */
+               case 0x18802: /* DTH2242 Grip Pen */
                case 0x022:
                        wacom->tool[idx] = BTN_TOOL_PEN;
                        break;
@@ -1912,7 +1912,7 @@ static const struct wacom_features wacom_features_0xBB =
        { "Wacom Intuos4 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 2047,
          63, INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xBC =
-       { "Wacom Intuos4 WL",     WACOM_PKGLEN_INTUOS,    40840, 25400, 2047,
+       { "Wacom Intuos4 WL",     WACOM_PKGLEN_INTUOS,    40640, 25400, 2047,
          63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0x26 =
        { "Wacom Intuos5 touch S", WACOM_PKGLEN_INTUOS,  31496, 19685, 2047,
@@ -2144,7 +2144,7 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x44) },
        { USB_DEVICE_WACOM(0x45) },
        { USB_DEVICE_WACOM(0x59) },
-       { USB_DEVICE_WACOM(0x5D) },
+       { USB_DEVICE_DETAILED(0x5D, USB_CLASS_HID, 0, 0) },
        { USB_DEVICE_WACOM(0xB0) },
        { USB_DEVICE_WACOM(0xB1) },
        { USB_DEVICE_WACOM(0xB2) },
@@ -2209,7 +2209,7 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x47) },
        { USB_DEVICE_WACOM(0xF4) },
        { USB_DEVICE_WACOM(0xF8) },
-       { USB_DEVICE_WACOM(0xF6) },
+       { USB_DEVICE_DETAILED(0xF6, USB_CLASS_HID, 0, 0) },
        { USB_DEVICE_WACOM(0xFA) },
        { USB_DEVICE_LENOVO(0x6004) },
        { }
index b287ca3..8301837 100644 (file)
@@ -173,7 +173,7 @@ static inline u16 get_device_id(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
 
-       return calc_devid(pdev->bus->number, pdev->devfn);
+       return PCI_DEVID(pdev->bus->number, pdev->devfn);
 }
 
 static struct iommu_dev_data *get_dev_data(struct device *dev)
@@ -649,26 +649,26 @@ retry:
        case EVENT_TYPE_ILL_DEV:
                printk("ILLEGAL_DEV_TABLE_ENTRY device=%02x:%02x.%x "
                       "address=0x%016llx flags=0x%04x]\n",
-                      PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+                      PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
                       address, flags);
                dump_dte_entry(devid);
                break;
        case EVENT_TYPE_IO_FAULT:
                printk("IO_PAGE_FAULT device=%02x:%02x.%x "
                       "domain=0x%04x address=0x%016llx flags=0x%04x]\n",
-                      PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+                      PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
                       domid, address, flags);
                break;
        case EVENT_TYPE_DEV_TAB_ERR:
                printk("DEV_TAB_HARDWARE_ERROR device=%02x:%02x.%x "
                       "address=0x%016llx flags=0x%04x]\n",
-                      PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+                      PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
                       address, flags);
                break;
        case EVENT_TYPE_PAGE_TAB_ERR:
                printk("PAGE_TAB_HARDWARE_ERROR device=%02x:%02x.%x "
                       "domain=0x%04x address=0x%016llx flags=0x%04x]\n",
-                      PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+                      PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
                       domid, address, flags);
                break;
        case EVENT_TYPE_ILL_CMD:
@@ -682,13 +682,13 @@ retry:
        case EVENT_TYPE_IOTLB_INV_TO:
                printk("IOTLB_INV_TIMEOUT device=%02x:%02x.%x "
                       "address=0x%016llx]\n",
-                      PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+                      PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
                       address);
                break;
        case EVENT_TYPE_INV_DEV_REQ:
                printk("INVALID_DEVICE_REQUEST device=%02x:%02x.%x "
                       "address=0x%016llx flags=0x%04x]\n",
-                      PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+                      PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
                       address, flags);
                break;
        default:
index e3c2d74..2f46881 100644 (file)
@@ -406,7 +406,7 @@ static int __init find_last_devid_on_pci(int bus, int dev, int fn, int cap_ptr)
        u32 cap;
 
        cap = read_pci_config(bus, dev, fn, cap_ptr+MMIO_RANGE_OFFSET);
-       update_last_devid(calc_devid(MMIO_GET_BUS(cap), MMIO_GET_LD(cap)));
+       update_last_devid(PCI_DEVID(MMIO_GET_BUS(cap), MMIO_GET_LD(cap)));
 
        return 0;
 }
@@ -423,7 +423,7 @@ static int __init find_last_devid_from_ivhd(struct ivhd_header *h)
        p += sizeof(*h);
        end += h->length;
 
-       find_last_devid_on_pci(PCI_BUS(h->devid),
+       find_last_devid_on_pci(PCI_BUS_NUM(h->devid),
                        PCI_SLOT(h->devid),
                        PCI_FUNC(h->devid),
                        h->cap_ptr);
@@ -784,10 +784,10 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
 
                        DUMP_printk("  DEV_ALL\t\t\t first devid: %02x:%02x.%x"
                                    " last device %02x:%02x.%x flags: %02x\n",
-                                   PCI_BUS(iommu->first_device),
+                                   PCI_BUS_NUM(iommu->first_device),
                                    PCI_SLOT(iommu->first_device),
                                    PCI_FUNC(iommu->first_device),
-                                   PCI_BUS(iommu->last_device),
+                                   PCI_BUS_NUM(iommu->last_device),
                                    PCI_SLOT(iommu->last_device),
                                    PCI_FUNC(iommu->last_device),
                                    e->flags);
@@ -801,7 +801,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
 
                        DUMP_printk("  DEV_SELECT\t\t\t devid: %02x:%02x.%x "
                                    "flags: %02x\n",
-                                   PCI_BUS(e->devid),
+                                   PCI_BUS_NUM(e->devid),
                                    PCI_SLOT(e->devid),
                                    PCI_FUNC(e->devid),
                                    e->flags);
@@ -813,7 +813,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
 
                        DUMP_printk("  DEV_SELECT_RANGE_START\t "
                                    "devid: %02x:%02x.%x flags: %02x\n",
-                                   PCI_BUS(e->devid),
+                                   PCI_BUS_NUM(e->devid),
                                    PCI_SLOT(e->devid),
                                    PCI_FUNC(e->devid),
                                    e->flags);
@@ -827,11 +827,11 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
 
                        DUMP_printk("  DEV_ALIAS\t\t\t devid: %02x:%02x.%x "
                                    "flags: %02x devid_to: %02x:%02x.%x\n",
-                                   PCI_BUS(e->devid),
+                                   PCI_BUS_NUM(e->devid),
                                    PCI_SLOT(e->devid),
                                    PCI_FUNC(e->devid),
                                    e->flags,
-                                   PCI_BUS(e->ext >> 8),
+                                   PCI_BUS_NUM(e->ext >> 8),
                                    PCI_SLOT(e->ext >> 8),
                                    PCI_FUNC(e->ext >> 8));
 
@@ -846,11 +846,11 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
                        DUMP_printk("  DEV_ALIAS_RANGE\t\t "
                                    "devid: %02x:%02x.%x flags: %02x "
                                    "devid_to: %02x:%02x.%x\n",
-                                   PCI_BUS(e->devid),
+                                   PCI_BUS_NUM(e->devid),
                                    PCI_SLOT(e->devid),
                                    PCI_FUNC(e->devid),
                                    e->flags,
-                                   PCI_BUS(e->ext >> 8),
+                                   PCI_BUS_NUM(e->ext >> 8),
                                    PCI_SLOT(e->ext >> 8),
                                    PCI_FUNC(e->ext >> 8));
 
@@ -864,7 +864,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
 
                        DUMP_printk("  DEV_EXT_SELECT\t\t devid: %02x:%02x.%x "
                                    "flags: %02x ext: %08x\n",
-                                   PCI_BUS(e->devid),
+                                   PCI_BUS_NUM(e->devid),
                                    PCI_SLOT(e->devid),
                                    PCI_FUNC(e->devid),
                                    e->flags, e->ext);
@@ -877,7 +877,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
 
                        DUMP_printk("  DEV_EXT_SELECT_RANGE\t devid: "
                                    "%02x:%02x.%x flags: %02x ext: %08x\n",
-                                   PCI_BUS(e->devid),
+                                   PCI_BUS_NUM(e->devid),
                                    PCI_SLOT(e->devid),
                                    PCI_FUNC(e->devid),
                                    e->flags, e->ext);
@@ -890,7 +890,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
                case IVHD_DEV_RANGE_END:
 
                        DUMP_printk("  DEV_RANGE_END\t\t devid: %02x:%02x.%x\n",
-                                   PCI_BUS(e->devid),
+                                   PCI_BUS_NUM(e->devid),
                                    PCI_SLOT(e->devid),
                                    PCI_FUNC(e->devid));
 
@@ -924,7 +924,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
 
                        DUMP_printk("  DEV_SPECIAL(%s[%d])\t\tdevid: %02x:%02x.%x\n",
                                    var, (int)handle,
-                                   PCI_BUS(devid),
+                                   PCI_BUS_NUM(devid),
                                    PCI_SLOT(devid),
                                    PCI_FUNC(devid));
 
@@ -1086,7 +1086,7 @@ static int __init init_iommu_all(struct acpi_table_header *table)
 
                        DUMP_printk("device: %02x:%02x.%01x cap: %04x "
                                    "seg: %d flags: %01x info %04x\n",
-                                   PCI_BUS(h->devid), PCI_SLOT(h->devid),
+                                   PCI_BUS_NUM(h->devid), PCI_SLOT(h->devid),
                                    PCI_FUNC(h->devid), h->cap_ptr,
                                    h->pci_seg, h->flags, h->info);
                        DUMP_printk("       mmio-addr: %016llx\n",
@@ -1116,7 +1116,7 @@ static int iommu_init_pci(struct amd_iommu *iommu)
        int cap_ptr = iommu->cap_ptr;
        u32 range, misc, low, high;
 
-       iommu->dev = pci_get_bus_and_slot(PCI_BUS(iommu->devid),
+       iommu->dev = pci_get_bus_and_slot(PCI_BUS_NUM(iommu->devid),
                                          iommu->devid & 0xff);
        if (!iommu->dev)
                return -ENODEV;
@@ -1128,9 +1128,9 @@ static int iommu_init_pci(struct amd_iommu *iommu)
        pci_read_config_dword(iommu->dev, cap_ptr + MMIO_MISC_OFFSET,
                              &misc);
 
-       iommu->first_device = calc_devid(MMIO_GET_BUS(range),
+       iommu->first_device = PCI_DEVID(MMIO_GET_BUS(range),
                                         MMIO_GET_FD(range));
-       iommu->last_device = calc_devid(MMIO_GET_BUS(range),
+       iommu->last_device = PCI_DEVID(MMIO_GET_BUS(range),
                                        MMIO_GET_LD(range));
 
        if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB)))
@@ -1388,8 +1388,8 @@ static int __init init_unity_map_range(struct ivmd_header *m)
 
        DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x"
                    " range_start: %016llx range_end: %016llx flags: %x\n", s,
-                   PCI_BUS(e->devid_start), PCI_SLOT(e->devid_start),
-                   PCI_FUNC(e->devid_start), PCI_BUS(e->devid_end),
+                   PCI_BUS_NUM(e->devid_start), PCI_SLOT(e->devid_start),
+                   PCI_FUNC(e->devid_start), PCI_BUS_NUM(e->devid_end),
                    PCI_SLOT(e->devid_end), PCI_FUNC(e->devid_end),
                    e->address_start, e->address_end, m->flags);
 
index e38ab43..ec36cf6 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
+#include <linux/pci.h>
 
 /*
  * Maximum number of IOMMUs supported
 
 #define MAX_DOMAIN_ID 65536
 
-/* FIXME: move this macro to <linux/pci.h> */
-#define PCI_BUS(x) (((x) >> 8) & 0xff)
-
 /* Protection domain flags */
 #define PD_DMA_OPS_MASK                (1UL << 0) /* domain used for dma_ops */
 #define PD_DEFAULT_MASK                (1UL << 1) /* domain is a default dma_ops
@@ -703,13 +701,6 @@ extern int amd_iommu_max_glx_val;
  */
 extern void iommu_flush_all_caches(struct amd_iommu *iommu);
 
-/* takes bus and device/function and returns the device id
- * FIXME: should that be in generic PCI code? */
-static inline u16 calc_devid(u8 bus, u8 devfn)
-{
-       return (((u16)bus) << 8) | devfn;
-}
-
 static inline int get_ioapic_devid(int id)
 {
        struct devid_map *entry;
index 0246b1f..c276fde 100644 (file)
@@ -480,6 +480,7 @@ static void tpci200_release_device(struct ipack_device *dev)
 
 static int tpci200_create_device(struct tpci200_board *tpci200, int i)
 {
+       int ret;
        enum ipack_space space;
        struct ipack_device *dev =
                kzalloc(sizeof(struct ipack_device), GFP_KERNEL);
@@ -495,7 +496,18 @@ static int tpci200_create_device(struct tpci200_board *tpci200, int i)
                        + tpci200_space_interval[space] * i;
                dev->region[space].size = tpci200_space_size[space];
        }
-       return ipack_device_register(dev);
+
+       ret = ipack_device_init(dev);
+       if (ret < 0) {
+               ipack_put_device(dev);
+               return ret;
+       }
+
+       ret = ipack_device_add(dev);
+       if (ret < 0)
+               ipack_put_device(dev);
+
+       return ret;
 }
 
 static int tpci200_pci_probe(struct pci_dev *pdev,
index 7ec6b20..6e066c5 100644 (file)
@@ -227,7 +227,7 @@ static int ipack_unregister_bus_member(struct device *dev, void *data)
        struct ipack_bus_device *bus = data;
 
        if (idev->bus == bus)
-               ipack_device_unregister(idev);
+               ipack_device_del(idev);
 
        return 1;
 }
@@ -419,7 +419,7 @@ out:
        return ret;
 }
 
-int ipack_device_register(struct ipack_device *dev)
+int ipack_device_init(struct ipack_device *dev)
 {
        int ret;
 
@@ -428,6 +428,7 @@ int ipack_device_register(struct ipack_device *dev)
        dev->dev.parent = dev->bus->parent;
        dev_set_name(&dev->dev,
                     "ipack-dev.%u.%u", dev->bus->bus_nr, dev->slot);
+       device_initialize(&dev->dev);
 
        if (dev->bus->ops->set_clockrate(dev, 8))
                dev_warn(&dev->dev, "failed to switch to 8 MHz operation for reading of device ID.\n");
@@ -447,19 +448,34 @@ int ipack_device_register(struct ipack_device *dev)
                        dev_err(&dev->dev, "failed to switch to 32 MHz operation.\n");
        }
 
-       ret = device_register(&dev->dev);
-       if (ret < 0)
-               kfree(dev->id);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipack_device_init);
 
-       return ret;
+int ipack_device_add(struct ipack_device *dev)
+{
+       return device_add(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(ipack_device_add);
+
+void ipack_device_del(struct ipack_device *dev)
+{
+       device_del(&dev->dev);
+       ipack_put_device(dev);
+}
+EXPORT_SYMBOL_GPL(ipack_device_del);
+
+void ipack_get_device(struct ipack_device *dev)
+{
+       get_device(&dev->dev);
 }
-EXPORT_SYMBOL_GPL(ipack_device_register);
+EXPORT_SYMBOL_GPL(ipack_get_device);
 
-void ipack_device_unregister(struct ipack_device *dev)
+void ipack_put_device(struct ipack_device *dev)
 {
-       device_unregister(&dev->dev);
+       put_device(&dev->dev);
 }
-EXPORT_SYMBOL_GPL(ipack_device_unregister);
+EXPORT_SYMBOL_GPL(ipack_put_device);
 
 static int __init ipack_init(void)
 {
index a32e0d5..fc6aebf 100644 (file)
@@ -236,7 +236,8 @@ static int gic_retrigger(struct irq_data *d)
        if (gic_arch_extn.irq_retrigger)
                return gic_arch_extn.irq_retrigger(d);
 
-       return -ENXIO;
+       /* the genirq layer expects 0 if we can't retrigger in hardware */
+       return 0;
 }
 
 #ifdef CONFIG_SMP
index c21353d..62b8030 100644 (file)
@@ -163,16 +163,4 @@ static struct pcmcia_driver avmcs_driver = {
        .remove = avmcs_detach,
        .id_table = avmcs_ids,
 };
-
-static int __init avmcs_init(void)
-{
-       return pcmcia_register_driver(&avmcs_driver);
-}
-
-static void __exit avmcs_exit(void)
-{
-       pcmcia_unregister_driver(&avmcs_driver);
-}
-
-module_init(avmcs_init);
-module_exit(avmcs_exit);
+module_pcmcia_driver(avmcs_driver);
index 4e676bc..baad94e 100644 (file)
@@ -159,16 +159,4 @@ static struct pcmcia_driver avma1cs_driver = {
        .remove         = avma1cs_detach,
        .id_table       = avma1cs_ids,
 };
-
-static int __init init_avma1_cs(void)
-{
-       return pcmcia_register_driver(&avma1cs_driver);
-}
-
-static void __exit exit_avma1_cs(void)
-{
-       pcmcia_unregister_driver(&avma1cs_driver);
-}
-
-module_init(init_avma1_cs);
-module_exit(exit_avma1_cs);
+module_pcmcia_driver(avma1cs_driver);
index ebe5691..40f6fad 100644 (file)
@@ -215,16 +215,4 @@ static struct pcmcia_driver elsa_cs_driver = {
        .suspend        = elsa_suspend,
        .resume         = elsa_resume,
 };
-
-static int __init init_elsa_cs(void)
-{
-       return pcmcia_register_driver(&elsa_cs_driver);
-}
-
-static void __exit exit_elsa_cs(void)
-{
-       pcmcia_unregister_driver(&elsa_cs_driver);
-}
-
-module_init(init_elsa_cs);
-module_exit(exit_elsa_cs);
+module_pcmcia_driver(elsa_cs_driver);
index 90f8129..92ef62d 100644 (file)
@@ -206,16 +206,4 @@ static struct pcmcia_driver sedlbauer_driver = {
        .suspend        = sedlbauer_suspend,
        .resume         = sedlbauer_resume,
 };
-
-static int __init init_sedlbauer_cs(void)
-{
-       return pcmcia_register_driver(&sedlbauer_driver);
-}
-
-static void __exit exit_sedlbauer_cs(void)
-{
-       pcmcia_unregister_driver(&sedlbauer_driver);
-}
-
-module_init(init_sedlbauer_cs);
-module_exit(exit_sedlbauer_cs);
+module_pcmcia_driver(sedlbauer_driver);
index f2476ff..b8dd149 100644 (file)
@@ -197,16 +197,4 @@ static struct pcmcia_driver teles_cs_driver = {
        .suspend        = teles_suspend,
        .resume         = teles_resume,
 };
-
-static int __init init_teles_cs(void)
-{
-       return pcmcia_register_driver(&teles_cs_driver);
-}
-
-static void __exit exit_teles_cs(void)
-{
-       pcmcia_unregister_driver(&teles_cs_driver);
-}
-
-module_init(init_teles_cs);
-module_exit(exit_teles_cs);
+module_pcmcia_driver(teles_cs_driver);
index 7e46926..9a0bdad 100644 (file)
@@ -611,6 +611,7 @@ static void dec_pending(struct dm_io *io, int error)
                        queue_io(md, bio);
                } else {
                        /* done with normal IO or empty flush */
+                       trace_block_bio_complete(md->queue, bio, io_error);
                        bio_endio(bio, io_error);
                }
        }
index 24909eb..f4e87bf 100644 (file)
@@ -184,6 +184,8 @@ static void return_io(struct bio *return_bi)
                return_bi = bi->bi_next;
                bi->bi_next = NULL;
                bi->bi_size = 0;
+               trace_block_bio_complete(bdev_get_queue(bi->bi_bdev),
+                                        bi, 0);
                bio_endio(bi, 0);
                bi = return_bi;
        }
@@ -3914,6 +3916,8 @@ static void raid5_align_endio(struct bio *bi, int error)
        rdev_dec_pending(rdev, conf->mddev);
 
        if (!error && uptodate) {
+               trace_block_bio_complete(bdev_get_queue(raid_bi->bi_bdev),
+                                        raid_bi, 0);
                bio_endio(raid_bi, 0);
                if (atomic_dec_and_test(&conf->active_aligned_reads))
                        wake_up(&conf->wait_for_stripe);
@@ -4382,6 +4386,8 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                if ( rw == WRITE )
                        md_write_end(mddev);
 
+               trace_block_bio_complete(bdev_get_queue(bi->bi_bdev),
+                                        bi, 0);
                bio_endio(bi, 0);
        }
 }
@@ -4758,8 +4764,11 @@ static int  retry_aligned_read(struct r5conf *conf, struct bio *raid_bio)
                handled++;
        }
        remaining = raid5_dec_bi_active_stripes(raid_bio);
-       if (remaining == 0)
+       if (remaining == 0) {
+               trace_block_bio_complete(bdev_get_queue(raid_bio->bi_bdev),
+                                        raid_bio, 0);
                bio_endio(raid_bio, 0);
+       }
        if (atomic_dec_and_test(&conf->active_aligned_reads))
                wake_up(&conf->wait_for_stripe);
        return handled;
index f19cd73..4faaf80 100644 (file)
@@ -610,7 +610,7 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer,
               __func__, 'A' + layer, segment * isdbt_rate[m][f][i]/1000,
                rate, rate);
 
-       state->estimated_rate[i] = rate;
+       state->estimated_rate[layer] = rate;
 }
 
 
index d4de021..31ce769 100644 (file)
@@ -461,7 +461,7 @@ int cx25821_video_register(struct cx25821_dev *dev)
 
        spin_lock_init(&dev->slock);
 
-       for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) {
+       for (i = 0; i < VID_CHANNEL_NUM; ++i) {
                cx25821_init_controls(dev, i);
 
                cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper,
index df08736..cadf1cc 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
+#include <linux/pm.h>
 #include <memory/jedec_ddr.h>
 #include "emif.h"
 #include "of_memory.h"
@@ -256,6 +257,41 @@ static void set_lpmode(struct emif_data *emif, u8 lpmode)
        u32 temp;
        void __iomem *base = emif->base;
 
+       /*
+        * Workaround for errata i743 - LPDDR2 Power-Down State is Not
+        * Efficient
+        *
+        * i743 DESCRIPTION:
+        * The EMIF supports power-down state for low power. The EMIF
+        * automatically puts the SDRAM into power-down after the memory is
+        * not accessed for a defined number of cycles and the
+        * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field is set to 0x4.
+        * As the EMIF supports automatic output impedance calibration, a ZQ
+        * calibration long command is issued every time it exits active
+        * power-down and precharge power-down modes. The EMIF waits and
+        * blocks any other command during this calibration.
+        * The EMIF does not allow selective disabling of ZQ calibration upon
+        * exit of power-down mode. Due to very short periods of power-down
+        * cycles, ZQ calibration overhead creates bandwidth issues and
+        * increases overall system power consumption. On the other hand,
+        * issuing ZQ calibration long commands when exiting self-refresh is
+        * still required.
+        *
+        * WORKAROUND
+        * Because there is no power consumption benefit of the power-down due
+        * to the calibration and there is a performance risk, the guideline
+        * is to not allow power-down state and, therefore, to not have set
+        * the EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field to 0x4.
+        */
+       if ((emif->plat_data->ip_rev == EMIF_4D) &&
+           (EMIF_LP_MODE_PWR_DN == lpmode)) {
+               WARN_ONCE(1,
+                         "REG_LP_MODE = LP_MODE_PWR_DN(4) is prohibited by"
+                         "erratum i743 switch to LP_MODE_SELF_REFRESH(2)\n");
+               /* rollback LP_MODE to Self-refresh mode */
+               lpmode = EMIF_LP_MODE_SELF_REFRESH;
+       }
+
        temp = readl(base + EMIF_POWER_MANAGEMENT_CONTROL);
        temp &= ~LP_MODE_MASK;
        temp |= (lpmode << LP_MODE_SHIFT);
@@ -715,6 +751,8 @@ static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev)
        u32 timeout_perf        = EMIF_LP_MODE_TIMEOUT_PERFORMANCE;
        u32 timeout_pwr         = EMIF_LP_MODE_TIMEOUT_POWER;
        u32 freq_threshold      = EMIF_LP_MODE_FREQ_THRESHOLD;
+       u32 mask;
+       u8 shift;
 
        struct emif_custom_configs *cust_cfgs = emif->plat_data->custom_configs;
 
@@ -728,37 +766,59 @@ static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev)
        /* Timeout based on DDR frequency */
        timeout = freq >= freq_threshold ? timeout_perf : timeout_pwr;
 
-       /* The value to be set in register is "log2(timeout) - 3" */
+       /*
+        * The value to be set in register is "log2(timeout) - 3"
+        * if timeout < 16 load 0 in register
+        * if timeout is not a power of 2, round to next highest power of 2
+        */
        if (timeout < 16) {
                timeout = 0;
        } else {
-               timeout = __fls(timeout) - 3;
                if (timeout & (timeout - 1))
-                       timeout++;
+                       timeout <<= 1;
+               timeout = __fls(timeout) - 3;
        }
 
        switch (lpmode) {
        case EMIF_LP_MODE_CLOCK_STOP:
-               pwr_mgmt_ctrl = (timeout << CS_TIM_SHIFT) |
-                                       SR_TIM_MASK | PD_TIM_MASK;
+               shift = CS_TIM_SHIFT;
+               mask = CS_TIM_MASK;
                break;
        case EMIF_LP_MODE_SELF_REFRESH:
                /* Workaround for errata i735 */
                if (timeout < 6)
                        timeout = 6;
 
-               pwr_mgmt_ctrl = (timeout << SR_TIM_SHIFT) |
-                                       CS_TIM_MASK | PD_TIM_MASK;
+               shift = SR_TIM_SHIFT;
+               mask = SR_TIM_MASK;
                break;
        case EMIF_LP_MODE_PWR_DN:
-               pwr_mgmt_ctrl = (timeout << PD_TIM_SHIFT) |
-                                       CS_TIM_MASK | SR_TIM_MASK;
+               shift = PD_TIM_SHIFT;
+               mask = PD_TIM_MASK;
                break;
        case EMIF_LP_MODE_DISABLE:
        default:
-               pwr_mgmt_ctrl = CS_TIM_MASK |
-                                       PD_TIM_MASK | SR_TIM_MASK;
+               mask = 0;
+               shift = 0;
+               break;
        }
+       /* Round to maximum in case of overflow, BUT warn! */
+       if (lpmode != EMIF_LP_MODE_DISABLE && timeout > mask >> shift) {
+               pr_err("TIMEOUT Overflow - lpmode=%d perf=%d pwr=%d freq=%d\n",
+                      lpmode,
+                      timeout_perf,
+                      timeout_pwr,
+                      freq_threshold);
+               WARN(1, "timeout=0x%02x greater than 0x%02x. Using max\n",
+                    timeout, mask >> shift);
+               timeout = mask >> shift;
+       }
+
+       /* Setup required timing */
+       pwr_mgmt_ctrl = (timeout << shift) & mask;
+       /* setup a default mask for rest of the modes */
+       pwr_mgmt_ctrl |= (SR_TIM_MASK | CS_TIM_MASK | PD_TIM_MASK) &
+                         ~mask;
 
        /* No CS_TIM in EMIF_4D5 */
        if (ip_rev == EMIF_4D5)
@@ -815,6 +875,8 @@ static void setup_registers(struct emif_data *emif, struct emif_regs *regs)
 
        writel(regs->sdram_tim2_shdw, base + EMIF_SDRAM_TIMING_2_SHDW);
        writel(regs->phy_ctrl_1_shdw, base + EMIF_DDR_PHY_CTRL_1_SHDW);
+       writel(regs->pwr_mgmt_ctrl_shdw,
+              base + EMIF_POWER_MANAGEMENT_CTRL_SHDW);
 
        /* Settings specific for EMIF4D5 */
        if (emif->plat_data->ip_rev != EMIF_4D5)
@@ -892,6 +954,7 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
 {
        u32             old_temp_level;
        irqreturn_t     ret = IRQ_HANDLED;
+       struct emif_custom_configs *custom_configs;
 
        spin_lock_irqsave(&emif_lock, irq_state);
        old_temp_level = emif->temperature_level;
@@ -904,6 +967,29 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
                goto out;
        }
 
+       custom_configs = emif->plat_data->custom_configs;
+
+       /*
+        * IF we detect higher than "nominal rating" from DDR sensor
+        * on an unsupported DDR part, shutdown system
+        */
+       if (custom_configs && !(custom_configs->mask &
+                               EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART)) {
+               if (emif->temperature_level >= SDRAM_TEMP_HIGH_DERATE_REFRESH) {
+                       dev_err(emif->dev,
+                               "%s:NOT Extended temperature capable memory."
+                               "Converting MR4=0x%02x as shutdown event\n",
+                               __func__, emif->temperature_level);
+                       /*
+                        * Temperature far too high - do kernel_power_off()
+                        * from thread context
+                        */
+                       emif->temperature_level = SDRAM_TEMP_VERY_HIGH_SHUTDOWN;
+                       ret = IRQ_WAKE_THREAD;
+                       goto out;
+               }
+       }
+
        if (emif->temperature_level < old_temp_level ||
                emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
                /*
@@ -965,7 +1051,14 @@ static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
 
        if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
                dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n");
-               kernel_power_off();
+
+               /* If we have Power OFF ability, use it, else try restarting */
+               if (pm_power_off) {
+                       kernel_power_off();
+               } else {
+                       WARN(1, "FIXME: NO pm_power_off!!! trying restart\n");
+                       kernel_restart("SDRAM Over-temp Emergency restart");
+               }
                return IRQ_HANDLED;
        }
 
@@ -1170,7 +1263,7 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
 {
        struct emif_custom_configs      *cust_cfgs = NULL;
        int                             len;
-       const int                       *lpmode, *poll_intvl;
+       const __be32                    *lpmode, *poll_intvl;
 
        lpmode = of_get_property(np_emif, "low-power-mode", &len);
        poll_intvl = of_get_property(np_emif, "temp-alert-poll-interval", &len);
@@ -1184,7 +1277,7 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
 
        if (lpmode) {
                cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_LPMODE;
-               cust_cfgs->lpmode = *lpmode;
+               cust_cfgs->lpmode = be32_to_cpup(lpmode);
                of_property_read_u32(np_emif,
                                "low-power-mode-timeout-performance",
                                &cust_cfgs->lpmode_timeout_performance);
@@ -1199,9 +1292,13 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
        if (poll_intvl) {
                cust_cfgs->mask |=
                                EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL;
-               cust_cfgs->temp_alert_poll_interval_ms = *poll_intvl;
+               cust_cfgs->temp_alert_poll_interval_ms =
+                                               be32_to_cpup(poll_intvl);
        }
 
+       if (of_find_property(np_emif, "extended-temp-part", &len))
+               cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART;
+
        if (!is_custom_config_valid(cust_cfgs, emif->dev)) {
                devm_kfree(emif->dev, cust_cfgs);
                return;
@@ -1407,7 +1504,7 @@ static struct emif_data *__init_or_module get_device_details(
        if (pd->timings) {
                temp = devm_kzalloc(dev, size, GFP_KERNEL);
                if (temp) {
-                       memcpy(temp, pd->timings, sizeof(*pd->timings));
+                       memcpy(temp, pd->timings, size);
                        pd->timings = temp;
                } else {
                        dev_warn(dev, "%s:%d: allocation error\n", __func__,
@@ -1841,18 +1938,8 @@ static struct platform_driver emif_driver = {
        },
 };
 
-static int __init_or_module emif_register(void)
-{
-       return platform_driver_probe(&emif_driver, emif_probe);
-}
-
-static void __exit emif_unregister(void)
-{
-       platform_driver_unregister(&emif_driver);
-}
+module_platform_driver_probe(emif_driver, emif_probe);
 
-module_init(emif_register);
-module_exit(emif_unregister);
 MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:emif");
index 0b97598..f4ae074 100644 (file)
@@ -268,6 +268,7 @@ static const u32 tegra30_mc_ctx[] = {
        MC_INTMASK,
 };
 
+#ifdef CONFIG_PM
 static int tegra30_mc_suspend(struct device *dev)
 {
        int i;
@@ -291,6 +292,7 @@ static int tegra30_mc_resume(struct device *dev)
        mc_readl(mc, MC_TIMING_CONTROL);
        return 0;
 }
+#endif
 
 static UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm,
                            tegra30_mc_suspend,
index c346941..ca86581 100644 (file)
@@ -991,7 +991,7 @@ config MFD_PM8XXX
 
 config MFD_PM8921_CORE
        tristate "Qualcomm PM8921 PMIC chip"
-       depends on MSM_SSBI
+       depends on SSBI && BROKEN
        select MFD_CORE
        select MFD_PM8XXX
        help
index d4b297c..ecc137f 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/err.h>
-#include <linux/msm_ssbi.h>
+#include <linux/ssbi.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/mfd/pm8xxx/core.h>
@@ -35,7 +35,7 @@ static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
 
-       return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
+       return ssbi_read(pmic->dev->parent, addr, val, 1);
 }
 
 static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
@@ -43,7 +43,7 @@ static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
 
-       return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
+       return ssbi_write(pmic->dev->parent, addr, &val, 1);
 }
 
 static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
@@ -52,7 +52,7 @@ static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
 
-       return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
+       return ssbi_read(pmic->dev->parent, addr, buf, cnt);
 }
 
 static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
@@ -61,7 +61,7 @@ static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
        const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
 
-       return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
+       return ssbi_write(pmic->dev->parent, addr, buf, cnt);
 }
 
 static int pm8921_read_irq_stat(const struct device *dev, int irq)
@@ -124,7 +124,7 @@ static int pm8921_probe(struct platform_device *pdev)
        }
 
        /* Read PMIC chip revision */
-       rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
+       rc = ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
        if (rc) {
                pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
                goto err_read_rev;
@@ -133,7 +133,7 @@ static int pm8921_probe(struct platform_device *pdev)
        rev = val;
 
        /* Read PMIC chip revision 2 */
-       rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
+       rc = ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
        if (rc) {
                pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
                        REG_HWREV_2, rc);
index a433f58..ca2aed6 100644 (file)
@@ -331,6 +331,10 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x000002A3, 0x1102 },   /* R675   - Mic Detect 1 */ 
        { 0x000002A4, 0x009F },   /* R676   - Mic Detect 2 */ 
        { 0x000002A5, 0x0000 },   /* R677   - Mic Detect 3 */ 
+       { 0x000002A6, 0x3737 },   /* R678   - Mic Detect Level 1 */
+       { 0x000002A7, 0x372C },   /* 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 */ 
@@ -1090,6 +1094,10 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_MIC_DETECT_1:
        case ARIZONA_MIC_DETECT_2:
        case ARIZONA_MIC_DETECT_3:
+       case ARIZONA_MIC_DETECT_LEVEL_1:
+       case ARIZONA_MIC_DETECT_LEVEL_2:
+       case ARIZONA_MIC_DETECT_LEVEL_3:
+       case ARIZONA_MIC_DETECT_LEVEL_4:
        case ARIZONA_MIC_NOISE_MIX_CONTROL_1:
        case ARIZONA_ISOLATION_CONTROL:
        case ARIZONA_JACK_DETECT_ANALOGUE:
index e83fdfe..e29e798 100644 (file)
@@ -93,6 +93,14 @@ config ATMEL_TCB_CLKSRC_BLOCK
          TC can be used for other purposes, such as PWM generation and
          interval timing.
 
+config DUMMY_IRQ
+       tristate "Dummy IRQ handler"
+       default n
+       ---help---
+         This module accepts a single 'irq' parameter, which it should register for.
+         The sole purpose of this module is to help with debugging of systems on
+         which spurious IRQs would happen on disabled IRQ vector.
+
 config IBM_ASM
        tristate "Device driver for IBM RSA service processor"
        depends on X86 && PCI && INPUT
@@ -398,7 +406,7 @@ config DS1682
 
 config SPEAR13XX_PCIE_GADGET
        bool "PCIe gadget support for SPEAr13XX platform"
-       depends on ARCH_SPEAR13XX
+       depends on ARCH_SPEAR13XX && BROKEN
        default n
        help
         This option enables gadget support for PCIe controller. If
index 35a1463..865cbc6 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_ATMEL_TCLIB)     += atmel_tclib.o
 obj-$(CONFIG_BMP085)           += bmp085.o
 obj-$(CONFIG_BMP085_I2C)       += bmp085-i2c.o
 obj-$(CONFIG_BMP085_SPI)       += bmp085-spi.o
+obj-$(CONFIG_DUMMY_IRQ)                += dummy-irq.o
 obj-$(CONFIG_ICS932S401)       += ics932s401.o
 obj-$(CONFIG_LKDTM)            += lkdtm.o
 obj-$(CONFIG_TIFM_CORE)        += tifm_core.o
@@ -49,6 +50,5 @@ obj-y                         += carma/
 obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
 obj-$(CONFIG_ALTERA_STAPL)     +=altera-stapl/
 obj-$(CONFIG_INTEL_MEI)                += mei/
-obj-$(CONFIG_MAX8997_MUIC)     += max8997-muic.o
 obj-$(CONFIG_VMWARE_VMCI)      += vmw_vmci/
 obj-$(CONFIG_LATTICE_ECP3_CONFIG)      += lattice-ecp3-config.o
index d648b08..5b5fd84 100644 (file)
@@ -272,19 +272,8 @@ static int apds9802als_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int apds9802als_suspend(struct i2c_client *client, pm_message_t mesg)
-{
-       als_set_power_state(client, false);
-       return 0;
-}
-
-static int apds9802als_resume(struct i2c_client *client)
-{
-       als_set_default_config(client);
-       return 0;
-}
 
-static int apds9802als_runtime_suspend(struct device *dev)
+static int apds9802als_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
 
@@ -292,7 +281,7 @@ static int apds9802als_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int apds9802als_runtime_resume(struct device *dev)
+static int apds9802als_resume(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
 
@@ -300,16 +289,12 @@ static int apds9802als_runtime_resume(struct device *dev)
        return 0;
 }
 
-static const struct dev_pm_ops apds9802als_pm_ops = {
-       .runtime_suspend = apds9802als_runtime_suspend,
-       .runtime_resume = apds9802als_runtime_resume,
-};
+static UNIVERSAL_DEV_PM_OPS(apds9802als_pm_ops, apds9802als_suspend,
+       apds9802als_resume, NULL);
 
 #define APDS9802ALS_PM_OPS (&apds9802als_pm_ops)
 
 #else  /* CONFIG_PM */
-#define apds9802als_suspend NULL
-#define apds9802als_resume NULL
 #define APDS9802ALS_PM_OPS NULL
 #endif /* CONFIG_PM */
 
@@ -327,8 +312,6 @@ static struct i2c_driver apds9802als_driver = {
        },
        .probe = apds9802als_probe,
        .remove = apds9802als_remove,
-       .suspend = apds9802als_suspend,
-       .resume = apds9802als_resume,
        .id_table = apds9802als_id,
 };
 
index 0e67f82..98f9bb2 100644 (file)
@@ -700,9 +700,6 @@ static ssize_t apds990x_lux_calib_store(struct device *dev,
        if (strict_strtoul(buf, 0, &value))
                return -EINVAL;
 
-       if (chip->lux_calib > APDS_RANGE)
-               return -EINVAL;
-
        chip->lux_calib = value;
 
        return len;
@@ -1204,7 +1201,7 @@ static int apds990x_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int apds990x_suspend(struct device *dev)
 {
        struct i2c_client *client = container_of(dev, struct i2c_client, dev);
@@ -1227,10 +1224,6 @@ static int apds990x_resume(struct device *dev)
 
        return 0;
 }
-#else
-#define apds990x_suspend  NULL
-#define apds990x_resume          NULL
-#define apds990x_shutdown NULL
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
index fe8616a..48651ef 100644 (file)
@@ -378,18 +378,7 @@ static struct platform_driver charlcd_driver = {
        .remove = __exit_p(charlcd_remove),
 };
 
-static int __init charlcd_init(void)
-{
-       return platform_driver_probe(&charlcd_driver, charlcd_probe);
-}
-
-static void __exit charlcd_exit(void)
-{
-       platform_driver_unregister(&charlcd_driver);
-}
-
-module_init(charlcd_init);
-module_exit(charlcd_exit);
+module_platform_driver_probe(charlcd_driver, charlcd_probe);
 
 MODULE_AUTHOR("Linus Walleij <triad@df.lth.se>");
 MODULE_DESCRIPTION("ARM Character LCD Driver");
index 28f5aaa..494d050 100644 (file)
@@ -393,17 +393,7 @@ static struct platform_driver atmel_pwm_driver = {
         */
 };
 
-static int __init pwm_init(void)
-{
-       return platform_driver_probe(&atmel_pwm_driver, pwm_probe);
-}
-module_init(pwm_init);
-
-static void __exit pwm_exit(void)
-{
-       platform_driver_unregister(&atmel_pwm_driver);
-}
-module_exit(pwm_exit);
+module_platform_driver_probe(atmel_pwm_driver, pwm_probe);
 
 MODULE_DESCRIPTION("Driver for AT32/AT91 PWM module");
 MODULE_LICENSE("GPL");
index 2ed8fc3..f4975f7 100644 (file)
@@ -1310,7 +1310,7 @@ static int bh1770_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int bh1770_suspend(struct device *dev)
 {
        struct i2c_client *client = container_of(dev, struct i2c_client, dev);
@@ -1346,11 +1346,6 @@ static int bh1770_resume(struct device *dev)
        }
        return ret;
 }
-
-#else
-#define bh1770_suspend NULL
-#define bh1770_shutdown NULL
-#define bh1770_resume  NULL
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
index cf03d0a..818f3a0 100644 (file)
@@ -196,7 +196,7 @@ static int bh1780_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int bh1780_suspend(struct device *dev)
 {
        struct bh1780_data *ddata;
@@ -235,11 +235,9 @@ static int bh1780_resume(struct device *dev)
 
        return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
+
 static SIMPLE_DEV_PM_OPS(bh1780_pm, bh1780_suspend, bh1780_resume);
-#define BH1780_PMOPS (&bh1780_pm)
-#else
-#define BH1780_PMOPS NULL
-#endif /* CONFIG_PM */
 
 static const struct i2c_device_id bh1780_id[] = {
        { "bh1780", 0 },
@@ -252,7 +250,7 @@ static struct i2c_driver bh1780_driver = {
        .id_table       = bh1780_id,
        .driver = {
                .name = "bh1780",
-               .pm     = BH1780_PMOPS,
+               .pm     = &bh1780_pm,
        },
 };
 
index 9858f36..effd8c6 100644 (file)
 
 static int mfgpt_reset_timers;
 module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644);
-MODULE_PARM_DESC(mfgptfix, "Reset the MFGPT timers during init; "
-               "required by some broken BIOSes (ie, TinyBIOS < 0.99).");
+MODULE_PARM_DESC(mfgptfix, "Try to reset the MFGPT timers during init; "
+               "required by some broken BIOSes (ie, TinyBIOS < 0.99) or kexec "
+               "(1 = reset the MFGPT using an undocumented bit, "
+               "2 = perform a soft reset by unconfiguring all timers); "
+               "use what works best for you.");
 
 struct cs5535_mfgpt_timer {
        struct cs5535_mfgpt_chip *chip;
@@ -256,6 +259,28 @@ static void reset_all_timers(void)
 }
 
 /*
+ * This is another sledgehammer to reset all MFGPT timers.
+ * Instead of using the undocumented bit method it clears
+ * IRQ, NMI and RESET settings.
+ */
+static void soft_reset(void)
+{
+       int i;
+       struct cs5535_mfgpt_timer t;
+
+       for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
+               t.nr = i;
+
+               cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_RESET, 0);
+               cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_RESET, 0);
+               cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_NMI, 0);
+               cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_NMI, 0);
+               cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_IRQ, 0);
+               cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_IRQ, 0);
+       }
+}
+
+/*
  * Check whether any MFGPTs are available for the kernel to use.  In most
  * cases, firmware that uses AMD's VSA code will claim all timers during
  * bootup; we certainly don't want to take them if they're already in use.
@@ -271,15 +296,17 @@ static int scan_timers(struct cs5535_mfgpt_chip *mfgpt)
        int i;
 
        /* bios workaround */
-       if (mfgpt_reset_timers)
+       if (mfgpt_reset_timers == 1)
                reset_all_timers();
+       else if (mfgpt_reset_timers == 2)
+               soft_reset();
 
        /* just to be safe, protect this section w/ lock */
        spin_lock_irqsave(&mfgpt->lock, flags);
        for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
                timer.nr = i;
                val = cs5535_mfgpt_read(&timer, MFGPT_REG_SETUP);
-               if (!(val & MFGPT_SETUP_SETUP)) {
+               if (!(val & MFGPT_SETUP_SETUP) || mfgpt_reset_timers == 2) {
                        __set_bit(i, mfgpt->avail);
                        timers++;
                }
@@ -294,6 +321,12 @@ static int cs5535_mfgpt_probe(struct platform_device *pdev)
        struct resource *res;
        int err = -EIO, t;
 
+       if (mfgpt_reset_timers < 0 || mfgpt_reset_timers > 2) {
+               dev_err(&pdev->dev, "Bad mfgpt_reset_timers value: %i\n",
+                       mfgpt_reset_timers);
+               goto done;
+       }
+
        /* There are two ways to get the MFGPT base address; one is by
         * fetching it from MSR_LBAR_MFGPT, the other is by reading the
         * PCI BAR info.  The latter method is easier (especially across
diff --git a/drivers/misc/dummy-irq.c b/drivers/misc/dummy-irq.c
new file mode 100644 (file)
index 0000000..7014167
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Dummy IRQ handler driver.
+ *
+ * This module only registers itself as a handler that is specified to it
+ * by the 'irq' parameter.
+ *
+ * The sole purpose of this module is to help with debugging of systems on
+ * which spurious IRQs would happen on disabled IRQ vector.
+ *
+ * Copyright (C) 2013 Jiri Kosina
+ */
+
+/*
+ * 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/module.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+static int irq;
+
+static irqreturn_t dummy_interrupt(int irq, void *dev_id)
+{
+       static int count = 0;
+
+       if (count == 0) {
+               printk(KERN_INFO "dummy-irq: interrupt occured on IRQ %d\n",
+                               irq);
+               count++;
+       }
+
+       return IRQ_NONE;
+}
+
+static int __init dummy_irq_init(void)
+{
+       if (request_irq(irq, &dummy_interrupt, IRQF_SHARED, "dummy_irq", &irq)) {
+               printk(KERN_ERR "dummy-irq: cannot register IRQ %d\n", irq);
+               return -EIO;
+       }
+       printk(KERN_INFO "dummy-irq: registered for IRQ %d\n", irq);
+       return 0;
+}
+
+static void __exit dummy_irq_exit(void)
+{
+       printk(KERN_INFO "dummy-irq unloaded\n");
+       free_irq(irq, &irq);
+}
+
+module_init(dummy_irq_init);
+module_exit(dummy_irq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jiri Kosina");
+module_param(irq, uint, 0444);
+MODULE_PARM_DESC(irq, "The IRQ to register for");
index b08cf8a..ad8fd8e 100644 (file)
@@ -412,7 +412,7 @@ static int at25_probe(struct spi_device *spi)
        mutex_init(&at25->lock);
        at25->chip = chip;
        at25->spi = spi_dev_get(spi);
-       dev_set_drvdata(&spi->dev, at25);
+       spi_set_drvdata(spi, at25);
        at25->addrlen = addrlen;
 
        /* Export the EEPROM bytes through sysfs, since that's convenient.
@@ -463,7 +463,7 @@ static int at25_remove(struct spi_device *spi)
 {
        struct at25_data        *at25;
 
-       at25 = dev_get_drvdata(&spi->dev);
+       at25 = spi_get_drvdata(spi);
        sysfs_remove_bin_file(&spi->dev.kobj, &at25->bin);
        kfree(at25);
        return 0;
index a6b5d5e..94cfc12 100644 (file)
@@ -363,7 +363,7 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
                        dev_err(&spi->dev, "can't create erase interface\n");
        }
 
-       dev_set_drvdata(&spi->dev, edev);
+       spi_set_drvdata(spi, edev);
        return 0;
 fail:
        kfree(edev);
@@ -372,13 +372,13 @@ fail:
 
 static int eeprom_93xx46_remove(struct spi_device *spi)
 {
-       struct eeprom_93xx46_dev *edev = dev_get_drvdata(&spi->dev);
+       struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi);
 
        if (!(edev->pdata->flags & EE_READONLY))
                device_remove_file(&spi->dev, &dev_attr_erase);
 
        sysfs_remove_bin_file(&spi->dev.kobj, &edev->bin);
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
        kfree(edev);
        return 0;
 }
index 16d7179..96787ec 100644 (file)
@@ -365,18 +365,7 @@ static struct platform_driver ep93xx_pwm_driver = {
        .remove         = __exit_p(ep93xx_pwm_remove),
 };
 
-static int __init ep93xx_pwm_init(void)
-{
-       return platform_driver_probe(&ep93xx_pwm_driver, ep93xx_pwm_probe);
-}
-
-static void __exit ep93xx_pwm_exit(void)
-{
-       platform_driver_unregister(&ep93xx_pwm_driver);
-}
-
-module_init(ep93xx_pwm_init);
-module_exit(ep93xx_pwm_exit);
+module_platform_driver_probe(ep93xx_pwm_driver, ep93xx_pwm_probe);
 
 MODULE_AUTHOR("Matthieu Crapet <mcrapet@gmail.com>, "
              "H Hartley Sweeten <hsweeten@visionengravers.com>");
index e8cbb1c..a725c79 100644 (file)
@@ -474,10 +474,11 @@ static int fsa9480_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
-static int fsa9480_suspend(struct i2c_client *client, pm_message_t state)
+static int fsa9480_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
        struct fsa9480_platform_data *pdata = usbsw->pdata;
 
@@ -490,8 +491,9 @@ static int fsa9480_suspend(struct i2c_client *client, pm_message_t state)
        return 0;
 }
 
-static int fsa9480_resume(struct i2c_client *client)
+static int fsa9480_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
        int dev1, dev2;
 
@@ -515,12 +517,14 @@ static int fsa9480_resume(struct i2c_client *client)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(fsa9480_pm_ops, fsa9480_suspend, fsa9480_resume);
+#define FSA9480_PM_OPS (&fsa9480_pm_ops)
+
 #else
 
-#define fsa9480_suspend NULL
-#define fsa9480_resume NULL
+#define FSA9480_PM_OPS NULL
 
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static const struct i2c_device_id fsa9480_id[] = {
        {"fsa9480", 0},
@@ -531,11 +535,10 @@ MODULE_DEVICE_TABLE(i2c, fsa9480_id);
 static struct i2c_driver fsa9480_i2c_driver = {
        .driver = {
                .name = "fsa9480",
+               .pm = FSA9480_PM_OPS,
        },
        .probe = fsa9480_probe,
        .remove = fsa9480_remove,
-       .resume = fsa9480_resume,
-       .suspend = fsa9480_suspend,
        .id_table = fsa9480_id,
 };
 
index 29b306c..c5145b3 100644 (file)
@@ -409,18 +409,20 @@ static int isl29003_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int isl29003_suspend(struct i2c_client *client, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int isl29003_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct isl29003_data *data = i2c_get_clientdata(client);
 
        data->power_state_before_suspend = isl29003_get_power_state(client);
        return isl29003_set_power_state(client, 0);
 }
 
-static int isl29003_resume(struct i2c_client *client)
+static int isl29003_resume(struct device *dev)
 {
        int i;
+       struct i2c_client *client = to_i2c_client(dev);
        struct isl29003_data *data = i2c_get_clientdata(client);
 
        /* restore registers from cache */
@@ -432,10 +434,12 @@ static int isl29003_resume(struct i2c_client *client)
                data->power_state_before_suspend);
 }
 
+static SIMPLE_DEV_PM_OPS(isl29003_pm_ops, isl29003_suspend, isl29003_resume);
+#define ISL29003_PM_OPS (&isl29003_pm_ops)
+
 #else
-#define isl29003_suspend       NULL
-#define isl29003_resume                NULL
-#endif /* CONFIG_PM */
+#define ISL29003_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
 
 static const struct i2c_device_id isl29003_id[] = {
        { "isl29003", 0 },
@@ -447,9 +451,8 @@ static struct i2c_driver isl29003_driver = {
        .driver = {
                .name   = ISL29003_DRV_NAME,
                .owner  = THIS_MODULE,
+               .pm     = ISL29003_PM_OPS,
        },
-       .suspend = isl29003_suspend,
-       .resume = isl29003_resume,
        .probe  = isl29003_probe,
        .remove = isl29003_remove,
        .id_table = isl29003_id,
index 155700b..bb26f08 100644 (file)
@@ -69,7 +69,7 @@ static const struct ecp3_dev ecp3_dev[] = {
 static void firmware_load(const struct firmware *fw, void *context)
 {
        struct spi_device *spi = (struct spi_device *)context;
-       struct fpga_data *data = dev_get_drvdata(&spi->dev);
+       struct fpga_data *data = spi_get_drvdata(spi);
        u8 *buffer;
        int ret;
        u8 txbuf[8];
index d21b4d0..c76fa31 100644 (file)
@@ -10,10 +10,9 @@ config INTEL_MEI
          <http://software.intel.com/en-us/manageability/>
 
 config INTEL_MEI_ME
-       bool "ME Enabled Intel Chipsets"
-       depends on INTEL_MEI
+       tristate "ME Enabled Intel Chipsets"
+       select INTEL_MEI
        depends on X86 && PCI && WATCHDOG_CORE
-       default y
        help
          MEI support for ME Enabled Intel chipsets.
 
index 040af6c..08698a4 100644 (file)
@@ -10,5 +10,10 @@ mei-objs += client.o
 mei-objs += main.o
 mei-objs += amthif.o
 mei-objs += wd.o
-mei-$(CONFIG_INTEL_MEI_ME) += pci-me.o
-mei-$(CONFIG_INTEL_MEI_ME) += hw-me.o
+mei-objs += bus.o
+mei-objs += nfc.o
+mei-$(CONFIG_DEBUG_FS) += debugfs.o
+
+obj-$(CONFIG_INTEL_MEI_ME) += mei-me.o
+mei-me-objs := pci-me.o
+mei-me-objs += hw-me.o
index c86d7e3..31a6212 100644 (file)
@@ -449,7 +449,7 @@ int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
        struct mei_msg_hdr mei_hdr;
        struct mei_cl *cl = cb->cl;
        size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index;
-       size_t msg_slots = mei_data2slots(len);
+       u32 msg_slots = mei_data2slots(len);
 
        mei_hdr.host_addr = cl->host_client_id;
        mei_hdr.me_addr = cl->me_client_id;
@@ -505,14 +505,15 @@ int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
  * mei_amthif_irq_read_message - read routine after ISR to
  *                     handle the read amthif message
  *
- * @complete_list: An instance of our list structure
  * @dev: the device structure
  * @mei_hdr: header of amthif message
+ * @complete_list: An instance of our list structure
  *
  * returns 0 on success, <0 on failure.
  */
-int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
-               struct mei_device *dev, struct mei_msg_hdr *mei_hdr)
+int mei_amthif_irq_read_msg(struct mei_device *dev,
+                           struct mei_msg_hdr *mei_hdr,
+                           struct mei_cl_cb *complete_list)
 {
        struct mei_cl_cb *cb;
        unsigned char *buffer;
@@ -530,8 +531,7 @@ int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
        if (!mei_hdr->msg_complete)
                return 0;
 
-       dev_dbg(&dev->pdev->dev,
-                       "amthif_message_buffer_index =%d\n",
+       dev_dbg(&dev->pdev->dev, "amthif_message_buffer_index =%d\n",
                        mei_hdr->length);
 
        dev_dbg(&dev->pdev->dev, "completed amthif read.\n ");
@@ -566,12 +566,13 @@ int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
  */
 int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
 {
+       u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
 
-       if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr)
-                       + sizeof(struct hbm_flow_control))) {
+       if (*slots < msg_slots)
                return -EMSGSIZE;
-       }
-       *slots -= mei_data2slots(sizeof(struct hbm_flow_control));
+
+       *slots -= msg_slots;
+
        if (mei_hbm_cl_flow_control_req(dev, &dev->iamthif_cl)) {
                dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
                return -EIO;
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
new file mode 100644 (file)
index 0000000..1e935ea
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2012-2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/mei_cl_bus.h>
+
+#include "mei_dev.h"
+#include "hw-me.h"
+#include "client.h"
+
+#define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
+#define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev)
+
+static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
+{
+       struct mei_cl_device *device = to_mei_cl_device(dev);
+       struct mei_cl_driver *driver = to_mei_cl_driver(drv);
+       const struct mei_cl_device_id *id;
+
+       if (!device)
+               return 0;
+
+       if (!driver || !driver->id_table)
+               return 0;
+
+       id = driver->id_table;
+
+       while (id->name[0]) {
+               if (!strcmp(dev_name(dev), id->name))
+                       return 1;
+
+               id++;
+       }
+
+       return 0;
+}
+
+static int mei_cl_device_probe(struct device *dev)
+{
+       struct mei_cl_device *device = to_mei_cl_device(dev);
+       struct mei_cl_driver *driver;
+       struct mei_cl_device_id id;
+
+       if (!device)
+               return 0;
+
+       driver = to_mei_cl_driver(dev->driver);
+       if (!driver || !driver->probe)
+               return -ENODEV;
+
+       dev_dbg(dev, "Device probe\n");
+
+       strncpy(id.name, dev_name(dev), MEI_CL_NAME_SIZE);
+
+       return driver->probe(device, &id);
+}
+
+static int mei_cl_device_remove(struct device *dev)
+{
+       struct mei_cl_device *device = to_mei_cl_device(dev);
+       struct mei_cl_driver *driver;
+
+       if (!device || !dev->driver)
+               return 0;
+
+       if (device->event_cb) {
+               device->event_cb = NULL;
+               cancel_work_sync(&device->event_work);
+       }
+
+       driver = to_mei_cl_driver(dev->driver);
+       if (!driver->remove) {
+               dev->driver = NULL;
+
+               return 0;
+       }
+
+       return driver->remove(device);
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+                            char *buf)
+{
+       int len;
+
+       len = snprintf(buf, PAGE_SIZE, "mei:%s\n", dev_name(dev));
+
+       return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute mei_cl_dev_attrs[] = {
+       __ATTR_RO(modalias),
+       __ATTR_NULL,
+};
+
+static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       if (add_uevent_var(env, "MODALIAS=mei:%s", dev_name(dev)))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static struct bus_type mei_cl_bus_type = {
+       .name           = "mei",
+       .dev_attrs      = mei_cl_dev_attrs,
+       .match          = mei_cl_device_match,
+       .probe          = mei_cl_device_probe,
+       .remove         = mei_cl_device_remove,
+       .uevent         = mei_cl_uevent,
+};
+
+static void mei_cl_dev_release(struct device *dev)
+{
+       kfree(to_mei_cl_device(dev));
+}
+
+static struct device_type mei_cl_device_type = {
+       .release        = mei_cl_dev_release,
+};
+
+static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
+                                               uuid_le uuid)
+{
+       struct mei_cl *cl, *next;
+
+       list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
+               if (!uuid_le_cmp(uuid, cl->device_uuid))
+                       return cl;
+       }
+
+       return NULL;
+}
+struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
+                                       uuid_le uuid, char *name,
+                                       struct mei_cl_ops *ops)
+{
+       struct mei_cl_device *device;
+       struct mei_cl *cl;
+       int status;
+
+       cl = mei_bus_find_mei_cl_by_uuid(dev, uuid);
+       if (cl == NULL)
+               return NULL;
+
+       device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
+       if (!device)
+               return NULL;
+
+       device->cl = cl;
+       device->ops = ops;
+
+       device->dev.parent = &dev->pdev->dev;
+       device->dev.bus = &mei_cl_bus_type;
+       device->dev.type = &mei_cl_device_type;
+
+       dev_set_name(&device->dev, "%s", name);
+
+       status = device_register(&device->dev);
+       if (status) {
+               dev_err(&dev->pdev->dev, "Failed to register MEI device\n");
+               kfree(device);
+               return NULL;
+       }
+
+       cl->device = device;
+
+       dev_dbg(&device->dev, "client %s registered\n", name);
+
+       return device;
+}
+EXPORT_SYMBOL_GPL(mei_cl_add_device);
+
+void mei_cl_remove_device(struct mei_cl_device *device)
+{
+       device_unregister(&device->dev);
+}
+EXPORT_SYMBOL_GPL(mei_cl_remove_device);
+
+int __mei_cl_driver_register(struct mei_cl_driver *driver, struct module *owner)
+{
+       int err;
+
+       driver->driver.name = driver->name;
+       driver->driver.owner = owner;
+       driver->driver.bus = &mei_cl_bus_type;
+
+       err = driver_register(&driver->driver);
+       if (err)
+               return err;
+
+       pr_debug("mei: driver [%s] registered\n", driver->driver.name);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__mei_cl_driver_register);
+
+void mei_cl_driver_unregister(struct mei_cl_driver *driver)
+{
+       driver_unregister(&driver->driver);
+
+       pr_debug("mei: driver [%s] unregistered\n", driver->driver.name);
+}
+EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
+
+static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
+                       bool blocking)
+{
+       struct mei_device *dev;
+       struct mei_cl_cb *cb;
+       int id;
+       int rets;
+
+       if (WARN_ON(!cl || !cl->dev))
+               return -ENODEV;
+
+       dev = cl->dev;
+
+       if (cl->state != MEI_FILE_CONNECTED)
+               return -ENODEV;
+
+       /* Check if we have an ME client device */
+       id = mei_me_cl_by_id(dev, cl->me_client_id);
+       if (id < 0)
+               return -ENODEV;
+
+       if (length > dev->me_clients[id].props.max_msg_length)
+               return -EINVAL;
+
+       cb = mei_io_cb_init(cl, NULL);
+       if (!cb)
+               return -ENOMEM;
+
+       rets = mei_io_cb_alloc_req_buf(cb, length);
+       if (rets < 0) {
+               mei_io_cb_free(cb);
+               return rets;
+       }
+
+       memcpy(cb->request_buffer.data, buf, length);
+
+       mutex_lock(&dev->device_lock);
+
+       rets = mei_cl_write(cl, cb, blocking);
+
+       mutex_unlock(&dev->device_lock);
+       if (rets < 0)
+               mei_io_cb_free(cb);
+
+       return rets;
+}
+
+int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
+{
+       struct mei_device *dev;
+       struct mei_cl_cb *cb;
+       size_t r_length;
+       int err;
+
+       if (WARN_ON(!cl || !cl->dev))
+               return -ENODEV;
+
+       dev = cl->dev;
+
+       mutex_lock(&dev->device_lock);
+
+       if (!cl->read_cb) {
+               err = mei_cl_read_start(cl, length);
+               if (err < 0) {
+                       mutex_unlock(&dev->device_lock);
+                       return err;
+               }
+       }
+
+       if (cl->reading_state != MEI_READ_COMPLETE &&
+           !waitqueue_active(&cl->rx_wait)) {
+               mutex_unlock(&dev->device_lock);
+
+               if (wait_event_interruptible(cl->rx_wait,
+                               (MEI_READ_COMPLETE == cl->reading_state))) {
+                       if (signal_pending(current))
+                               return -EINTR;
+                       return -ERESTARTSYS;
+               }
+
+               mutex_lock(&dev->device_lock);
+       }
+
+       cb = cl->read_cb;
+
+       if (cl->reading_state != MEI_READ_COMPLETE) {
+               r_length = 0;
+               goto out;
+       }
+
+       r_length = min_t(size_t, length, cb->buf_idx);
+
+       memcpy(buf, cb->response_buffer.data, r_length);
+
+       mei_io_cb_free(cb);
+       cl->reading_state = MEI_IDLE;
+       cl->read_cb = NULL;
+
+out:
+       mutex_unlock(&dev->device_lock);
+
+       return r_length;
+}
+
+inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
+{
+       return ___mei_cl_send(cl, buf, length, 0);
+}
+
+inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
+{
+       return ___mei_cl_send(cl, buf, length, 1);
+}
+
+int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
+{
+       struct mei_cl *cl = device->cl;
+
+       if (cl == NULL)
+               return -ENODEV;
+
+       if (device->ops && device->ops->send)
+               return device->ops->send(device, buf, length);
+
+       return __mei_cl_send(cl, buf, length);
+}
+EXPORT_SYMBOL_GPL(mei_cl_send);
+
+int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
+{
+       struct mei_cl *cl =  device->cl;
+
+       if (cl == NULL)
+               return -ENODEV;
+
+       if (device->ops && device->ops->recv)
+               return device->ops->recv(device, buf, length);
+
+       return __mei_cl_recv(cl, buf, length);
+}
+EXPORT_SYMBOL_GPL(mei_cl_recv);
+
+static void mei_bus_event_work(struct work_struct *work)
+{
+       struct mei_cl_device *device;
+
+       device = container_of(work, struct mei_cl_device, event_work);
+
+       if (device->event_cb)
+               device->event_cb(device, device->events, device->event_context);
+
+       device->events = 0;
+
+       /* Prepare for the next read */
+       mei_cl_read_start(device->cl, 0);
+}
+
+int mei_cl_register_event_cb(struct mei_cl_device *device,
+                         mei_cl_event_cb_t event_cb, void *context)
+{
+       if (device->event_cb)
+               return -EALREADY;
+
+       device->events = 0;
+       device->event_cb = event_cb;
+       device->event_context = context;
+       INIT_WORK(&device->event_work, mei_bus_event_work);
+
+       mei_cl_read_start(device->cl, 0);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
+
+void *mei_cl_get_drvdata(const struct mei_cl_device *device)
+{
+       return dev_get_drvdata(&device->dev);
+}
+EXPORT_SYMBOL_GPL(mei_cl_get_drvdata);
+
+void mei_cl_set_drvdata(struct mei_cl_device *device, void *data)
+{
+       dev_set_drvdata(&device->dev, data);
+}
+EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);
+
+int mei_cl_enable_device(struct mei_cl_device *device)
+{
+       int err;
+       struct mei_device *dev;
+       struct mei_cl *cl = device->cl;
+
+       if (cl == NULL)
+               return -ENODEV;
+
+       dev = cl->dev;
+
+       mutex_lock(&dev->device_lock);
+
+       cl->state = MEI_FILE_CONNECTING;
+
+       err = mei_cl_connect(cl, NULL);
+       if (err < 0) {
+               mutex_unlock(&dev->device_lock);
+               dev_err(&dev->pdev->dev, "Could not connect to the ME client");
+
+               return err;
+       }
+
+       mutex_unlock(&dev->device_lock);
+
+       if (device->event_cb && !cl->read_cb)
+               mei_cl_read_start(device->cl, 0);
+
+       if (!device->ops || !device->ops->enable)
+               return 0;
+
+       return device->ops->enable(device);
+}
+EXPORT_SYMBOL_GPL(mei_cl_enable_device);
+
+int mei_cl_disable_device(struct mei_cl_device *device)
+{
+       int err;
+       struct mei_device *dev;
+       struct mei_cl *cl = device->cl;
+
+       if (cl == NULL)
+               return -ENODEV;
+
+       dev = cl->dev;
+
+       mutex_lock(&dev->device_lock);
+
+       if (cl->state != MEI_FILE_CONNECTED) {
+               mutex_unlock(&dev->device_lock);
+               dev_err(&dev->pdev->dev, "Already disconnected");
+
+               return 0;
+       }
+
+       cl->state = MEI_FILE_DISCONNECTING;
+
+       err = mei_cl_disconnect(cl);
+       if (err < 0) {
+               mutex_unlock(&dev->device_lock);
+               dev_err(&dev->pdev->dev,
+                       "Could not disconnect from the ME client");
+
+               return err;
+       }
+
+       /* Flush queues and remove any pending read */
+       mei_cl_flush_queues(cl);
+
+       if (cl->read_cb) {
+               struct mei_cl_cb *cb = NULL;
+
+               cb = mei_cl_find_read_cb(cl);
+               /* Remove entry from read list */
+               if (cb)
+                       list_del(&cb->list);
+
+               cb = cl->read_cb;
+               cl->read_cb = NULL;
+
+               if (cb) {
+                       mei_io_cb_free(cb);
+                       cb = NULL;
+               }
+       }
+
+       mutex_unlock(&dev->device_lock);
+
+       if (!device->ops || !device->ops->disable)
+               return 0;
+
+       return device->ops->disable(device);
+}
+EXPORT_SYMBOL_GPL(mei_cl_disable_device);
+
+void mei_cl_bus_rx_event(struct mei_cl *cl)
+{
+       struct mei_cl_device *device = cl->device;
+
+       if (!device || !device->event_cb)
+               return;
+
+       set_bit(MEI_CL_EVENT_RX, &device->events);
+
+       schedule_work(&device->event_work);
+}
+
+int __init mei_cl_bus_init(void)
+{
+       return bus_register(&mei_cl_bus_type);
+}
+
+void __exit mei_cl_bus_exit(void)
+{
+       bus_unregister(&mei_cl_bus_type);
+}
index 1569afe..7189274 100644 (file)
@@ -216,6 +216,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
        init_waitqueue_head(&cl->rx_wait);
        init_waitqueue_head(&cl->tx_wait);
        INIT_LIST_HEAD(&cl->link);
+       INIT_LIST_HEAD(&cl->device_link);
        cl->reading_state = MEI_IDLE;
        cl->writing_state = MEI_IDLE;
        cl->dev = dev;
@@ -357,6 +358,9 @@ void mei_host_client_init(struct work_struct *work)
                        mei_amthif_host_init(dev);
                else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
                        mei_wd_host_init(dev);
+               else if (!uuid_le_cmp(client_props->protocol_name, mei_nfc_guid))
+                       mei_nfc_host_init(dev);
+
        }
 
        dev->dev_state = MEI_DEV_ENABLED;
@@ -620,7 +624,7 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
  *
  * returns 0 on success, <0 on failure.
  */
-int mei_cl_read_start(struct mei_cl *cl)
+int mei_cl_read_start(struct mei_cl *cl, size_t length)
 {
        struct mei_device *dev;
        struct mei_cl_cb *cb;
@@ -653,8 +657,9 @@ int mei_cl_read_start(struct mei_cl *cl)
        if (!cb)
                return -ENOMEM;
 
-       rets = mei_io_cb_alloc_resp_buf(cb,
-                       dev->me_clients[i].props.max_msg_length);
+       /* always allocate at least client max message */
+       length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length);
+       rets = mei_io_cb_alloc_resp_buf(cb, length);
        if (rets)
                goto err;
 
@@ -677,6 +682,111 @@ err:
 }
 
 /**
+ * mei_cl_write - submit a write cb to mei device
+       assumes device_lock is locked
+ *
+ * @cl: host client
+ * @cl: write callback with filled data
+ *
+ * returns numbe of bytes sent on success, <0 on failure.
+ */
+int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
+{
+       struct mei_device *dev;
+       struct mei_msg_data *buf;
+       struct mei_msg_hdr mei_hdr;
+       int rets;
+
+
+       if (WARN_ON(!cl || !cl->dev))
+               return -ENODEV;
+
+       if (WARN_ON(!cb))
+               return -EINVAL;
+
+       dev = cl->dev;
+
+
+       buf = &cb->request_buffer;
+
+       dev_dbg(&dev->pdev->dev, "mei_cl_write %d\n", buf->size);
+
+
+       cb->fop_type = MEI_FOP_WRITE;
+
+       rets = mei_cl_flow_ctrl_creds(cl);
+       if (rets < 0)
+               goto err;
+
+       /* Host buffer is not ready, we queue the request */
+       if (rets == 0 || !dev->hbuf_is_ready) {
+               cb->buf_idx = 0;
+               /* unseting complete will enqueue the cb for write */
+               mei_hdr.msg_complete = 0;
+               cl->writing_state = MEI_WRITING;
+               rets = buf->size;
+               goto out;
+       }
+
+       dev->hbuf_is_ready = false;
+
+       /* Check for a maximum length */
+       if (buf->size > mei_hbuf_max_len(dev)) {
+               mei_hdr.length = mei_hbuf_max_len(dev);
+               mei_hdr.msg_complete = 0;
+       } else {
+               mei_hdr.length = buf->size;
+               mei_hdr.msg_complete = 1;
+       }
+
+       mei_hdr.host_addr = cl->host_client_id;
+       mei_hdr.me_addr = cl->me_client_id;
+       mei_hdr.reserved = 0;
+
+       dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n",
+               MEI_HDR_PRM(&mei_hdr));
+
+
+       if (mei_write_message(dev, &mei_hdr, buf->data)) {
+               rets = -EIO;
+               goto err;
+       }
+
+       cl->writing_state = MEI_WRITING;
+       cb->buf_idx = mei_hdr.length;
+
+       rets = buf->size;
+out:
+       if (mei_hdr.msg_complete) {
+               if (mei_cl_flow_ctrl_reduce(cl)) {
+                       rets = -ENODEV;
+                       goto err;
+               }
+               list_add_tail(&cb->list, &dev->write_waiting_list.list);
+       } else {
+               list_add_tail(&cb->list, &dev->write_list.list);
+       }
+
+
+       if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
+
+               mutex_unlock(&dev->device_lock);
+               if (wait_event_interruptible(cl->tx_wait,
+                       cl->writing_state == MEI_WRITE_COMPLETE)) {
+                               if (signal_pending(current))
+                                       rets = -EINTR;
+                               else
+                                       rets = -ERESTARTSYS;
+               }
+               mutex_lock(&dev->device_lock);
+       }
+err:
+       return rets;
+}
+
+
+
+/**
  * mei_cl_all_disconnect - disconnect forcefully all connected clients
  *
  * @dev - mei device
index 214b239..cfdb144 100644 (file)
@@ -86,17 +86,16 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
  */
 bool mei_cl_is_other_connecting(struct mei_cl *cl);
 int mei_cl_disconnect(struct mei_cl *cl);
-
-int mei_cl_read_start(struct mei_cl *cl);
-
 int mei_cl_connect(struct mei_cl *cl, struct file *file);
+int mei_cl_read_start(struct mei_cl *cl, size_t length);
+int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);
 
 void mei_host_client_init(struct work_struct *work);
 
 
+
 void mei_cl_all_disconnect(struct mei_device *dev);
 void mei_cl_all_read_wakeup(struct mei_device *dev);
 void mei_cl_all_write_clear(struct mei_device *dev);
 
-
 #endif /* _MEI_CLIENT_H_ */
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
new file mode 100644 (file)
index 0000000..e3870f2
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2012-2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/pci.h>
+
+#include <linux/mei.h>
+
+#include "mei_dev.h"
+#include "hw.h"
+
+static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
+                                       size_t cnt, loff_t *ppos)
+{
+       struct mei_device *dev = fp->private_data;
+       struct mei_me_client *cl;
+       const size_t bufsz = 1024;
+       char *buf = kzalloc(bufsz, GFP_KERNEL);
+       int i;
+       int pos = 0;
+       int ret;
+
+       if  (!buf)
+               return -ENOMEM;
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "  |id|addr|         UUID                       |con|msg len|\n");
+
+       mutex_lock(&dev->device_lock);
+
+       /*  if the driver is not enabled the list won't b consitent */
+       if (dev->dev_state != MEI_DEV_ENABLED)
+               goto out;
+
+       for (i = 0; i < dev->me_clients_num; i++) {
+               cl = &dev->me_clients[i];
+
+               /* skip me clients that cannot be connected */
+               if (cl->props.max_number_of_connections == 0)
+                       continue;
+
+               pos += scnprintf(buf + pos, bufsz - pos,
+                       "%2d|%2d|%4d|%pUl|%3d|%7d|\n",
+                       i, cl->client_id,
+                       cl->props.fixed_address,
+                       &cl->props.protocol_name,
+                       cl->props.max_number_of_connections,
+                       cl->props.max_msg_length);
+       }
+out:
+       mutex_unlock(&dev->device_lock);
+       ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations mei_dbgfs_fops_meclients = {
+       .open = simple_open,
+       .read = mei_dbgfs_read_meclients,
+       .llseek = generic_file_llseek,
+};
+
+static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
+                                       size_t cnt, loff_t *ppos)
+{
+       struct mei_device *dev = fp->private_data;
+       const size_t bufsz = 1024;
+       char *buf = kzalloc(bufsz, GFP_KERNEL);
+       int pos = 0;
+       int ret;
+
+       if  (!buf)
+               return -ENOMEM;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
+                       mei_dev_state_str(dev->dev_state));
+       ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+static const struct file_operations mei_dbgfs_fops_devstate = {
+       .open = simple_open,
+       .read = mei_dbgfs_read_devstate,
+       .llseek = generic_file_llseek,
+};
+
+/**
+ * mei_dbgfs_deregister - Remove the debugfs files and directories
+ * @mei - pointer to mei device private dat
+ */
+void mei_dbgfs_deregister(struct mei_device *dev)
+{
+       if (!dev->dbgfs_dir)
+               return;
+       debugfs_remove_recursive(dev->dbgfs_dir);
+       dev->dbgfs_dir = NULL;
+}
+
+/**
+ * Add the debugfs files
+ *
+ */
+int mei_dbgfs_register(struct mei_device *dev, const char *name)
+{
+       struct dentry *dir, *f;
+       dir = debugfs_create_dir(name, NULL);
+       if (!dir)
+               return -ENOMEM;
+
+       f = debugfs_create_file("meclients", S_IRUSR, dir,
+                               dev, &mei_dbgfs_fops_meclients);
+       if (!f) {
+               dev_err(&dev->pdev->dev, "meclients: registration failed\n");
+               goto err;
+       }
+       f = debugfs_create_file("devstate", S_IRUSR, dir,
+                               dev, &mei_dbgfs_fops_devstate);
+       if (!f) {
+               dev_err(&dev->pdev->dev, "devstate: registration failed\n");
+               goto err;
+       }
+       dev->dbgfs_dir = dir;
+       return 0;
+err:
+       mei_dbgfs_deregister(dev);
+       return -ENODEV;
+}
+
index fb9e63b..db605f5 100644 (file)
@@ -52,7 +52,7 @@ static void mei_hbm_me_cl_allocate(struct mei_device *dev)
                        sizeof(struct mei_me_client), GFP_KERNEL);
        if (!clients) {
                dev_err(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
-               dev->dev_state = MEI_DEV_RESETING;
+               dev->dev_state = MEI_DEV_RESETTING;
                mei_reset(dev, 1);
                return;
        }
@@ -123,12 +123,33 @@ static bool is_treat_specially_client(struct mei_cl *cl,
        return false;
 }
 
+int mei_hbm_start_wait(struct mei_device *dev)
+{
+       int ret;
+       if (dev->hbm_state > MEI_HBM_START)
+               return 0;
+
+       mutex_unlock(&dev->device_lock);
+       ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
+                       dev->hbm_state == MEI_HBM_IDLE ||
+                       dev->hbm_state > MEI_HBM_START,
+                       mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
+       mutex_lock(&dev->device_lock);
+
+       if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
+               dev->hbm_state = MEI_HBM_IDLE;
+               dev_err(&dev->pdev->dev, "wating for mei start failed\n");
+               return -ETIMEDOUT;
+       }
+       return 0;
+}
+
 /**
  * mei_hbm_start_req - sends start request message.
  *
  * @dev: the device structure
  */
-void mei_hbm_start_req(struct mei_device *dev)
+int mei_hbm_start_req(struct mei_device *dev)
 {
        struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
        struct hbm_host_version_request *start_req;
@@ -143,18 +164,19 @@ void mei_hbm_start_req(struct mei_device *dev)
        start_req->host_version.major_version = HBM_MAJOR_VERSION;
        start_req->host_version.minor_version = HBM_MINOR_VERSION;
 
-       dev->recvd_msg = false;
+       dev->hbm_state = MEI_HBM_IDLE;
        if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
-               dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
-               dev->dev_state = MEI_DEV_RESETING;
+               dev_err(&dev->pdev->dev, "version message writet failed\n");
+               dev->dev_state = MEI_DEV_RESETTING;
                mei_reset(dev, 1);
+               return -ENODEV;
        }
-       dev->init_clients_state = MEI_START_MESSAGE;
+       dev->hbm_state = MEI_HBM_START;
        dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
-       return ;
+       return 0;
 }
 
-/**
+/*
  * mei_hbm_enum_clients_req - sends enumeration client request message.
  *
  * @dev: the device structure
@@ -174,11 +196,11 @@ static void mei_hbm_enum_clients_req(struct mei_device *dev)
        enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
 
        if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
-               dev->dev_state = MEI_DEV_RESETING;
-               dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
+               dev->dev_state = MEI_DEV_RESETTING;
+               dev_err(&dev->pdev->dev, "enumeration request write failed.\n");
                mei_reset(dev, 1);
        }
-       dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
+       dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
        dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
        return;
 }
@@ -208,6 +230,7 @@ static int mei_hbm_prop_req(struct mei_device *dev)
 
        /* We got all client properties */
        if (next_client_index == MEI_CLIENTS_MAX) {
+               dev->hbm_state = MEI_HBM_STARTED;
                schedule_work(&dev->init_work);
 
                return 0;
@@ -226,8 +249,8 @@ static int mei_hbm_prop_req(struct mei_device *dev)
        prop_req->address = next_client_index;
 
        if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
-               dev->dev_state = MEI_DEV_RESETING;
-               dev_err(&dev->pdev->dev, "Properties request command failed\n");
+               dev->dev_state = MEI_DEV_RESETTING;
+               dev_err(&dev->pdev->dev, "properties request write failed\n");
                mei_reset(dev, 1);
 
                return -EIO;
@@ -542,27 +565,28 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
                        dev->version = version_res->me_max_version;
                        dev_dbg(&dev->pdev->dev, "version mismatch.\n");
 
+                       dev->hbm_state = MEI_HBM_STOP;
                        mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
                                                dev->wr_msg.data);
                        mei_write_message(dev, &dev->wr_msg.hdr,
                                        dev->wr_msg.data);
+
                        return;
                }
 
                dev->version.major_version = HBM_MAJOR_VERSION;
                dev->version.minor_version = HBM_MINOR_VERSION;
                if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
-                   dev->init_clients_state == MEI_START_MESSAGE) {
+                   dev->hbm_state == MEI_HBM_START) {
                        dev->init_clients_timer = 0;
                        mei_hbm_enum_clients_req(dev);
                } else {
-                       dev->recvd_msg = false;
-                       dev_dbg(&dev->pdev->dev, "reset due to received hbm: host start\n");
+                       dev_err(&dev->pdev->dev, "reset: wrong host start response\n");
                        mei_reset(dev, 1);
                        return;
                }
 
-               dev->recvd_msg = true;
+               wake_up_interruptible(&dev->wait_recvd_msg);
                dev_dbg(&dev->pdev->dev, "host start response message received.\n");
                break;
 
@@ -591,23 +615,20 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
                me_client = &dev->me_clients[dev->me_client_presentation_num];
 
                if (props_res->status || !dev->me_clients) {
-                       dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
+                       dev_err(&dev->pdev->dev, "reset: properties response hbm wrong status.\n");
                        mei_reset(dev, 1);
                        return;
                }
 
                if (me_client->client_id != props_res->address) {
-                       dev_err(&dev->pdev->dev,
-                               "Host client properties reply mismatch\n");
+                       dev_err(&dev->pdev->dev, "reset: host properties response address mismatch\n");
                        mei_reset(dev, 1);
-
                        return;
                }
 
                if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
-                   dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) {
-                       dev_err(&dev->pdev->dev,
-                               "Unexpected client properties reply\n");
+                   dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
+                       dev_err(&dev->pdev->dev, "reset: unexpected properties response\n");
                        mei_reset(dev, 1);
 
                        return;
@@ -626,26 +647,28 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
                enum_res = (struct hbm_host_enum_response *) mei_msg;
                memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
                if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
-                   dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
+                   dev->hbm_state == MEI_HBM_ENUM_CLIENTS) {
                                dev->init_clients_timer = 0;
                                dev->me_client_presentation_num = 0;
                                dev->me_client_index = 0;
                                mei_hbm_me_cl_allocate(dev);
-                               dev->init_clients_state =
-                                       MEI_CLIENT_PROPERTIES_MESSAGE;
+                               dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
 
                                /* first property reqeust */
                                mei_hbm_prop_req(dev);
                } else {
-                       dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
+                       dev_err(&dev->pdev->dev, "reset: unexpected enumeration response hbm.\n");
                        mei_reset(dev, 1);
                        return;
                }
                break;
 
        case HOST_STOP_RES_CMD:
+
+               if (dev->hbm_state != MEI_HBM_STOP)
+                       dev_err(&dev->pdev->dev, "unexpected stop response hbm.\n");
                dev->dev_state = MEI_DEV_DISABLED;
-               dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
+               dev_info(&dev->pdev->dev, "reset: FW stop response.\n");
                mei_reset(dev, 1);
                break;
 
@@ -657,6 +680,7 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
 
        case ME_STOP_REQ_CMD:
 
+               dev->hbm_state = MEI_HBM_STOP;
                mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
                                        dev->wr_ext_msg.data);
                break;
index b552afb..e80dc24 100644 (file)
 #ifndef _MEI_HBM_H_
 #define _MEI_HBM_H_
 
+struct mei_device;
+struct mei_msg_hdr;
+struct mei_cl;
+
+/**
+ * enum mei_hbm_state - host bus message protocol state
+ *
+ * @MEI_HBM_IDLE : protocol not started
+ * @MEI_HBM_START : start request message was sent
+ * @MEI_HBM_ENUM_CLIENTS : enumeration request was sent
+ * @MEI_HBM_CLIENT_PROPERTIES : acquiring clients properties
+ */
+enum mei_hbm_state {
+       MEI_HBM_IDLE = 0,
+       MEI_HBM_START,
+       MEI_HBM_ENUM_CLIENTS,
+       MEI_HBM_CLIENT_PROPERTIES,
+       MEI_HBM_STARTED,
+       MEI_HBM_STOP,
+};
+
 void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr);
 
 static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
@@ -28,8 +49,8 @@ static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
        hdr->reserved = 0;
 }
 
-void mei_hbm_start_req(struct mei_device *dev);
-
+int mei_hbm_start_req(struct mei_device *dev);
+int mei_hbm_start_wait(struct mei_device *dev);
 int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl);
 int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl);
 int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl);
index 642c622..fc03227 100644 (file)
 
 
 /**
- * mei_reg_read - Reads 32bit data from the mei device
+ * mei_me_reg_read - Reads 32bit data from the mei device
  *
  * @dev: the device structure
  * @offset: offset from which to read the data
  *
  * returns register value (u32)
  */
-static inline u32 mei_reg_read(const struct mei_me_hw *hw,
+static inline u32 mei_me_reg_read(const struct mei_me_hw *hw,
                               unsigned long offset)
 {
        return ioread32(hw->mem_addr + offset);
@@ -41,20 +41,20 @@ static inline u32 mei_reg_read(const struct mei_me_hw *hw,
 
 
 /**
- * mei_reg_write - Writes 32bit data to the mei device
+ * mei_me_reg_write - Writes 32bit data to the mei device
  *
  * @dev: the device structure
  * @offset: offset from which to write the data
  * @value: register value to write (u32)
  */
-static inline void mei_reg_write(const struct mei_me_hw *hw,
+static inline void mei_me_reg_write(const struct mei_me_hw *hw,
                                 unsigned long offset, u32 value)
 {
        iowrite32(value, hw->mem_addr + offset);
 }
 
 /**
- * mei_mecbrw_read - Reads 32bit data from ME circular buffer
+ * mei_me_mecbrw_read - Reads 32bit data from ME circular buffer
  *  read window register
  *
  * @dev: the device structure
@@ -63,18 +63,18 @@ static inline void mei_reg_write(const struct mei_me_hw *hw,
  */
 static u32 mei_me_mecbrw_read(const struct mei_device *dev)
 {
-       return mei_reg_read(to_me_hw(dev), ME_CB_RW);
+       return mei_me_reg_read(to_me_hw(dev), ME_CB_RW);
 }
 /**
- * mei_mecsr_read - Reads 32bit data from the ME CSR
+ * mei_me_mecsr_read - Reads 32bit data from the ME CSR
  *
  * @dev: the device structure
  *
  * returns ME_CSR_HA register value (u32)
  */
-static inline u32 mei_mecsr_read(const struct mei_me_hw *hw)
+static inline u32 mei_me_mecsr_read(const struct mei_me_hw *hw)
 {
-       return mei_reg_read(hw, ME_CSR_HA);
+       return mei_me_reg_read(hw, ME_CSR_HA);
 }
 
 /**
@@ -86,7 +86,7 @@ static inline u32 mei_mecsr_read(const struct mei_me_hw *hw)
  */
 static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
 {
-       return mei_reg_read(hw, H_CSR);
+       return mei_me_reg_read(hw, H_CSR);
 }
 
 /**
@@ -98,7 +98,7 @@ static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
 static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
 {
        hcsr &= ~H_IS;
-       mei_reg_write(hw, H_CSR, hcsr);
+       mei_me_reg_write(hw, H_CSR, hcsr);
 }
 
 
@@ -123,7 +123,7 @@ static void mei_me_intr_clear(struct mei_device *dev)
        struct mei_me_hw *hw = to_me_hw(dev);
        u32 hcsr = mei_hcsr_read(hw);
        if ((hcsr & H_IS) == H_IS)
-               mei_reg_write(hw, H_CSR, hcsr);
+               mei_me_reg_write(hw, H_CSR, hcsr);
 }
 /**
  * mei_me_intr_enable - enables mei device interrupts
@@ -228,10 +228,42 @@ static bool mei_me_host_is_ready(struct mei_device *dev)
 static bool mei_me_hw_is_ready(struct mei_device *dev)
 {
        struct mei_me_hw *hw = to_me_hw(dev);
-       hw->me_hw_state = mei_mecsr_read(hw);
+       hw->me_hw_state = mei_me_mecsr_read(hw);
        return (hw->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA;
 }
 
+static int mei_me_hw_ready_wait(struct mei_device *dev)
+{
+       int err;
+       if (mei_me_hw_is_ready(dev))
+               return 0;
+
+       mutex_unlock(&dev->device_lock);
+       err = wait_event_interruptible_timeout(dev->wait_hw_ready,
+                       dev->recvd_hw_ready, MEI_INTEROP_TIMEOUT);
+       mutex_lock(&dev->device_lock);
+       if (!err && !dev->recvd_hw_ready) {
+               dev_err(&dev->pdev->dev,
+                       "wait hw ready failed. status = 0x%x\n", err);
+               return -ETIMEDOUT;
+       }
+
+       dev->recvd_hw_ready = false;
+       return 0;
+}
+
+static int mei_me_hw_start(struct mei_device *dev)
+{
+       int ret = mei_me_hw_ready_wait(dev);
+       if (ret)
+               return ret;
+       dev_dbg(&dev->pdev->dev, "hw is ready\n");
+
+       mei_me_host_set_ready(dev);
+       return ret;
+}
+
+
 /**
  * mei_hbuf_filled_slots - gets number of device filled buffer slots
  *
@@ -305,10 +337,11 @@ static int mei_me_write_message(struct mei_device *dev,
                        unsigned char *buf)
 {
        struct mei_me_hw *hw = to_me_hw(dev);
-       unsigned long rem, dw_cnt;
+       unsigned long rem;
        unsigned long length = header->length;
        u32 *reg_buf = (u32 *)buf;
        u32 hcsr;
+       u32 dw_cnt;
        int i;
        int empty_slots;
 
@@ -321,16 +354,16 @@ static int mei_me_write_message(struct mei_device *dev,
        if (empty_slots < 0 || dw_cnt > empty_slots)
                return -EIO;
 
-       mei_reg_write(hw, H_CB_WW, *((u32 *) header));
+       mei_me_reg_write(hw, H_CB_WW, *((u32 *) header));
 
        for (i = 0; i < length / 4; i++)
-               mei_reg_write(hw, H_CB_WW, reg_buf[i]);
+               mei_me_reg_write(hw, H_CB_WW, reg_buf[i]);
 
        rem = length & 0x3;
        if (rem > 0) {
                u32 reg = 0;
                memcpy(&reg, &buf[length - rem], rem);
-               mei_reg_write(hw, H_CB_WW, reg);
+               mei_me_reg_write(hw, H_CB_WW, reg);
        }
 
        hcsr = mei_hcsr_read(hw) | H_IG;
@@ -354,7 +387,7 @@ static int mei_me_count_full_read_slots(struct mei_device *dev)
        char read_ptr, write_ptr;
        unsigned char buffer_depth, filled_slots;
 
-       hw->me_hw_state = mei_mecsr_read(hw);
+       hw->me_hw_state = mei_me_mecsr_read(hw);
        buffer_depth = (unsigned char)((hw->me_hw_state & ME_CBD_HRA) >> 24);
        read_ptr = (char) ((hw->me_hw_state & ME_CBRP_HRA) >> 8);
        write_ptr = (char) ((hw->me_hw_state & ME_CBWP_HRA) >> 16);
@@ -414,7 +447,7 @@ irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
                return IRQ_NONE;
 
        /* clear H_IS bit in H_CSR */
-       mei_reg_write(hw, H_CSR, csr_reg);
+       mei_me_reg_write(hw, H_CSR, csr_reg);
 
        return IRQ_WAKE_THREAD;
 }
@@ -433,12 +466,8 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
 {
        struct mei_device *dev = (struct mei_device *) dev_id;
        struct mei_cl_cb complete_list;
-       struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
-       struct mei_cl *cl;
        s32 slots;
        int rets;
-       bool  bus_message_received;
-
 
        dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
        /* initialize our complete list */
@@ -452,7 +481,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
 
        /* check if ME wants a reset */
        if (!mei_hw_is_ready(dev) &&
-           dev->dev_state != MEI_DEV_RESETING &&
+           dev->dev_state != MEI_DEV_RESETTING &&
            dev->dev_state != MEI_DEV_INITIALIZING) {
                dev_dbg(&dev->pdev->dev, "FW not ready.\n");
                mei_reset(dev, 1);
@@ -465,14 +494,9 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
                if (mei_hw_is_ready(dev)) {
                        dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
 
-                       mei_host_set_ready(dev);
+                       dev->recvd_hw_ready = true;
+                       wake_up_interruptible(&dev->wait_hw_ready);
 
-                       dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
-                       /* link is established * start sending messages.  */
-
-                       dev->dev_state = MEI_DEV_INIT_CLIENTS;
-
-                       mei_hbm_start_req(dev);
                        mutex_unlock(&dev->device_lock);
                        return IRQ_HANDLED;
                } else {
@@ -499,44 +523,20 @@ end:
        dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
        dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
 
-       bus_message_received = false;
-       if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
-               dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
-               bus_message_received = true;
-       }
        mutex_unlock(&dev->device_lock);
-       if (bus_message_received) {
-               dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
-               wake_up_interruptible(&dev->wait_recvd_msg);
-               bus_message_received = false;
-       }
-       if (list_empty(&complete_list.list))
-               return IRQ_HANDLED;
 
+       mei_irq_compl_handler(dev, &complete_list);
 
-       list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) {
-               cl = cb_pos->cl;
-               list_del(&cb_pos->list);
-               if (cl) {
-                       if (cl != &dev->iamthif_cl) {
-                               dev_dbg(&dev->pdev->dev, "completing call back.\n");
-                               mei_irq_complete_handler(cl, cb_pos);
-                               cb_pos = NULL;
-                       } else if (cl == &dev->iamthif_cl) {
-                               mei_amthif_complete(dev, cb_pos);
-                       }
-               }
-       }
        return IRQ_HANDLED;
 }
 static const struct mei_hw_ops mei_me_hw_ops = {
 
-       .host_set_ready = mei_me_host_set_ready,
        .host_is_ready = mei_me_host_is_ready,
 
        .hw_is_ready = mei_me_hw_is_ready,
        .hw_reset = mei_me_hw_reset,
-       .hw_config  = mei_me_hw_config,
+       .hw_config = mei_me_hw_config,
+       .hw_start = mei_me_hw_start,
 
        .intr_clear = mei_me_intr_clear,
        .intr_enable = mei_me_intr_enable,
@@ -571,14 +571,6 @@ struct mei_device *mei_me_dev_init(struct pci_dev *pdev)
 
        mei_device_init(dev);
 
-       INIT_LIST_HEAD(&dev->wd_cl.link);
-       INIT_LIST_HEAD(&dev->iamthif_cl.link);
-       mei_io_list_init(&dev->amthif_cmd_list);
-       mei_io_list_init(&dev->amthif_rd_complete_list);
-
-       INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
-       INIT_WORK(&dev->init_work, mei_host_client_init);
-
        dev->ops = &mei_me_hw_ops;
 
        dev->pdev = pdev;
index 8518d3e..80bd829 100644 (file)
@@ -36,12 +36,6 @@ struct mei_me_hw {
 
 struct mei_device *mei_me_dev_init(struct pci_dev *pdev);
 
-/* get slots (dwords) from a message length + header (bytes) */
-static inline unsigned char mei_data2slots(size_t length)
-{
-       return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4);
-}
-
 irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id);
 irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id);
 
index 3561799..713d89f 100644 (file)
@@ -14,6 +14,7 @@
  *
  */
 
+#include <linux/export.h>
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
@@ -22,6 +23,7 @@
 #include <linux/mei.h>
 
 #include "mei_dev.h"
+#include "hbm.h"
 #include "client.h"
 
 const char *mei_dev_state_str(int state)
@@ -31,9 +33,8 @@ const char *mei_dev_state_str(int state)
        MEI_DEV_STATE(INITIALIZING);
        MEI_DEV_STATE(INIT_CLIENTS);
        MEI_DEV_STATE(ENABLED);
-       MEI_DEV_STATE(RESETING);
+       MEI_DEV_STATE(RESETTING);
        MEI_DEV_STATE(DISABLED);
-       MEI_DEV_STATE(RECOVERING_FROM_RESET);
        MEI_DEV_STATE(POWER_DOWN);
        MEI_DEV_STATE(POWER_UP);
        default:
@@ -46,7 +47,9 @@ void mei_device_init(struct mei_device *dev)
 {
        /* setup our list array */
        INIT_LIST_HEAD(&dev->file_list);
+       INIT_LIST_HEAD(&dev->device_list);
        mutex_init(&dev->device_lock);
+       init_waitqueue_head(&dev->wait_hw_ready);
        init_waitqueue_head(&dev->wait_recvd_msg);
        init_waitqueue_head(&dev->wait_stop_wd);
        dev->dev_state = MEI_DEV_INITIALIZING;
@@ -56,19 +59,27 @@ void mei_device_init(struct mei_device *dev)
        mei_io_list_init(&dev->write_waiting_list);
        mei_io_list_init(&dev->ctrl_wr_list);
        mei_io_list_init(&dev->ctrl_rd_list);
+
+       INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
+       INIT_WORK(&dev->init_work, mei_host_client_init);
+
+       INIT_LIST_HEAD(&dev->wd_cl.link);
+       INIT_LIST_HEAD(&dev->iamthif_cl.link);
+       mei_io_list_init(&dev->amthif_cmd_list);
+       mei_io_list_init(&dev->amthif_rd_complete_list);
+
 }
+EXPORT_SYMBOL_GPL(mei_device_init);
 
 /**
- * mei_hw_init - initializes host and fw to start work.
+ * mei_start - initializes host and fw to start work.
  *
  * @dev: the device structure
  *
  * returns 0 on success, <0 on failure.
  */
-int mei_hw_init(struct mei_device *dev)
+int mei_start(struct mei_device *dev)
 {
-       int ret = 0;
-
        mutex_lock(&dev->device_lock);
 
        /* acknowledge interrupt and stop interupts */
@@ -76,29 +87,15 @@ int mei_hw_init(struct mei_device *dev)
 
        mei_hw_config(dev);
 
-       dev->recvd_msg = false;
        dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
 
        mei_reset(dev, 1);
 
-       /* wait for ME to turn on ME_RDY */
-       if (!dev->recvd_msg) {
-               mutex_unlock(&dev->device_lock);
-               ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
-                       dev->recvd_msg,
-                       mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
-               mutex_lock(&dev->device_lock);
-       }
-
-       if (ret <= 0 && !dev->recvd_msg) {
-               dev->dev_state = MEI_DEV_DISABLED;
-               dev_dbg(&dev->pdev->dev,
-                       "wait_event_interruptible_timeout failed"
-                       "on wait for ME to turn on ME_RDY.\n");
+       if (mei_hbm_start_wait(dev)) {
+               dev_err(&dev->pdev->dev, "HBM haven't started");
                goto err;
        }
 
-
        if (!mei_host_is_ready(dev)) {
                dev_err(&dev->pdev->dev, "host is not ready.\n");
                goto err;
@@ -115,7 +112,6 @@ int mei_hw_init(struct mei_device *dev)
                goto err;
        }
 
-       dev->recvd_msg = false;
        dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
 
        mutex_unlock(&dev->device_lock);
@@ -126,6 +122,7 @@ err:
        mutex_unlock(&dev->device_lock);
        return -ENODEV;
 }
+EXPORT_SYMBOL_GPL(mei_start);
 
 /**
  * mei_reset - resets host and fw.
@@ -137,9 +134,6 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
 {
        bool unexpected;
 
-       if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET)
-               return;
-
        unexpected = (dev->dev_state != MEI_DEV_INITIALIZING &&
                        dev->dev_state != MEI_DEV_DISABLED &&
                        dev->dev_state != MEI_DEV_POWER_DOWN &&
@@ -147,11 +141,12 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
 
        mei_hw_reset(dev, interrupts_enabled);
 
+       dev->hbm_state = MEI_HBM_IDLE;
 
        if (dev->dev_state != MEI_DEV_INITIALIZING) {
                if (dev->dev_state != MEI_DEV_DISABLED &&
                    dev->dev_state != MEI_DEV_POWER_DOWN)
-                       dev->dev_state = MEI_DEV_RESETING;
+                       dev->dev_state = MEI_DEV_RESETTING;
 
                mei_cl_all_disconnect(dev);
 
@@ -176,12 +171,27 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
                dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
                         mei_dev_state_str(dev->dev_state));
 
+       if (!interrupts_enabled) {
+               dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n");
+               return;
+       }
+
+       mei_hw_start(dev);
+
+       dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
+       /* link is established * start sending messages.  */
+
+       dev->dev_state = MEI_DEV_INIT_CLIENTS;
+
+       mei_hbm_start_req(dev);
+
        /* wake up all readings so they can be interrupted */
        mei_cl_all_read_wakeup(dev);
 
        /* remove all waiting requests */
        mei_cl_all_write_clear(dev);
 }
+EXPORT_SYMBOL_GPL(mei_reset);
 
 void mei_stop(struct mei_device *dev)
 {
@@ -193,14 +203,18 @@ void mei_stop(struct mei_device *dev)
 
        mei_wd_stop(dev);
 
+       mei_nfc_host_exit();
+
        dev->dev_state = MEI_DEV_POWER_DOWN;
        mei_reset(dev, 0);
 
        mutex_unlock(&dev->device_lock);
 
        flush_scheduled_work();
-}
 
+       mei_watchdog_unregister(dev);
+}
+EXPORT_SYMBOL_GPL(mei_stop);
 
 
 
index 3535b26..1473cfd 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 
+#include <linux/export.h>
 #include <linux/pci.h>
 #include <linux/kthread.h>
 #include <linux/interrupt.h>
 
 
 /**
- * mei_complete_handler - processes completed operation.
+ * mei_cl_complete_handler - processes completed operation for a client
  *
  * @cl: private data of the file object.
- * @cb_pos: callback block.
+ * @cb: callback block.
  */
-void mei_irq_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
+static void mei_cl_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb)
 {
-       if (cb_pos->fop_type == MEI_FOP_WRITE) {
-               mei_io_cb_free(cb_pos);
-               cb_pos = NULL;
+       if (cb->fop_type == MEI_FOP_WRITE) {
+               mei_io_cb_free(cb);
+               cb = NULL;
                cl->writing_state = MEI_WRITE_COMPLETE;
                if (waitqueue_active(&cl->tx_wait))
                        wake_up_interruptible(&cl->tx_wait);
 
-       } else if (cb_pos->fop_type == MEI_FOP_READ &&
+       } else if (cb->fop_type == MEI_FOP_READ &&
                        MEI_READING == cl->reading_state) {
                cl->reading_state = MEI_READ_COMPLETE;
                if (waitqueue_active(&cl->rx_wait))
                        wake_up_interruptible(&cl->rx_wait);
+               else
+                       mei_cl_bus_rx_event(cl);
+
+       }
+}
+
+/**
+ * mei_irq_compl_handler - dispatch complete handelers
+ *     for the completed callbacks
+ *
+ * @dev - mei device
+ * @compl_list - list of completed cbs
+ */
+void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list)
+{
+       struct mei_cl_cb *cb, *next;
+       struct mei_cl *cl;
+
+       list_for_each_entry_safe(cb, next, &compl_list->list, list) {
+               cl = cb->cl;
+               list_del(&cb->list);
+               if (!cl)
+                       continue;
 
+               dev_dbg(&dev->pdev->dev, "completing call back.\n");
+               if (cl == &dev->iamthif_cl)
+                       mei_amthif_complete(dev, cb);
+               else
+                       mei_cl_complete_handler(cl, cb);
        }
 }
+EXPORT_SYMBOL_GPL(mei_irq_compl_handler);
 
 /**
- * _mei_irq_thread_state_ok - checks if mei header matches file private data
+ * mei_cl_hbm_equal - check if hbm is addressed to the client
  *
- * @cl: private data of the file object
+ * @cl: host client
  * @mei_hdr: header of mei client message
  *
- * returns !=0 if matches, 0 if no match.
+ * returns true if matches, false otherwise
+ */
+static inline int mei_cl_hbm_equal(struct mei_cl *cl,
+                       struct mei_msg_hdr *mei_hdr)
+{
+       return cl->host_client_id == mei_hdr->host_addr &&
+               cl->me_client_id == mei_hdr->me_addr;
+}
+/**
+ * mei_cl_is_reading - checks if the client
+               is the one to read this message
+ *
+ * @cl: mei client
+ * @mei_hdr: header of mei message
+ *
+ * returns true on match and false otherwise
  */
-static int _mei_irq_thread_state_ok(struct mei_cl *cl,
-                               struct mei_msg_hdr *mei_hdr)
+static bool mei_cl_is_reading(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr)
 {
-       return (cl->host_client_id == mei_hdr->host_addr &&
-               cl->me_client_id == mei_hdr->me_addr &&
+       return mei_cl_hbm_equal(cl, mei_hdr) &&
                cl->state == MEI_FILE_CONNECTED &&
-               MEI_READ_COMPLETE != cl->reading_state);
+               cl->reading_state != MEI_READ_COMPLETE;
 }
 
 /**
- * mei_irq_thread_read_client_message - bottom half read routine after ISR to
- * handle the read mei client message data processing.
+ * mei_irq_read_client_message - process client message
  *
- * @complete_list: An instance of our list structure
  * @dev: the device structure
  * @mei_hdr: header of mei client message
+ * @complete_list: An instance of our list structure
  *
  * returns 0 on success, <0 on failure.
  */
-static int mei_irq_thread_read_client_message(struct mei_cl_cb *complete_list,
-               struct mei_device *dev,
-               struct mei_msg_hdr *mei_hdr)
+static int mei_cl_irq_read_msg(struct mei_device *dev,
+                              struct mei_msg_hdr *mei_hdr,
+                              struct mei_cl_cb *complete_list)
 {
        struct mei_cl *cl;
-       struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
+       struct mei_cl_cb *cb, *next;
        unsigned char *buffer = NULL;
 
-       dev_dbg(&dev->pdev->dev, "start client msg\n");
-       if (list_empty(&dev->read_list.list))
-               goto quit;
+       list_for_each_entry_safe(cb, next, &dev->read_list.list, list) {
+               cl = cb->cl;
+               if (!cl || !mei_cl_is_reading(cl, mei_hdr))
+                       continue;
 
-       list_for_each_entry_safe(cb_pos, cb_next, &dev->read_list.list, list) {
-               cl = cb_pos->cl;
-               if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
-                       cl->reading_state = MEI_READING;
-                       buffer = cb_pos->response_buffer.data + cb_pos->buf_idx;
+               cl->reading_state = MEI_READING;
 
-                       if (cb_pos->response_buffer.size <
-                                       mei_hdr->length + cb_pos->buf_idx) {
-                               dev_dbg(&dev->pdev->dev, "message overflow.\n");
-                               list_del(&cb_pos->list);
+               if (cb->response_buffer.size == 0 ||
+                   cb->response_buffer.data == NULL) {
+                       dev_err(&dev->pdev->dev, "response buffer is not allocated.\n");
+                       list_del(&cb->list);
+                       return -ENOMEM;
+               }
+
+               if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) {
+                       dev_dbg(&dev->pdev->dev, "message overflow. size %d len %d idx %ld\n",
+                               cb->response_buffer.size,
+                               mei_hdr->length, cb->buf_idx);
+                       buffer = krealloc(cb->response_buffer.data,
+                                         mei_hdr->length + cb->buf_idx,
+                                         GFP_KERNEL);
+
+                       if (!buffer) {
+                               dev_err(&dev->pdev->dev, "allocation failed.\n");
+                               list_del(&cb->list);
                                return -ENOMEM;
                        }
-                       if (buffer)
-                               mei_read_slots(dev, buffer, mei_hdr->length);
-
-                       cb_pos->buf_idx += mei_hdr->length;
-                       if (mei_hdr->msg_complete) {
-                               cl->status = 0;
-                               list_del(&cb_pos->list);
-                               dev_dbg(&dev->pdev->dev,
-                                       "completed read H cl = %d, ME cl = %d, length = %lu\n",
-                                       cl->host_client_id,
-                                       cl->me_client_id,
-                                       cb_pos->buf_idx);
-
-                               list_add_tail(&cb_pos->list,
-                                               &complete_list->list);
-                       }
-
-                       break;
+                       cb->response_buffer.data = buffer;
+                       cb->response_buffer.size =
+                               mei_hdr->length + cb->buf_idx;
                }
 
+               buffer = cb->response_buffer.data + cb->buf_idx;
+               mei_read_slots(dev, buffer, mei_hdr->length);
+
+               cb->buf_idx += mei_hdr->length;
+               if (mei_hdr->msg_complete) {
+                       cl->status = 0;
+                       list_del(&cb->list);
+                       dev_dbg(&dev->pdev->dev, "completed read H cl = %d, ME cl = %d, length = %lu\n",
+                               cl->host_client_id,
+                               cl->me_client_id,
+                               cb->buf_idx);
+                       list_add_tail(&cb->list, &complete_list->list);
+               }
+               break;
        }
 
-quit:
        dev_dbg(&dev->pdev->dev, "message read\n");
        if (!buffer) {
                mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
@@ -153,25 +204,27 @@ static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
                                struct mei_cl *cl,
                                struct mei_cl_cb *cmpl_list)
 {
-       if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) +
-                       sizeof(struct hbm_client_connect_request)))
-               return -EBADMSG;
+       u32 msg_slots =
+               mei_data2slots(sizeof(struct hbm_client_connect_request));
 
-       *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request));
+       if (*slots < msg_slots)
+               return -EMSGSIZE;
+
+       *slots -= msg_slots;
 
        if (mei_hbm_cl_disconnect_req(dev, cl)) {
                cl->status = 0;
                cb_pos->buf_idx = 0;
                list_move_tail(&cb_pos->list, &cmpl_list->list);
-               return -EMSGSIZE;
-       } else {
-               cl->state = MEI_FILE_DISCONNECTING;
-               cl->status = 0;
-               cb_pos->buf_idx = 0;
-               list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list);
-               cl->timer_count = MEI_CONNECT_TIMEOUT;
+               return -EIO;
        }
 
+       cl->state = MEI_FILE_DISCONNECTING;
+       cl->status = 0;
+       cb_pos->buf_idx = 0;
+       list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list);
+       cl->timer_count = MEI_CONNECT_TIMEOUT;
+
        return 0;
 }
 
@@ -192,14 +245,15 @@ static int _mei_irq_thread_read(struct mei_device *dev,   s32 *slots,
                        struct mei_cl *cl,
                        struct mei_cl_cb *cmpl_list)
 {
-       if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) +
-                       sizeof(struct hbm_flow_control))) {
+       u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
+
+       if (*slots < msg_slots) {
                /* return the cancel routine */
                list_del(&cb_pos->list);
-               return -EBADMSG;
+               return -EMSGSIZE;
        }
 
-       *slots -= mei_data2slots(sizeof(struct hbm_flow_control));
+       *slots -= msg_slots;
 
        if (mei_hbm_cl_flow_control_req(dev, cl)) {
                cl->status = -ENODEV;
@@ -229,15 +283,19 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
                        struct mei_cl *cl,
                        struct mei_cl_cb *cmpl_list)
 {
-       if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) +
-                       sizeof(struct hbm_client_connect_request))) {
+       u32 msg_slots =
+               mei_data2slots(sizeof(struct hbm_client_connect_request));
+
+       if (*slots < msg_slots) {
                /* return the cancel routine */
                list_del(&cb_pos->list);
-               return -EBADMSG;
+               return -EMSGSIZE;
        }
 
+       *slots -=  msg_slots;
+
        cl->state = MEI_FILE_CONNECTING;
-       *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request));
+
        if (mei_hbm_cl_connect_req(dev, cl)) {
                cl->status = -ENODEV;
                cb_pos->buf_idx = 0;
@@ -266,7 +324,7 @@ static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots,
        struct mei_msg_hdr mei_hdr;
        struct mei_cl *cl = cb->cl;
        size_t len = cb->request_buffer.size - cb->buf_idx;
-       size_t msg_slots = mei_data2slots(len);
+       u32 msg_slots = mei_data2slots(len);
 
        mei_hdr.host_addr = cl->host_client_id;
        mei_hdr.me_addr = cl->me_client_id;
@@ -298,13 +356,14 @@ static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots,
                return -ENODEV;
        }
 
-       if (mei_cl_flow_ctrl_reduce(cl))
-               return -ENODEV;
 
        cl->status = 0;
        cb->buf_idx += mei_hdr.length;
-       if (mei_hdr.msg_complete)
+       if (mei_hdr.msg_complete) {
+               if (mei_cl_flow_ctrl_reduce(cl))
+                       return -ENODEV;
                list_move_tail(&cb->list, &dev->write_waiting_list.list);
+       }
 
        return 0;
 }
@@ -350,8 +409,7 @@ int mei_irq_read_handler(struct mei_device *dev,
                                        " client = %d, ME client = %d\n",
                                        cl_pos->host_client_id,
                                        cl_pos->me_client_id);
-                       if (cl_pos->host_client_id == mei_hdr->host_addr &&
-                           cl_pos->me_client_id == mei_hdr->me_addr)
+                       if (mei_cl_hbm_equal(cl_pos, mei_hdr))
                                break;
                }
 
@@ -362,7 +420,7 @@ int mei_irq_read_handler(struct mei_device *dev,
                }
        }
        if (((*slots) * sizeof(u32)) < mei_hdr->length) {
-               dev_dbg(&dev->pdev->dev,
+               dev_err(&dev->pdev->dev,
                                "we can't read the message slots =%08x.\n",
                                *slots);
                /* we can't read the message */
@@ -378,20 +436,19 @@ int mei_irq_read_handler(struct mei_device *dev,
        } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
                   (MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
                   (dev->iamthif_state == MEI_IAMTHIF_READING)) {
-               dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
 
+               dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
                dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
 
-               ret = mei_amthif_irq_read_message(cmpl_list, dev, mei_hdr);
+               ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list);
                if (ret)
                        goto end;
        } else {
-               dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n");
-               ret = mei_irq_thread_read_client_message(cmpl_list,
-                                                        dev, mei_hdr);
+               dev_dbg(&dev->pdev->dev, "call mei_cl_irq_read_msg.\n");
+               dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
+               ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list);
                if (ret)
                        goto end;
-
        }
 
        /* reset the number of slots and header */
@@ -400,7 +457,7 @@ int mei_irq_read_handler(struct mei_device *dev,
 
        if (*slots == -EOVERFLOW) {
                /* overflow - reset */
-               dev_dbg(&dev->pdev->dev, "resetting due to slots overflow.\n");
+               dev_err(&dev->pdev->dev, "resetting due to slots overflow.\n");
                /* set the event since message has been read */
                ret = -ERANGE;
                goto end;
@@ -408,6 +465,7 @@ int mei_irq_read_handler(struct mei_device *dev,
 end:
        return ret;
 }
+EXPORT_SYMBOL_GPL(mei_irq_read_handler);
 
 
 /**
@@ -419,8 +477,7 @@ end:
  *
  * returns 0 on success, <0 on failure.
  */
-int mei_irq_write_handler(struct mei_device *dev,
-                               struct mei_cl_cb *cmpl_list)
+int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
 {
 
        struct mei_cl *cl;
@@ -559,6 +616,7 @@ int mei_irq_write_handler(struct mei_device *dev,
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(mei_irq_write_handler);
 
 
 
@@ -586,8 +644,8 @@ void mei_timer(struct work_struct *work)
                if (dev->dev_state == MEI_DEV_INIT_CLIENTS) {
                        if (dev->init_clients_timer) {
                                if (--dev->init_clients_timer == 0) {
-                                       dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
-                                               dev->init_clients_state);
+                                       dev_err(&dev->pdev->dev, "reset: init clients timeout hbm_state = %d.\n",
+                                               dev->hbm_state);
                                        mei_reset(dev, 1);
                                }
                        }
@@ -598,7 +656,7 @@ void mei_timer(struct work_struct *work)
        list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
                if (cl_pos->timer_count) {
                        if (--cl_pos->timer_count == 0) {
-                               dev_dbg(&dev->pdev->dev, "HECI reset due to connect/disconnect timeout.\n");
+                               dev_err(&dev->pdev->dev, "reset: connect/disconnect timeout.\n");
                                mei_reset(dev, 1);
                                goto out;
                        }
@@ -607,7 +665,7 @@ void mei_timer(struct work_struct *work)
 
        if (dev->iamthif_stall_timer) {
                if (--dev->iamthif_stall_timer == 0) {
-                       dev_dbg(&dev->pdev->dev, "resetting because of hang to amthi.\n");
+                       dev_err(&dev->pdev->dev, "reset: amthif  hanged.\n");
                        mei_reset(dev, 1);
                        dev->iamthif_msg_buf_size = 0;
                        dev->iamthif_msg_buf_index = 0;
index 903f809..7c44c8d 100644 (file)
@@ -48,7 +48,7 @@
  *
  * @inode: pointer to inode structure
  * @file: pointer to file structure
- *
+ e
  * returns 0 on success, <0 on error
  */
 static int mei_open(struct inode *inode, struct file *file)
@@ -244,7 +244,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
                goto out;
        }
 
-       err = mei_cl_read_start(cl);
+       err = mei_cl_read_start(cl, length);
        if (err && err != -EBUSY) {
                dev_dbg(&dev->pdev->dev,
                        "mei start read failure with status = %d\n", err);
@@ -292,9 +292,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
        }
        /* now copy the data to user space */
 copy_buffer:
-       dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n",
-           cb->response_buffer.size);
-       dev_dbg(&dev->pdev->dev, "cb->buf_idx - %lu\n", cb->buf_idx);
+       dev_dbg(&dev->pdev->dev, "buf.size = %d buf.idx= %ld\n",
+           cb->response_buffer.size, cb->buf_idx);
        if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) {
                rets = -EMSGSIZE;
                goto free;
@@ -342,11 +341,10 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 {
        struct mei_cl *cl = file->private_data;
        struct mei_cl_cb *write_cb = NULL;
-       struct mei_msg_hdr mei_hdr;
        struct mei_device *dev;
        unsigned long timeout = 0;
        int rets;
-       int i;
+       int id;
 
        if (WARN_ON(!cl || !cl->dev))
                return -ENODEV;
@@ -357,24 +355,24 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 
        if (dev->dev_state != MEI_DEV_ENABLED) {
                rets = -ENODEV;
-               goto err;
+               goto out;
        }
 
-       i = mei_me_cl_by_id(dev, cl->me_client_id);
-       if (i < 0) {
+       id = mei_me_cl_by_id(dev, cl->me_client_id);
+       if (id < 0) {
                rets = -ENODEV;
-               goto err;
+               goto out;
        }
-       if (length > dev->me_clients[i].props.max_msg_length || length <= 0) {
+       if (length > dev->me_clients[id].props.max_msg_length || length <= 0) {
                rets = -EMSGSIZE;
-               goto err;
+               goto out;
        }
 
        if (cl->state != MEI_FILE_CONNECTED) {
-               rets = -ENODEV;
                dev_err(&dev->pdev->dev, "host client = %d,  is not connected to ME client = %d",
                        cl->host_client_id, cl->me_client_id);
-               goto err;
+               rets = -ENODEV;
+               goto out;
        }
        if (cl == &dev->iamthif_cl) {
                write_cb = mei_amthif_find_read_list_entry(dev, file);
@@ -412,17 +410,15 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
        if (!write_cb) {
                dev_err(&dev->pdev->dev, "write cb allocation failed\n");
                rets = -ENOMEM;
-               goto err;
+               goto out;
        }
        rets = mei_io_cb_alloc_req_buf(write_cb, length);
        if (rets)
-               goto err;
-
-       dev_dbg(&dev->pdev->dev, "cb request size = %zd\n", length);
+               goto out;
 
        rets = copy_from_user(write_cb->request_buffer.data, ubuf, length);
        if (rets)
-               goto err;
+               goto out;
 
        cl->sm_state = 0;
        if (length == 4 &&
@@ -440,65 +436,17 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
                if (rets) {
                        dev_err(&dev->pdev->dev,
                                "amthif write failed with status = %d\n", rets);
-                       goto err;
+                       goto out;
                }
                mutex_unlock(&dev->device_lock);
                return length;
        }
 
-       write_cb->fop_type = MEI_FOP_WRITE;
-
-       dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n",
-           cl->host_client_id, cl->me_client_id);
-       rets = mei_cl_flow_ctrl_creds(cl);
-       if (rets < 0)
-               goto err;
-
-       if (rets == 0 || !dev->hbuf_is_ready) {
-               write_cb->buf_idx = 0;
-               mei_hdr.msg_complete = 0;
-               cl->writing_state = MEI_WRITING;
-               goto out;
-       }
-
-       dev->hbuf_is_ready = false;
-       if (length >  mei_hbuf_max_len(dev)) {
-               mei_hdr.length = mei_hbuf_max_len(dev);
-               mei_hdr.msg_complete = 0;
-       } else {
-               mei_hdr.length = length;
-               mei_hdr.msg_complete = 1;
-       }
-       mei_hdr.host_addr = cl->host_client_id;
-       mei_hdr.me_addr = cl->me_client_id;
-       mei_hdr.reserved = 0;
-
-       dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n",
-               MEI_HDR_PRM(&mei_hdr));
-       if (mei_write_message(dev, &mei_hdr, write_cb->request_buffer.data)) {
-               rets = -ENODEV;
-               goto err;
-       }
-       cl->writing_state = MEI_WRITING;
-       write_cb->buf_idx = mei_hdr.length;
-
+       rets = mei_cl_write(cl, write_cb, false);
 out:
-       if (mei_hdr.msg_complete) {
-               if (mei_cl_flow_ctrl_reduce(cl)) {
-                       rets = -ENODEV;
-                       goto err;
-               }
-               list_add_tail(&write_cb->list, &dev->write_waiting_list.list);
-       } else {
-               list_add_tail(&write_cb->list, &dev->write_list.list);
-       }
-
        mutex_unlock(&dev->device_lock);
-       return length;
-
-err:
-       mutex_unlock(&dev->device_lock);
-       mei_io_cb_free(write_cb);
+       if (rets < 0)
+               mei_io_cb_free(write_cb);
        return rets;
 }
 
@@ -753,17 +701,44 @@ static struct miscdevice  mei_misc_device = {
                .minor = MISC_DYNAMIC_MINOR,
 };
 
-int mei_register(struct device *dev)
+
+int mei_register(struct mei_device *dev)
 {
-       mei_misc_device.parent = dev;
-       return misc_register(&mei_misc_device);
+       int ret;
+       mei_misc_device.parent = &dev->pdev->dev;
+       ret = misc_register(&mei_misc_device);
+       if (ret)
+               return ret;
+
+       if (mei_dbgfs_register(dev, mei_misc_device.name))
+               dev_err(&dev->pdev->dev, "cannot register debugfs\n");
+
+       return 0;
 }
+EXPORT_SYMBOL_GPL(mei_register);
 
-void mei_deregister(void)
+void mei_deregister(struct mei_device *dev)
 {
+       mei_dbgfs_deregister(dev);
        misc_deregister(&mei_misc_device);
        mei_misc_device.parent = NULL;
 }
+EXPORT_SYMBOL_GPL(mei_deregister);
+
+static int __init mei_init(void)
+{
+       return mei_cl_bus_init();
+}
+
+static void __exit mei_exit(void)
+{
+       mei_cl_bus_exit();
+}
+
+module_init(mei_init);
+module_exit(mei_exit);
 
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
 MODULE_LICENSE("GPL v2");
 
index 9787381..4de5140 100644 (file)
 #include <linux/watchdog.h>
 #include <linux/poll.h>
 #include <linux/mei.h>
+#include <linux/mei_cl_bus.h>
 
 #include "hw.h"
 #include "hw-me-regs.h"
+#include "hbm.h"
 
 /*
  * watch dog definition
@@ -95,22 +97,14 @@ enum mei_dev_state {
        MEI_DEV_INITIALIZING = 0,
        MEI_DEV_INIT_CLIENTS,
        MEI_DEV_ENABLED,
-       MEI_DEV_RESETING,
+       MEI_DEV_RESETTING,
        MEI_DEV_DISABLED,
-       MEI_DEV_RECOVERING_FROM_RESET,
        MEI_DEV_POWER_DOWN,
        MEI_DEV_POWER_UP
 };
 
 const char *mei_dev_state_str(int state);
 
-/* init clients states*/
-enum mei_init_clients_states {
-       MEI_START_MESSAGE = 0,
-       MEI_ENUM_CLIENTS_MESSAGE,
-       MEI_CLIENT_PROPERTIES_MESSAGE
-};
-
 enum iamthif_states {
        MEI_IAMTHIF_IDLE,
        MEI_IAMTHIF_WRITING,
@@ -153,7 +147,7 @@ enum mei_cb_file_ops {
 /*
  * Intel MEI message data struct
  */
-struct mei_message_data {
+struct mei_msg_data {
        u32 size;
        unsigned char *data;
 };
@@ -184,8 +178,8 @@ struct mei_cl_cb {
        struct list_head list;
        struct mei_cl *cl;
        enum mei_cb_file_ops fop_type;
-       struct mei_message_data request_buffer;
-       struct mei_message_data response_buffer;
+       struct mei_msg_data request_buffer;
+       struct mei_msg_data response_buffer;
        unsigned long buf_idx;
        unsigned long read_time;
        struct file *file_object;
@@ -209,15 +203,20 @@ struct mei_cl {
        enum mei_file_transaction_states writing_state;
        int sm_state;
        struct mei_cl_cb *read_cb;
+
+       /* MEI CL bus data */
+       struct mei_cl_device *device;
+       struct list_head device_link;
+       uuid_le device_uuid;
 };
 
 /** struct mei_hw_ops
  *
- * @host_set_ready   - notify FW that host side is ready
  * @host_is_ready    - query for host readiness
 
  * @hw_is_ready      - query if hw is ready
  * @hw_reset         - reset hw
+ * @hw_start         - start hw after reset
  * @hw_config        - configure hw
 
  * @intr_clear       - clear pending interrupts
@@ -237,11 +236,11 @@ struct mei_cl {
  */
 struct mei_hw_ops {
 
-       void (*host_set_ready) (struct mei_device *dev);
        bool (*host_is_ready) (struct mei_device *dev);
 
        bool (*hw_is_ready) (struct mei_device *dev);
        void (*hw_reset) (struct mei_device *dev, bool enable);
+       int  (*hw_start) (struct mei_device *dev);
        void (*hw_config) (struct mei_device *dev);
 
        void (*intr_clear) (struct mei_device *dev);
@@ -263,9 +262,77 @@ struct mei_hw_ops {
                     unsigned char *buf, unsigned long len);
 };
 
+/* MEI bus API*/
+
+/**
+ * struct mei_cl_ops - MEI CL device ops
+ * This structure allows ME host clients to implement technology
+ * specific operations.
+ *
+ * @enable: Enable an MEI CL device. Some devices require specific
+ *     HECI commands to initialize completely.
+ * @disable: Disable an MEI CL device.
+ * @send: Tx hook for the device. This allows ME host clients to trap
+ *     the device driver buffers before actually physically
+ *     pushing it to the ME.
+ * @recv: Rx hook for the device. This allows ME host clients to trap the
+ *     ME buffers before forwarding them to the device driver.
+ */
+struct mei_cl_ops {
+       int (*enable)(struct mei_cl_device *device);
+       int (*disable)(struct mei_cl_device *device);
+       int (*send)(struct mei_cl_device *device, u8 *buf, size_t length);
+       int (*recv)(struct mei_cl_device *device, u8 *buf, size_t length);
+};
+
+struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
+                                       uuid_le uuid, char *name,
+                                       struct mei_cl_ops *ops);
+void mei_cl_remove_device(struct mei_cl_device *device);
+
+int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
+int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
+int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
+void mei_cl_bus_rx_event(struct mei_cl *cl);
+int mei_cl_bus_init(void);
+void mei_cl_bus_exit(void);
+
+
+/**
+ * struct mei_cl_device - MEI device handle
+ * An mei_cl_device pointer is returned from mei_add_device()
+ * and links MEI bus clients to their actual ME host client pointer.
+ * Drivers for MEI devices will get an mei_cl_device pointer
+ * when being probed and shall use it for doing ME bus I/O.
+ *
+ * @dev: linux driver model device pointer
+ * @uuid: me client uuid
+ * @cl: mei client
+ * @ops: ME transport ops
+ * @event_cb: Drivers register this callback to get asynchronous ME
+ *     events (e.g. Rx buffer pending) notifications.
+ * @events: Events bitmask sent to the driver.
+ * @priv_data: client private data
+ */
+struct mei_cl_device {
+       struct device dev;
+
+       struct mei_cl *cl;
+
+       const struct mei_cl_ops *ops;
+
+       struct work_struct event_work;
+       mei_cl_event_cb_t event_cb;
+       void *event_context;
+       unsigned long events;
+
+       void *priv_data;
+};
+
 /**
  * struct mei_device -  MEI private device struct
 
+ * @hbm_state - state of host bus message protocol
  * @mem_addr - mem mapped base register address
 
  * @hbuf_depth - depth of hardware host/write buffer is slots
@@ -296,11 +363,12 @@ struct mei_device {
         */
        struct mutex device_lock; /* device lock */
        struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */
-       bool recvd_msg;
 
+       bool recvd_hw_ready;
        /*
         * waiting queue for receive message from FW
         */
+       wait_queue_head_t wait_hw_ready;
        wait_queue_head_t wait_recvd_msg;
        wait_queue_head_t wait_stop_wd;
 
@@ -308,7 +376,7 @@ struct mei_device {
         * mei device  states
         */
        enum mei_dev_state dev_state;
-       enum mei_init_clients_states init_clients_state;
+       enum mei_hbm_state hbm_state;
        u16 init_clients_timer;
 
        unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE];  /* control messages */
@@ -365,6 +433,14 @@ struct mei_device {
 
        struct work_struct init_work;
 
+       /* List of bus devices */
+       struct list_head device_list;
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+       struct dentry *dbgfs_dir;
+#endif /* CONFIG_DEBUG_FS */
+
+
        const struct mei_hw_ops *ops;
        char hw[0] __aligned(sizeof(void *));
 };
@@ -374,13 +450,23 @@ static inline unsigned long mei_secs_to_jiffies(unsigned long sec)
        return msecs_to_jiffies(sec * MSEC_PER_SEC);
 }
 
+/**
+ * mei_data2slots - get slots - number of (dwords) from a message length
+ *     + size of the mei header
+ * @length - size of the messages in bytes
+ * returns  - number of slots
+ */
+static inline u32 mei_data2slots(size_t length)
+{
+       return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4);
+}
 
 /*
  * mei init function prototypes
  */
 void mei_device_init(struct mei_device *dev);
 void mei_reset(struct mei_device *dev, int interrupts);
-int mei_hw_init(struct mei_device *dev);
+int mei_start(struct mei_device *dev);
 void mei_stop(struct mei_device *dev);
 
 /*
@@ -392,8 +478,7 @@ int mei_irq_read_handler(struct mei_device *dev,
                struct mei_cl_cb *cmpl_list, s32 *slots);
 
 int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list);
-
-void mei_irq_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb_pos);
+void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list);
 
 /*
  * AMTHIF - AMT Host Interface Functions
@@ -417,6 +502,25 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
 
 void mei_amthif_run_next_cmd(struct mei_device *dev);
 
+int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
+                       struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list);
+
+void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb);
+int mei_amthif_irq_read_msg(struct mei_device *dev,
+                           struct mei_msg_hdr *mei_hdr,
+                           struct mei_cl_cb *complete_list);
+int mei_amthif_irq_read(struct mei_device *dev, s32 *slots);
+
+/*
+ * NFC functions
+ */
+int mei_nfc_host_init(struct mei_device *dev);
+void mei_nfc_host_exit(void);
+
+/*
+ * NFC Client UUID
+ */
+extern const uuid_le mei_nfc_guid;
 
 int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
                        struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list);
@@ -455,6 +559,11 @@ static inline void mei_hw_reset(struct mei_device *dev, bool enable)
        dev->ops->hw_reset(dev, enable);
 }
 
+static inline void mei_hw_start(struct mei_device *dev)
+{
+       dev->ops->hw_start(dev);
+}
+
 static inline void mei_clear_interrupts(struct mei_device *dev)
 {
        dev->ops->intr_clear(dev);
@@ -470,10 +579,6 @@ static inline void mei_disable_interrupts(struct mei_device *dev)
        dev->ops->intr_disable(dev);
 }
 
-static inline void mei_host_set_ready(struct mei_device *dev)
-{
-       dev->ops->host_set_ready(dev);
-}
 static inline bool mei_host_is_ready(struct mei_device *dev)
 {
        return dev->ops->host_is_ready(dev);
@@ -521,8 +626,19 @@ static inline int mei_count_full_read_slots(struct mei_device *dev)
        return dev->ops->rdbuf_full_slots(dev);
 }
 
-int mei_register(struct device *dev);
-void mei_deregister(void);
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+int mei_dbgfs_register(struct mei_device *dev, const char *name);
+void mei_dbgfs_deregister(struct mei_device *dev);
+#else
+static inline int mei_dbgfs_register(struct mei_device *dev, const char *name)
+{
+       return 0;
+}
+static inline void mei_dbgfs_deregister(struct mei_device *dev) {}
+#endif /* CONFIG_DEBUG_FS */
+
+int mei_register(struct mei_device *dev);
+void mei_deregister(struct mei_device *dev);
 
 #define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d comp=%1d"
 #define MEI_HDR_PRM(hdr)                  \
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
new file mode 100644 (file)
index 0000000..3adf8a7
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/mei_cl_bus.h>
+
+#include "mei_dev.h"
+#include "client.h"
+
+struct mei_nfc_cmd {
+       u8 command;
+       u8 status;
+       u16 req_id;
+       u32 reserved;
+       u16 data_size;
+       u8 sub_command;
+       u8 data[];
+} __packed;
+
+struct mei_nfc_reply {
+       u8 command;
+       u8 status;
+       u16 req_id;
+       u32 reserved;
+       u16 data_size;
+       u8 sub_command;
+       u8 reply_status;
+       u8 data[];
+} __packed;
+
+struct mei_nfc_if_version {
+       u8 radio_version_sw[3];
+       u8 reserved[3];
+       u8 radio_version_hw[3];
+       u8 i2c_addr;
+       u8 fw_ivn;
+       u8 vendor_id;
+       u8 radio_type;
+} __packed;
+
+struct mei_nfc_connect {
+       u8 fw_ivn;
+       u8 vendor_id;
+} __packed;
+
+struct mei_nfc_connect_resp {
+       u8 fw_ivn;
+       u8 vendor_id;
+       u16 me_major;
+       u16 me_minor;
+       u16 me_hotfix;
+       u16 me_build;
+} __packed;
+
+struct mei_nfc_hci_hdr {
+       u8 cmd;
+       u8 status;
+       u16 req_id;
+       u32 reserved;
+       u16 data_size;
+} __packed;
+
+#define MEI_NFC_CMD_MAINTENANCE 0x00
+#define MEI_NFC_CMD_HCI_SEND 0x01
+#define MEI_NFC_CMD_HCI_RECV 0x02
+
+#define MEI_NFC_SUBCMD_CONNECT    0x00
+#define MEI_NFC_SUBCMD_IF_VERSION 0x01
+
+#define MEI_NFC_HEADER_SIZE 10
+
+/** mei_nfc_dev - NFC mei device
+ *
+ * @cl: NFC host client
+ * @cl_info: NFC info host client
+ * @init_work: perform connection to the info client
+ * @fw_ivn: NFC Intervace Version Number
+ * @vendor_id: NFC manufacturer ID
+ * @radio_type: NFC radio type
+ */
+struct mei_nfc_dev {
+       struct mei_cl *cl;
+       struct mei_cl *cl_info;
+       struct work_struct init_work;
+       wait_queue_head_t send_wq;
+       u8 fw_ivn;
+       u8 vendor_id;
+       u8 radio_type;
+       char *bus_name;
+
+       u16 req_id;
+       u16 recv_req_id;
+};
+
+static struct mei_nfc_dev nfc_dev;
+
+/* UUIDs for NFC F/W clients */
+const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50,
+                                    0x94, 0xd4, 0x50, 0x26,
+                                    0x67, 0x23, 0x77, 0x5c);
+
+static const uuid_le mei_nfc_info_guid = UUID_LE(0xd2de1625, 0x382d, 0x417d,
+                                       0x48, 0xa4, 0xef, 0xab,
+                                       0xba, 0x8a, 0x12, 0x06);
+
+/* Vendors */
+#define MEI_NFC_VENDOR_INSIDE 0x00
+#define MEI_NFC_VENDOR_NXP    0x01
+
+/* Radio types */
+#define MEI_NFC_VENDOR_INSIDE_UREAD 0x00
+#define MEI_NFC_VENDOR_NXP_PN544    0x01
+
+static void mei_nfc_free(struct mei_nfc_dev *ndev)
+{
+       if (ndev->cl) {
+               list_del(&ndev->cl->device_link);
+               mei_cl_unlink(ndev->cl);
+               kfree(ndev->cl);
+       }
+
+       if (ndev->cl_info) {
+               list_del(&ndev->cl_info->device_link);
+               mei_cl_unlink(ndev->cl_info);
+               kfree(ndev->cl_info);
+       }
+}
+
+static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev)
+{
+       struct mei_device *dev;
+
+       if (!ndev->cl)
+               return -ENODEV;
+
+       dev = ndev->cl->dev;
+
+       switch (ndev->vendor_id) {
+       case MEI_NFC_VENDOR_INSIDE:
+               switch (ndev->radio_type) {
+               case MEI_NFC_VENDOR_INSIDE_UREAD:
+                       ndev->bus_name = "microread";
+                       return 0;
+
+               default:
+                       dev_err(&dev->pdev->dev, "Unknow radio type 0x%x\n",
+                               ndev->radio_type);
+
+                       return -EINVAL;
+               }
+
+       case MEI_NFC_VENDOR_NXP:
+               switch (ndev->radio_type) {
+               case MEI_NFC_VENDOR_NXP_PN544:
+                       ndev->bus_name = "pn544";
+                       return 0;
+               default:
+                       dev_err(&dev->pdev->dev, "Unknow radio type 0x%x\n",
+                               ndev->radio_type);
+
+                       return -EINVAL;
+               }
+
+       default:
+               dev_err(&dev->pdev->dev, "Unknow vendor ID 0x%x\n",
+                       ndev->vendor_id);
+
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int mei_nfc_connect(struct mei_nfc_dev *ndev)
+{
+       struct mei_device *dev;
+       struct mei_cl *cl;
+       struct mei_nfc_cmd *cmd, *reply;
+       struct mei_nfc_connect *connect;
+       struct mei_nfc_connect_resp *connect_resp;
+       size_t connect_length, connect_resp_length;
+       int bytes_recv, ret;
+
+       cl = ndev->cl;
+       dev = cl->dev;
+
+       connect_length = sizeof(struct mei_nfc_cmd) +
+                       sizeof(struct mei_nfc_connect);
+
+       connect_resp_length = sizeof(struct mei_nfc_cmd) +
+                       sizeof(struct mei_nfc_connect_resp);
+
+       cmd = kzalloc(connect_length, GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+       connect = (struct mei_nfc_connect *)cmd->data;
+
+       reply = kzalloc(connect_resp_length, GFP_KERNEL);
+       if (!reply) {
+               kfree(cmd);
+               return -ENOMEM;
+       }
+
+       connect_resp = (struct mei_nfc_connect_resp *)reply->data;
+
+       cmd->command = MEI_NFC_CMD_MAINTENANCE;
+       cmd->data_size = 3;
+       cmd->sub_command = MEI_NFC_SUBCMD_CONNECT;
+       connect->fw_ivn = ndev->fw_ivn;
+       connect->vendor_id = ndev->vendor_id;
+
+       ret = __mei_cl_send(cl, (u8 *)cmd, connect_length);
+       if (ret < 0) {
+               dev_err(&dev->pdev->dev, "Could not send connect cmd\n");
+               goto err;
+       }
+
+       bytes_recv = __mei_cl_recv(cl, (u8 *)reply, connect_resp_length);
+       if (bytes_recv < 0) {
+               dev_err(&dev->pdev->dev, "Could not read connect response\n");
+               ret = bytes_recv;
+               goto err;
+       }
+
+       dev_info(&dev->pdev->dev, "IVN 0x%x Vendor ID 0x%x\n",
+                connect_resp->fw_ivn, connect_resp->vendor_id);
+
+       dev_info(&dev->pdev->dev, "ME FW %d.%d.%d.%d\n",
+               connect_resp->me_major, connect_resp->me_minor,
+               connect_resp->me_hotfix, connect_resp->me_build);
+
+       ret = 0;
+
+err:
+       kfree(reply);
+       kfree(cmd);
+
+       return ret;
+}
+
+static int mei_nfc_if_version(struct mei_nfc_dev *ndev)
+{
+       struct mei_device *dev;
+       struct mei_cl *cl;
+
+       struct mei_nfc_cmd cmd;
+       struct mei_nfc_reply *reply = NULL;
+       struct mei_nfc_if_version *version;
+       size_t if_version_length;
+       int bytes_recv, ret;
+
+       cl = ndev->cl_info;
+       dev = cl->dev;
+
+       memset(&cmd, 0, sizeof(struct mei_nfc_cmd));
+       cmd.command = MEI_NFC_CMD_MAINTENANCE;
+       cmd.data_size = 1;
+       cmd.sub_command = MEI_NFC_SUBCMD_IF_VERSION;
+
+       ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd));
+       if (ret < 0) {
+               dev_err(&dev->pdev->dev, "Could not send IF version cmd\n");
+               return ret;
+       }
+
+       /* to be sure on the stack we alloc memory */
+       if_version_length = sizeof(struct mei_nfc_reply) +
+               sizeof(struct mei_nfc_if_version);
+
+       reply = kzalloc(if_version_length, GFP_KERNEL);
+       if (!reply)
+               return -ENOMEM;
+
+       bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length);
+       if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) {
+               dev_err(&dev->pdev->dev, "Could not read IF version\n");
+               ret = -EIO;
+               goto err;
+       }
+
+       version = (struct mei_nfc_if_version *)reply->data;
+
+       ndev->fw_ivn = version->fw_ivn;
+       ndev->vendor_id = version->vendor_id;
+       ndev->radio_type = version->radio_type;
+
+err:
+       kfree(reply);
+       return ret;
+}
+
+static int mei_nfc_enable(struct mei_cl_device *cldev)
+{
+       struct mei_device *dev;
+       struct mei_nfc_dev *ndev = &nfc_dev;
+       int ret;
+
+       dev = ndev->cl->dev;
+
+       ret = mei_nfc_connect(ndev);
+       if (ret < 0) {
+               dev_err(&dev->pdev->dev, "Could not connect to NFC");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int mei_nfc_disable(struct mei_cl_device *cldev)
+{
+       return 0;
+}
+
+static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
+{
+       struct mei_device *dev;
+       struct mei_nfc_dev *ndev;
+       struct mei_nfc_hci_hdr *hdr;
+       u8 *mei_buf;
+       int err;
+
+       ndev = (struct mei_nfc_dev *) cldev->priv_data;
+       dev = ndev->cl->dev;
+
+       mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL);
+       if (!mei_buf)
+               return -ENOMEM;
+
+       hdr = (struct mei_nfc_hci_hdr *) mei_buf;
+       hdr->cmd = MEI_NFC_CMD_HCI_SEND;
+       hdr->status = 0;
+       hdr->req_id = ndev->req_id;
+       hdr->reserved = 0;
+       hdr->data_size = length;
+
+       memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length);
+
+       err = __mei_cl_send(ndev->cl, mei_buf, length + MEI_NFC_HEADER_SIZE);
+       if (err < 0)
+               return err;
+
+       kfree(mei_buf);
+
+       if (!wait_event_interruptible_timeout(ndev->send_wq,
+                               ndev->recv_req_id == ndev->req_id, HZ)) {
+               dev_err(&dev->pdev->dev, "NFC MEI command timeout\n");
+               err = -ETIMEDOUT;
+       } else {
+               ndev->req_id++;
+       }
+
+       return err;
+}
+
+static int mei_nfc_recv(struct mei_cl_device *cldev, u8 *buf, size_t length)
+{
+       struct mei_nfc_dev *ndev;
+       struct mei_nfc_hci_hdr *hci_hdr;
+       int received_length;
+
+       ndev = (struct mei_nfc_dev *)cldev->priv_data;
+
+       received_length = __mei_cl_recv(ndev->cl, buf, length);
+       if (received_length < 0)
+               return received_length;
+
+       hci_hdr = (struct mei_nfc_hci_hdr *) buf;
+
+       if (hci_hdr->cmd == MEI_NFC_CMD_HCI_SEND) {
+               ndev->recv_req_id = hci_hdr->req_id;
+               wake_up(&ndev->send_wq);
+
+               return 0;
+       }
+
+       return received_length;
+}
+
+static struct mei_cl_ops nfc_ops = {
+       .enable = mei_nfc_enable,
+       .disable = mei_nfc_disable,
+       .send = mei_nfc_send,
+       .recv = mei_nfc_recv,
+};
+
+static void mei_nfc_init(struct work_struct *work)
+{
+       struct mei_device *dev;
+       struct mei_cl_device *cldev;
+       struct mei_nfc_dev *ndev;
+       struct mei_cl *cl_info;
+
+       ndev = container_of(work, struct mei_nfc_dev, init_work);
+
+       cl_info = ndev->cl_info;
+       dev = cl_info->dev;
+
+       mutex_lock(&dev->device_lock);
+
+       if (mei_cl_connect(cl_info, NULL) < 0) {
+               mutex_unlock(&dev->device_lock);
+               dev_err(&dev->pdev->dev,
+                       "Could not connect to the NFC INFO ME client");
+
+               goto err;
+       }
+
+       mutex_unlock(&dev->device_lock);
+
+       if (mei_nfc_if_version(ndev) < 0) {
+               dev_err(&dev->pdev->dev, "Could not get the NFC interfave version");
+
+               goto err;
+       }
+
+       dev_info(&dev->pdev->dev,
+               "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
+               ndev->fw_ivn, ndev->vendor_id, ndev->radio_type);
+
+       mutex_lock(&dev->device_lock);
+
+       if (mei_cl_disconnect(cl_info) < 0) {
+               mutex_unlock(&dev->device_lock);
+               dev_err(&dev->pdev->dev,
+                       "Could not disconnect the NFC INFO ME client");
+
+               goto err;
+       }
+
+       mutex_unlock(&dev->device_lock);
+
+       if (mei_nfc_build_bus_name(ndev) < 0) {
+               dev_err(&dev->pdev->dev,
+                       "Could not build the bus ID name\n");
+               return;
+       }
+
+       cldev = mei_cl_add_device(dev, mei_nfc_guid, ndev->bus_name, &nfc_ops);
+       if (!cldev) {
+               dev_err(&dev->pdev->dev,
+                       "Could not add the NFC device to the MEI bus\n");
+
+               goto err;
+       }
+
+       cldev->priv_data = ndev;
+
+
+       return;
+
+err:
+       mei_nfc_free(ndev);
+
+       return;
+}
+
+
+int mei_nfc_host_init(struct mei_device *dev)
+{
+       struct mei_nfc_dev *ndev = &nfc_dev;
+       struct mei_cl *cl_info, *cl = NULL;
+       int i, ret;
+
+       /* already initialzed */
+       if (ndev->cl_info)
+               return 0;
+
+       cl_info = mei_cl_allocate(dev);
+       cl = mei_cl_allocate(dev);
+
+       if (!cl || !cl_info) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       /* check for valid client id */
+       i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
+       if (i < 0) {
+               dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
+               ret = -ENOENT;
+               goto err;
+       }
+
+       cl_info->me_client_id = dev->me_clients[i].client_id;
+
+       ret = mei_cl_link(cl_info, MEI_HOST_CLIENT_ID_ANY);
+       if (ret)
+               goto err;
+
+       cl_info->device_uuid = mei_nfc_info_guid;
+
+       list_add_tail(&cl_info->device_link, &dev->device_list);
+
+       /* check for valid client id */
+       i = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
+       if (i < 0) {
+               dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
+               ret = -ENOENT;
+               goto err;
+       }
+
+       cl->me_client_id = dev->me_clients[i].client_id;
+
+       ret = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
+       if (ret)
+               goto err;
+
+       cl->device_uuid = mei_nfc_guid;
+
+       list_add_tail(&cl->device_link, &dev->device_list);
+
+       ndev->cl_info = cl_info;
+       ndev->cl = cl;
+       ndev->req_id = 1;
+
+       INIT_WORK(&ndev->init_work, mei_nfc_init);
+       init_waitqueue_head(&ndev->send_wq);
+       schedule_work(&ndev->init_work);
+
+       return 0;
+
+err:
+       mei_nfc_free(ndev);
+
+       return ret;
+}
+
+void mei_nfc_host_exit(void)
+{
+       struct mei_nfc_dev *ndev = &nfc_dev;
+
+       if (ndev->cl && ndev->cl->device)
+               mei_cl_remove_device(ndev->cl->device);
+
+       mei_nfc_free(ndev);
+}
index b8b5c9c..88aec6a 100644 (file)
@@ -47,7 +47,7 @@
 static struct pci_dev *mei_pdev;
 
 /* mei_pci_tbl - PCI Device ID Table */
-static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
+static DEFINE_PCI_DEVICE_TABLE(mei_me_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
@@ -86,7 +86,7 @@ static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
        {0, }
 };
 
-MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
+MODULE_DEVICE_TABLE(pci, mei_me_pci_tbl);
 
 static DEFINE_MUTEX(mei_mutex);
 
@@ -97,7 +97,7 @@ static DEFINE_MUTEX(mei_mutex);
  *
  * returns true if ME Interface is valid, false otherwise
  */
-static bool mei_quirk_probe(struct pci_dev *pdev,
+static bool mei_me_quirk_probe(struct pci_dev *pdev,
                                const struct pci_device_id *ent)
 {
        u32 reg;
@@ -119,7 +119,7 @@ static bool mei_quirk_probe(struct pci_dev *pdev,
  *
  * returns 0 on success, <0 on failure.
  */
-static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct mei_device *dev;
        struct mei_me_hw *hw;
@@ -127,7 +127,7 @@ static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        mutex_lock(&mei_mutex);
 
-       if (!mei_quirk_probe(pdev, ent)) {
+       if (!mei_me_quirk_probe(pdev, ent)) {
                err = -ENODEV;
                goto end;
        }
@@ -184,20 +184,19 @@ static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto disable_msi;
        }
 
-       if (mei_hw_init(dev)) {
+       if (mei_start(dev)) {
                dev_err(&pdev->dev, "init hw failure.\n");
                err = -ENODEV;
                goto release_irq;
        }
 
-       err = mei_register(&pdev->dev);
+       err = mei_register(dev);
        if (err)
                goto release_irq;
 
        mei_pdev = pdev;
        pci_set_drvdata(pdev, dev);
 
-
        schedule_delayed_work(&dev->timer_work, HZ);
 
        mutex_unlock(&mei_mutex);
@@ -233,7 +232,7 @@ end:
  * mei_remove is called by the PCI subsystem to alert the driver
  * that it should release a PCI device.
  */
-static void mei_remove(struct pci_dev *pdev)
+static void mei_me_remove(struct pci_dev *pdev)
 {
        struct mei_device *dev;
        struct mei_me_hw *hw;
@@ -253,8 +252,6 @@ static void mei_remove(struct pci_dev *pdev)
 
        mei_pdev = NULL;
 
-       mei_watchdog_unregister(dev);
-
        /* disable interrupts */
        mei_disable_interrupts(dev);
 
@@ -265,16 +262,17 @@ static void mei_remove(struct pci_dev *pdev)
        if (hw->mem_addr)
                pci_iounmap(pdev, hw->mem_addr);
 
+       mei_deregister(dev);
+
        kfree(dev);
 
        pci_release_regions(pdev);
        pci_disable_device(pdev);
 
-       mei_deregister();
 
 }
 #ifdef CONFIG_PM
-static int mei_pci_suspend(struct device *device)
+static int mei_me_pci_suspend(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
        struct mei_device *dev = pci_get_drvdata(pdev);
@@ -294,7 +292,7 @@ static int mei_pci_suspend(struct device *device)
        return 0;
 }
 
-static int mei_pci_resume(struct device *device)
+static int mei_me_pci_resume(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
        struct mei_device *dev;
@@ -334,24 +332,24 @@ static int mei_pci_resume(struct device *device)
 
        return err;
 }
-static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
-#define MEI_PM_OPS     (&mei_pm_ops)
+static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume);
+#define MEI_ME_PM_OPS  (&mei_me_pm_ops)
 #else
-#define MEI_PM_OPS     NULL
+#define MEI_ME_PM_OPS  NULL
 #endif /* CONFIG_PM */
 /*
  *  PCI driver structure
  */
-static struct pci_driver mei_driver = {
+static struct pci_driver mei_me_driver = {
        .name = KBUILD_MODNAME,
-       .id_table = mei_pci_tbl,
-       .probe = mei_probe,
-       .remove = mei_remove,
-       .shutdown = mei_remove,
-       .driver.pm = MEI_PM_OPS,
+       .id_table = mei_me_pci_tbl,
+       .probe = mei_me_probe,
+       .remove = mei_me_remove,
+       .shutdown = mei_me_remove,
+       .driver.pm = MEI_ME_PM_OPS,
 };
 
-module_pci_driver(mei_driver);
+module_pci_driver(mei_me_driver);
 
 MODULE_AUTHOR("Intel Corporation");
 MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
index 2413247..eb3f05c 100644 (file)
@@ -317,7 +317,8 @@ end:
  *
  * returns 0 if success, negative errno code for failure
  */
-static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
+static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev,
+               unsigned int timeout)
 {
        struct mei_device *dev;
 
index 1e7bc0e..1dfde4d 100644 (file)
@@ -417,24 +417,26 @@ static int tsl2550_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
-static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
+static int tsl2550_suspend(struct device *dev)
 {
-       return tsl2550_set_power_state(client, 0);
+       return tsl2550_set_power_state(to_i2c_client(dev), 0);
 }
 
-static int tsl2550_resume(struct i2c_client *client)
+static int tsl2550_resume(struct device *dev)
 {
-       return tsl2550_set_power_state(client, 1);
+       return tsl2550_set_power_state(to_i2c_client(dev), 1);
 }
 
+static SIMPLE_DEV_PM_OPS(tsl2550_pm_ops, tsl2550_suspend, tsl2550_resume);
+#define TSL2550_PM_OPS (&tsl2550_pm_ops)
+
 #else
 
-#define tsl2550_suspend                NULL
-#define tsl2550_resume         NULL
+#define TSL2550_PM_OPS NULL
 
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static const struct i2c_device_id tsl2550_id[] = {
        { "tsl2550", 0 },
@@ -446,9 +448,8 @@ static struct i2c_driver tsl2550_driver = {
        .driver = {
                .name   = TSL2550_DRV_NAME,
                .owner  = THIS_MODULE,
+               .pm     = TSL2550_PM_OPS,
        },
-       .suspend = tsl2550_suspend,
-       .resume = tsl2550_resume,
        .probe  = tsl2550_probe,
        .remove = tsl2550_remove,
        .id_table = tsl2550_id,
index 7009f17..50adbd1 100644 (file)
@@ -543,25 +543,7 @@ static struct pcmcia_driver sdricoh_driver = {
        .suspend = sdricoh_pcmcia_suspend,
        .resume = sdricoh_pcmcia_resume,
 };
-
-/*****************************************************************************\
- *                                                                           *
- * Driver init/exit                                                          *
- *                                                                           *
-\*****************************************************************************/
-
-static int __init sdricoh_drv_init(void)
-{
-       return pcmcia_register_driver(&sdricoh_driver);
-}
-
-static void __exit sdricoh_drv_exit(void)
-{
-       pcmcia_unregister_driver(&sdricoh_driver);
-}
-
-module_init(sdricoh_drv_init);
-module_exit(sdricoh_drv_exit);
+module_pcmcia_driver(sdricoh_driver);
 
 module_param(switchlocked, uint, 0444);
 
index 92ab30a..dc571eb 100644 (file)
@@ -1123,33 +1123,6 @@ static unsigned long mtdchar_get_unmapped_area(struct file *file,
 }
 #endif
 
-static inline unsigned long get_vm_size(struct vm_area_struct *vma)
-{
-       return vma->vm_end - vma->vm_start;
-}
-
-static inline resource_size_t get_vm_offset(struct vm_area_struct *vma)
-{
-       return (resource_size_t) vma->vm_pgoff << PAGE_SHIFT;
-}
-
-/*
- * Set a new vm offset.
- *
- * Verify that the incoming offset really works as a page offset,
- * and that the offset and size fit in a resource_size_t.
- */
-static inline int set_vm_offset(struct vm_area_struct *vma, resource_size_t off)
-{
-       pgoff_t pgoff = off >> PAGE_SHIFT;
-       if (off != (resource_size_t) pgoff << PAGE_SHIFT)
-               return -EINVAL;
-       if (off + get_vm_size(vma) - 1 < off)
-               return -EINVAL;
-       vma->vm_pgoff = pgoff;
-       return 0;
-}
-
 /*
  * set up a mapping for shared memory segments
  */
@@ -1159,45 +1132,17 @@ static int mtdchar_mmap(struct file *file, struct vm_area_struct *vma)
        struct mtd_file_info *mfi = file->private_data;
        struct mtd_info *mtd = mfi->mtd;
        struct map_info *map = mtd->priv;
-       resource_size_t start, off;
-       unsigned long len, vma_len;
 
         /* This is broken because it assumes the MTD device is map-based
           and that mtd->priv is a valid struct map_info.  It should be
           replaced with something that uses the mtd_get_unmapped_area()
           operation properly. */
        if (0 /*mtd->type == MTD_RAM || mtd->type == MTD_ROM*/) {
-               off = get_vm_offset(vma);
-               start = map->phys;
-               len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size);
-               start &= PAGE_MASK;
-               vma_len = get_vm_size(vma);
-
-               /* Overflow in off+len? */
-               if (vma_len + off < off)
-                       return -EINVAL;
-               /* Does it fit in the mapping? */
-               if (vma_len + off > len)
-                       return -EINVAL;
-
-               off += start;
-               /* Did that overflow? */
-               if (off < start)
-                       return -EINVAL;
-               if (set_vm_offset(vma, off) < 0)
-                       return -EINVAL;
-               vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
-
 #ifdef pgprot_noncached
-               if (file->f_flags & O_DSYNC || off >= __pa(high_memory))
+               if (file->f_flags & O_DSYNC || map->phys >= __pa(high_memory))
                        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 #endif
-               if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
-                                      vma->vm_end - vma->vm_start,
-                                      vma->vm_page_prot))
-                       return -EAGAIN;
-
-               return 0;
+               return vm_iomap_memory(vma, map->phys, map->size);
        }
        return -ENOSYS;
 #else
index 5bed4c4..74dc187 100644 (file)
@@ -333,16 +333,4 @@ static struct pcmcia_driver com20020_cs_driver = {
        .suspend        = com20020_suspend,
        .resume         = com20020_resume,
 };
-
-static int __init init_com20020_cs(void)
-{
-       return pcmcia_register_driver(&com20020_cs_driver);
-}
-
-static void __exit exit_com20020_cs(void)
-{
-       pcmcia_unregister_driver(&com20020_cs_driver);
-}
-
-module_init(init_com20020_cs);
-module_exit(exit_com20020_cs);
+module_pcmcia_driver(com20020_cs_driver);
index 07401a3..dbbea0e 100644 (file)
@@ -846,8 +846,10 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
                if (bond->dev->flags & IFF_ALLMULTI)
                        dev_set_allmulti(old_active->dev, -1);
 
+               netif_addr_lock_bh(bond->dev);
                netdev_for_each_mc_addr(ha, bond->dev)
                        dev_mc_del(old_active->dev, ha->addr);
+               netif_addr_unlock_bh(bond->dev);
        }
 
        if (new_active) {
@@ -858,8 +860,10 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
                if (bond->dev->flags & IFF_ALLMULTI)
                        dev_set_allmulti(new_active->dev, 1);
 
+               netif_addr_lock_bh(bond->dev);
                netdev_for_each_mc_addr(ha, bond->dev)
                        dev_mc_add(new_active->dev, ha->addr);
+               netif_addr_unlock_bh(bond->dev);
        }
 }
 
@@ -1901,11 +1905,29 @@ err_dest_symlinks:
        bond_destroy_slave_symlinks(bond_dev, slave_dev);
 
 err_detach:
+       if (!USES_PRIMARY(bond->params.mode)) {
+               netif_addr_lock_bh(bond_dev);
+               bond_mc_list_flush(bond_dev, slave_dev);
+               netif_addr_unlock_bh(bond_dev);
+       }
+       bond_del_vlans_from_slave(bond, slave_dev);
        write_lock_bh(&bond->lock);
        bond_detach_slave(bond, new_slave);
+       if (bond->primary_slave == new_slave)
+               bond->primary_slave = NULL;
        write_unlock_bh(&bond->lock);
+       if (bond->curr_active_slave == new_slave) {
+               read_lock(&bond->lock);
+               write_lock_bh(&bond->curr_slave_lock);
+               bond_change_active_slave(bond, NULL);
+               bond_select_active_slave(bond);
+               write_unlock_bh(&bond->curr_slave_lock);
+               read_unlock(&bond->lock);
+       }
+       slave_disable_netpoll(new_slave);
 
 err_close:
+       slave_dev->priv_flags &= ~IFF_BONDING;
        dev_close(slave_dev);
 
 err_unset_master:
@@ -3168,11 +3190,20 @@ static int bond_slave_netdev_event(unsigned long event,
                                   struct net_device *slave_dev)
 {
        struct slave *slave = bond_slave_get_rtnl(slave_dev);
-       struct bonding *bond = slave->bond;
-       struct net_device *bond_dev = slave->bond->dev;
+       struct bonding *bond;
+       struct net_device *bond_dev;
        u32 old_speed;
        u8 old_duplex;
 
+       /* A netdev event can be generated while enslaving a device
+        * before netdev_rx_handler_register is called in which case
+        * slave will be NULL
+        */
+       if (!slave)
+               return NOTIFY_DONE;
+       bond_dev = slave->bond->dev;
+       bond = slave->bond;
+
        switch (event) {
        case NETDEV_UNREGISTER:
                if (bond->setup_by_slave)
@@ -3286,20 +3317,22 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count)
  */
 static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count)
 {
-       struct ethhdr *data = (struct ethhdr *)skb->data;
-       struct iphdr *iph;
-       struct ipv6hdr *ipv6h;
+       const struct ethhdr *data;
+       const struct iphdr *iph;
+       const struct ipv6hdr *ipv6h;
        u32 v6hash;
-       __be32 *s, *d;
+       const __be32 *s, *d;
 
        if (skb->protocol == htons(ETH_P_IP) &&
-           skb_network_header_len(skb) >= sizeof(*iph)) {
+           pskb_network_may_pull(skb, sizeof(*iph))) {
                iph = ip_hdr(skb);
+               data = (struct ethhdr *)skb->data;
                return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^
                        (data->h_dest[5] ^ data->h_source[5])) % count;
        } else if (skb->protocol == htons(ETH_P_IPV6) &&
-                  skb_network_header_len(skb) >= sizeof(*ipv6h)) {
+                  pskb_network_may_pull(skb, sizeof(*ipv6h))) {
                ipv6h = ipv6_hdr(skb);
+               data = (struct ethhdr *)skb->data;
                s = &ipv6h->saddr.s6_addr32[0];
                d = &ipv6h->daddr.s6_addr32[0];
                v6hash = (s[1] ^ d[1]) ^ (s[2] ^ d[2]) ^ (s[3] ^ d[3]);
@@ -3318,33 +3351,36 @@ static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count)
 static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count)
 {
        u32 layer4_xor = 0;
-       struct iphdr *iph;
-       struct ipv6hdr *ipv6h;
-       __be32 *s, *d;
-       __be16 *layer4hdr;
+       const struct iphdr *iph;
+       const struct ipv6hdr *ipv6h;
+       const __be32 *s, *d;
+       const __be16 *l4 = NULL;
+       __be16 _l4[2];
+       int noff = skb_network_offset(skb);
+       int poff;
 
        if (skb->protocol == htons(ETH_P_IP) &&
-           skb_network_header_len(skb) >= sizeof(*iph)) {
+           pskb_may_pull(skb, noff + sizeof(*iph))) {
                iph = ip_hdr(skb);
-               if (!ip_is_fragment(iph) &&
-                   (iph->protocol == IPPROTO_TCP ||
-                    iph->protocol == IPPROTO_UDP) &&
-                   (skb_headlen(skb) - skb_network_offset(skb) >=
-                    iph->ihl * sizeof(u32) + sizeof(*layer4hdr) * 2)) {
-                       layer4hdr = (__be16 *)((u32 *)iph + iph->ihl);
-                       layer4_xor = ntohs(*layer4hdr ^ *(layer4hdr + 1));
+               poff = proto_ports_offset(iph->protocol);
+
+               if (!ip_is_fragment(iph) && poff >= 0) {
+                       l4 = skb_header_pointer(skb, noff + (iph->ihl << 2) + poff,
+                                               sizeof(_l4), &_l4);
+                       if (l4)
+                               layer4_xor = ntohs(l4[0] ^ l4[1]);
                }
                return (layer4_xor ^
                        ((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count;
        } else if (skb->protocol == htons(ETH_P_IPV6) &&
-                  skb_network_header_len(skb) >= sizeof(*ipv6h)) {
+                  pskb_may_pull(skb, noff + sizeof(*ipv6h))) {
                ipv6h = ipv6_hdr(skb);
-               if ((ipv6h->nexthdr == IPPROTO_TCP ||
-                    ipv6h->nexthdr == IPPROTO_UDP) &&
-                   (skb_headlen(skb) - skb_network_offset(skb) >=
-                    sizeof(*ipv6h) + sizeof(*layer4hdr) * 2)) {
-                       layer4hdr = (__be16 *)(ipv6h + 1);
-                       layer4_xor = ntohs(*layer4hdr ^ *(layer4hdr + 1));
+               poff = proto_ports_offset(ipv6h->nexthdr);
+               if (poff >= 0) {
+                       l4 = skb_header_pointer(skb, noff + sizeof(*ipv6h) + poff,
+                                               sizeof(_l4), &_l4);
+                       if (l4)
+                               layer4_xor = ntohs(l4[0] ^ l4[1]);
                }
                s = &ipv6h->saddr.s6_addr32[0];
                d = &ipv6h->daddr.s6_addr32[0];
index f32b9fc..9aa0c64 100644 (file)
@@ -929,6 +929,7 @@ static int mcp251x_open(struct net_device *net)
        struct mcp251x_priv *priv = netdev_priv(net);
        struct spi_device *spi = priv->spi;
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+       unsigned long flags;
        int ret;
 
        ret = open_candev(net);
@@ -945,9 +946,14 @@ static int mcp251x_open(struct net_device *net)
        priv->tx_skb = NULL;
        priv->tx_len = 0;
 
+       flags = IRQF_ONESHOT;
+       if (pdata->irq_flags)
+               flags |= pdata->irq_flags;
+       else
+               flags |= IRQF_TRIGGER_FALLING;
+
        ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
-                 pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING,
-                 DEVICE_NAME, priv);
+                                  flags, DEVICE_NAME, priv);
        if (ret) {
                dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
                if (pdata->transceiver_enable)
index 5c2f3fb..321c27e 100644 (file)
@@ -316,15 +316,4 @@ static struct pcmcia_driver ems_pcmcia_driver = {
        .remove = ems_pcmcia_remove,
        .id_table = ems_pcmcia_tbl,
 };
-
-static int __init ems_pcmcia_init(void)
-{
-       return pcmcia_register_driver(&ems_pcmcia_driver);
-}
-module_init(ems_pcmcia_init);
-
-static void __exit ems_pcmcia_exit(void)
-{
-       pcmcia_unregister_driver(&ems_pcmcia_driver);
-}
-module_exit(ems_pcmcia_exit);
+module_pcmcia_driver(ems_pcmcia_driver);
index 1a7020b..0a707f7 100644 (file)
@@ -740,15 +740,4 @@ static struct pcmcia_driver pcan_driver = {
        .remove = pcan_remove,
        .id_table = pcan_table,
 };
-
-static int __init pcan_init(void)
-{
-       return pcmcia_register_driver(&pcan_driver);
-}
-module_init(pcan_init);
-
-static void __exit pcan_exit(void)
-{
-       pcmcia_unregister_driver(&pcan_driver);
-}
-module_exit(pcan_exit);
+module_pcmcia_driver(pcan_driver);
index 6433b81..8e0c4a0 100644 (file)
@@ -96,8 +96,8 @@ static int sja1000_ofp_probe(struct platform_device *ofdev)
        struct net_device *dev;
        struct sja1000_priv *priv;
        struct resource res;
-       const u32 *prop;
-       int err, irq, res_size, prop_size;
+       u32 prop;
+       int err, irq, res_size;
        void __iomem *base;
 
        err = of_address_to_resource(np, 0, &res);
@@ -138,27 +138,27 @@ static int sja1000_ofp_probe(struct platform_device *ofdev)
        priv->read_reg = sja1000_ofp_read_reg;
        priv->write_reg = sja1000_ofp_write_reg;
 
-       prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size);
-       if (prop && (prop_size ==  sizeof(u32)))
-               priv->can.clock.freq = *prop / 2;
+       err = of_property_read_u32(np, "nxp,external-clock-frequency", &prop);
+       if (!err)
+               priv->can.clock.freq = prop / 2;
        else
                priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */
 
-       prop = of_get_property(np, "nxp,tx-output-mode", &prop_size);
-       if (prop && (prop_size == sizeof(u32)))
-               priv->ocr |= *prop & OCR_MODE_MASK;
+       err = of_property_read_u32(np, "nxp,tx-output-mode", &prop);
+       if (!err)
+               priv->ocr |= prop & OCR_MODE_MASK;
        else
                priv->ocr |= OCR_MODE_NORMAL; /* default */
 
-       prop = of_get_property(np, "nxp,tx-output-config", &prop_size);
-       if (prop && (prop_size == sizeof(u32)))
-               priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK;
+       err = of_property_read_u32(np, "nxp,tx-output-config", &prop);
+       if (!err)
+               priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;
        else
                priv->ocr |= OCR_TX0_PULLDOWN; /* default */
 
-       prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size);
-       if (prop && (prop_size == sizeof(u32)) && *prop) {
-               u32 divider = priv->can.clock.freq * 2 / *prop;
+       err = of_property_read_u32(np, "nxp,clock-out-frequency", &prop);
+       if (!err && prop) {
+               u32 divider = priv->can.clock.freq * 2 / prop;
 
                if (divider > 1)
                        priv->cdr |= divider / 2 - 1;
@@ -168,8 +168,7 @@ static int sja1000_ofp_probe(struct platform_device *ofdev)
                priv->cdr |= CDR_CLK_OFF; /* default */
        }
 
-       prop = of_get_property(np, "nxp,no-comparator-bypass", NULL);
-       if (!prop)
+       if (!of_property_read_bool(np, "nxp,no-comparator-bypass"))
                priv->cdr |= CDR_CBP; /* default */
 
        priv->irq_flags = IRQF_SHARED;
index c2c0a5b..498605f 100644 (file)
@@ -27,7 +27,7 @@
 #include "softing_platform.h"
 
 static int softingcs_index;
-static spinlock_t softingcs_index_lock;
+static DEFINE_SPINLOCK(softingcs_index_lock);
 
 static int softingcs_reset(struct platform_device *pdev, int v);
 static int softingcs_enable_irq(struct platform_device *pdev, int v);
@@ -340,19 +340,7 @@ static struct pcmcia_driver softingcs_driver = {
        .remove         = softingcs_remove,
 };
 
-static int __init softingcs_start(void)
-{
-       spin_lock_init(&softingcs_index_lock);
-       return pcmcia_register_driver(&softingcs_driver);
-}
-
-static void __exit softingcs_stop(void)
-{
-       pcmcia_unregister_driver(&softingcs_driver);
-}
-
-module_init(softingcs_start);
-module_exit(softingcs_stop);
+module_pcmcia_driver(softingcs_driver);
 
 MODULE_DESCRIPTION("softing CANcard driver"
                ", links PCMCIA card to softing driver");
index ffd8de2..6fc994f 100644 (file)
@@ -1165,16 +1165,4 @@ static struct pcmcia_driver tc574_driver = {
        .suspend        = tc574_suspend,
        .resume         = tc574_resume,
 };
-
-static int __init init_tc574(void)
-{
-       return pcmcia_register_driver(&tc574_driver);
-}
-
-static void __exit exit_tc574(void)
-{
-       pcmcia_unregister_driver(&tc574_driver);
-}
-
-module_init(init_tc574);
-module_exit(exit_tc574);
+module_pcmcia_driver(tc574_driver);
index a556c01..078480a 100644 (file)
@@ -928,16 +928,4 @@ static struct pcmcia_driver tc589_driver = {
        .suspend        = tc589_suspend,
        .resume         = tc589_resume,
 };
-
-static int __init init_tc589(void)
-{
-       return pcmcia_register_driver(&tc589_driver);
-}
-
-static void __exit exit_tc589(void)
-{
-       pcmcia_unregister_driver(&tc589_driver);
-}
-
-module_init(init_tc589);
-module_exit(exit_tc589);
+module_pcmcia_driver(tc589_driver);
index cab306a..e1d2643 100644 (file)
@@ -828,7 +828,7 @@ static int ax_probe(struct platform_device *pdev)
        struct ei_device *ei_local;
        struct ax_device *ax;
        struct resource *irq, *mem, *mem2;
-       resource_size_t mem_size, mem2_size = 0;
+       unsigned long mem_size, mem2_size = 0;
        int ret = 0;
 
        dev = ax__alloc_ei_netdev(sizeof(struct ax_device));
index e1b3941..d801c14 100644 (file)
@@ -728,19 +728,7 @@ static struct pcmcia_driver axnet_cs_driver = {
        .suspend        = axnet_suspend,
        .resume         = axnet_resume,
 };
-
-static int __init init_axnet_cs(void)
-{
-       return pcmcia_register_driver(&axnet_cs_driver);
-}
-
-static void __exit exit_axnet_cs(void)
-{
-       pcmcia_unregister_driver(&axnet_cs_driver);
-}
-
-module_init(init_axnet_cs);
-module_exit(exit_axnet_cs);
+module_pcmcia_driver(axnet_cs_driver);
 
 /*====================================================================*/
 
index de1af0b..46c5aad 100644 (file)
@@ -1694,16 +1694,4 @@ static struct pcmcia_driver pcnet_driver = {
        .suspend        = pcnet_suspend,
        .resume         = pcnet_resume,
 };
-
-static int __init init_pcnet_cs(void)
-{
-    return pcmcia_register_driver(&pcnet_driver);
-}
-
-static void __exit exit_pcnet_cs(void)
-{
-    pcmcia_unregister_driver(&pcnet_driver);
-}
-
-module_init(init_pcnet_cs);
-module_exit(exit_pcnet_cs);
+module_pcmcia_driver(pcnet_driver);
index 9f59bf6..d4ed891 100644 (file)
@@ -1508,16 +1508,4 @@ static struct pcmcia_driver nmclan_cs_driver = {
        .suspend        = nmclan_suspend,
        .resume         = nmclan_resume,
 };
-
-static int __init init_nmclan_cs(void)
-{
-       return pcmcia_register_driver(&nmclan_cs_driver);
-}
-
-static void __exit exit_nmclan_cs(void)
-{
-       pcmcia_unregister_driver(&nmclan_cs_driver);
-}
-
-module_init(init_nmclan_cs);
-module_exit(exit_nmclan_cs);
+module_pcmcia_driver(nmclan_cs_driver);
index 4046f97..57619dd 100644 (file)
@@ -2614,6 +2614,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
                        }
                }
 
+               /* initialize FW coalescing state machines in RAM */
+               bnx2x_update_coalesce(bp);
+
                /* setup the leading queue */
                rc = bnx2x_setup_leading(bp);
                if (rc) {
@@ -4580,11 +4583,11 @@ static void storm_memset_hc_disable(struct bnx2x *bp, u8 port,
        u32 enable_flag = disable ? 0 : (1 << HC_INDEX_DATA_HC_ENABLED_SHIFT);
        u32 addr = BAR_CSTRORM_INTMEM +
                   CSTORM_STATUS_BLOCK_DATA_FLAGS_OFFSET(fw_sb_id, sb_index);
-       u16 flags = REG_RD16(bp, addr);
+       u8 flags = REG_RD8(bp, addr);
        /* clear and set */
        flags &= ~HC_INDEX_DATA_HC_ENABLED;
        flags |= enable_flag;
-       REG_WR16(bp, addr, flags);
+       REG_WR8(bp, addr, flags);
        DP(NETIF_MSG_IFUP,
           "port %x fw_sb_id %d sb_index %d disable %d\n",
           port, fw_sb_id, sb_index, disable);
index 8e58da9..c50696b 100644 (file)
@@ -9878,6 +9878,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
                                REG_RD(bp, NIG_REG_NIG_INT_STS_CLR_0);
                        }
                }
+               if (!CHIP_IS_E1x(bp))
+                       /* block FW from writing to host */
+                       REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, 0);
+
                /* wait until BRB is empty */
                tmp_reg = REG_RD(bp, BRB1_REG_NUM_OF_FULL_BLOCKS);
                while (timer_count) {
index 08e54f3..2886c9b 100644 (file)
@@ -759,8 +759,9 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
 
        if (vlan_tx_tag_present(skb)) {
                vlan_tag = be_get_tx_vlan_tag(adapter, skb);
-               __vlan_put_tag(skb, vlan_tag);
-               skb->vlan_tci = 0;
+               skb = __vlan_put_tag(skb, vlan_tag);
+               if (skb)
+                       skb->vlan_tci = 0;
        }
 
        return skb;
index f292c3a..73195f6 100644 (file)
@@ -1002,6 +1002,7 @@ static void fec_enet_adjust_link(struct net_device *ndev)
        } else {
                if (fep->link) {
                        fec_stop(ndev);
+                       fep->link = phy_dev->link;
                        status_change = 1;
                }
        }
index 2418faf..ab98b77 100644 (file)
@@ -705,19 +705,7 @@ static struct pcmcia_driver fmvj18x_cs_driver = {
        .suspend        = fmvj18x_suspend,
        .resume         = fmvj18x_resume,
 };
-
-static int __init init_fmvj18x_cs(void)
-{
-       return pcmcia_register_driver(&fmvj18x_cs_driver);
-}
-
-static void __exit exit_fmvj18x_cs(void)
-{
-       pcmcia_unregister_driver(&fmvj18x_cs_driver);
-}
-
-module_init(init_fmvj18x_cs);
-module_exit(exit_fmvj18x_cs);
+module_pcmcia_driver(fmvj18x_cs_driver);
 
 /*====================================================================*/
 
index 2515140..ab577a7 100644 (file)
@@ -284,18 +284,10 @@ struct igb_q_vector {
 enum e1000_ring_flags_t {
        IGB_RING_FLAG_RX_SCTP_CSUM,
        IGB_RING_FLAG_RX_LB_VLAN_BSWAP,
-       IGB_RING_FLAG_RX_BUILD_SKB_ENABLED,
        IGB_RING_FLAG_TX_CTX_IDX,
        IGB_RING_FLAG_TX_DETECT_HANG
 };
 
-#define ring_uses_build_skb(ring) \
-       test_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
-#define set_ring_build_skb_enabled(ring) \
-       set_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
-#define clear_ring_build_skb_enabled(ring) \
-       clear_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
-
 #define IGB_TXD_DCMD (E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS)
 
 #define IGB_RX_DESC(R, i)          \
index 8496adf..64f7529 100644 (file)
@@ -3350,20 +3350,6 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
        wr32(E1000_RXDCTL(reg_idx), rxdctl);
 }
 
-static void igb_set_rx_buffer_len(struct igb_adapter *adapter,
-                                 struct igb_ring *rx_ring)
-{
-#define IGB_MAX_BUILD_SKB_SIZE \
-       (SKB_WITH_OVERHEAD(IGB_RX_BUFSZ) - \
-        (NET_SKB_PAD + NET_IP_ALIGN + IGB_TS_HDR_LEN))
-
-       /* set build_skb flag */
-       if (adapter->max_frame_size <= IGB_MAX_BUILD_SKB_SIZE)
-               set_ring_build_skb_enabled(rx_ring);
-       else
-               clear_ring_build_skb_enabled(rx_ring);
-}
-
 /**
  * igb_configure_rx - Configure receive Unit after Reset
  * @adapter: board private structure
@@ -3383,11 +3369,8 @@ static void igb_configure_rx(struct igb_adapter *adapter)
 
        /* Setup the HW Rx Head and Tail Descriptor Pointers and
         * the Base and Length of the Rx Descriptor Ring */
-       for (i = 0; i < adapter->num_rx_queues; i++) {
-               struct igb_ring *rx_ring = adapter->rx_ring[i];
-               igb_set_rx_buffer_len(adapter, rx_ring);
-               igb_configure_rx_ring(adapter, rx_ring);
-       }
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               igb_configure_rx_ring(adapter, adapter->rx_ring[i]);
 }
 
 /**
@@ -6203,78 +6186,6 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring,
        return igb_can_reuse_rx_page(rx_buffer, page, truesize);
 }
 
-static struct sk_buff *igb_build_rx_buffer(struct igb_ring *rx_ring,
-                                          union e1000_adv_rx_desc *rx_desc)
-{
-       struct igb_rx_buffer *rx_buffer;
-       struct sk_buff *skb;
-       struct page *page;
-       void *page_addr;
-       unsigned int size = le16_to_cpu(rx_desc->wb.upper.length);
-#if (PAGE_SIZE < 8192)
-       unsigned int truesize = IGB_RX_BUFSZ;
-#else
-       unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
-                               SKB_DATA_ALIGN(NET_SKB_PAD +
-                                              NET_IP_ALIGN +
-                                              size);
-#endif
-
-       /* If we spanned a buffer we have a huge mess so test for it */
-       BUG_ON(unlikely(!igb_test_staterr(rx_desc, E1000_RXD_STAT_EOP)));
-
-       rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
-       page = rx_buffer->page;
-       prefetchw(page);
-
-       page_addr = page_address(page) + rx_buffer->page_offset;
-
-       /* prefetch first cache line of first page */
-       prefetch(page_addr + NET_SKB_PAD + NET_IP_ALIGN);
-#if L1_CACHE_BYTES < 128
-       prefetch(page_addr + L1_CACHE_BYTES + NET_SKB_PAD + NET_IP_ALIGN);
-#endif
-
-       /* build an skb to around the page buffer */
-       skb = build_skb(page_addr, truesize);
-       if (unlikely(!skb)) {
-               rx_ring->rx_stats.alloc_failed++;
-               return NULL;
-       }
-
-       /* we are reusing so sync this buffer for CPU use */
-       dma_sync_single_range_for_cpu(rx_ring->dev,
-                                     rx_buffer->dma,
-                                     rx_buffer->page_offset,
-                                     IGB_RX_BUFSZ,
-                                     DMA_FROM_DEVICE);
-
-       /* update pointers within the skb to store the data */
-       skb_reserve(skb, NET_IP_ALIGN + NET_SKB_PAD);
-       __skb_put(skb, size);
-
-       /* pull timestamp out of packet data */
-       if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
-               igb_ptp_rx_pktstamp(rx_ring->q_vector, skb->data, skb);
-               __skb_pull(skb, IGB_TS_HDR_LEN);
-       }
-
-       if (igb_can_reuse_rx_page(rx_buffer, page, truesize)) {
-               /* hand second half of page back to the ring */
-               igb_reuse_rx_page(rx_ring, rx_buffer);
-       } else {
-               /* we are not reusing the buffer so unmap it */
-               dma_unmap_page(rx_ring->dev, rx_buffer->dma,
-                              PAGE_SIZE, DMA_FROM_DEVICE);
-       }
-
-       /* clear contents of buffer_info */
-       rx_buffer->dma = 0;
-       rx_buffer->page = NULL;
-
-       return skb;
-}
-
 static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring,
                                           union e1000_adv_rx_desc *rx_desc,
                                           struct sk_buff *skb)
@@ -6690,10 +6601,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
                rmb();
 
                /* retrieve a buffer from the ring */
-               if (ring_uses_build_skb(rx_ring))
-                       skb = igb_build_rx_buffer(rx_ring, rx_desc);
-               else
-                       skb = igb_fetch_rx_buffer(rx_ring, rx_desc, skb);
+               skb = igb_fetch_rx_buffer(rx_ring, rx_desc, skb);
 
                /* exit if we failed to retrieve a buffer */
                if (!skb)
@@ -6780,14 +6688,6 @@ static bool igb_alloc_mapped_page(struct igb_ring *rx_ring,
        return true;
 }
 
-static inline unsigned int igb_rx_offset(struct igb_ring *rx_ring)
-{
-       if (ring_uses_build_skb(rx_ring))
-               return NET_SKB_PAD + NET_IP_ALIGN;
-       else
-               return 0;
-}
-
 /**
  * igb_alloc_rx_buffers - Replace used receive buffers; packet split
  * @adapter: address of board private structure
@@ -6814,9 +6714,7 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
                 * Refresh the desc even if buffer_addrs didn't change
                 * because each write-back erases this info.
                 */
-               rx_desc->read.pkt_addr = cpu_to_le64(bi->dma +
-                                                    bi->page_offset +
-                                                    igb_rx_offset(rx_ring));
+               rx_desc->read.pkt_addr = cpu_to_le64(bi->dma + bi->page_offset);
 
                rx_desc++;
                bi++;
index d44b4d2..97e3366 100644 (file)
@@ -1049,6 +1049,12 @@ int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
        if ((vf >= adapter->num_vfs) || (vlan > 4095) || (qos > 7))
                return -EINVAL;
        if (vlan || qos) {
+               if (adapter->vfinfo[vf].pf_vlan)
+                       err = ixgbe_set_vf_vlan(adapter, false,
+                                               adapter->vfinfo[vf].pf_vlan,
+                                               vf);
+               if (err)
+                       goto out;
                err = ixgbe_set_vf_vlan(adapter, true, vlan, vf);
                if (err)
                        goto out;
index edfba93..434e33c 100644 (file)
@@ -33,6 +33,7 @@ config MV643XX_ETH
 
 config MVMDIO
        tristate "Marvell MDIO interface support"
+       select PHYLIB
        ---help---
          This driver supports the MDIO interface found in the network
          interface units of the Marvell EBU SoCs (Kirkwood, Orion5x,
@@ -45,7 +46,6 @@ config MVMDIO
 config MVNETA
        tristate "Marvell Armada 370/XP network interface support"
        depends on MACH_ARMADA_370_XP
-       select PHYLIB
        select MVMDIO
        ---help---
          This driver supports the network interface units in the
index 1e628ce..a47a097 100644 (file)
@@ -374,7 +374,6 @@ static int rxq_number = 8;
 static int txq_number = 8;
 
 static int rxq_def;
-static int txq_def;
 
 #define MVNETA_DRIVER_NAME "mvneta"
 #define MVNETA_DRIVER_VERSION "1.0"
@@ -1475,7 +1474,8 @@ error:
 static int mvneta_tx(struct sk_buff *skb, struct net_device *dev)
 {
        struct mvneta_port *pp = netdev_priv(dev);
-       struct mvneta_tx_queue *txq = &pp->txqs[txq_def];
+       u16 txq_id = skb_get_queue_mapping(skb);
+       struct mvneta_tx_queue *txq = &pp->txqs[txq_id];
        struct mvneta_tx_desc *tx_desc;
        struct netdev_queue *nq;
        int frags = 0;
@@ -1485,7 +1485,7 @@ static int mvneta_tx(struct sk_buff *skb, struct net_device *dev)
                goto out;
 
        frags = skb_shinfo(skb)->nr_frags + 1;
-       nq    = netdev_get_tx_queue(dev, txq_def);
+       nq    = netdev_get_tx_queue(dev, txq_id);
 
        /* Get a descriptor for the first part of the packet */
        tx_desc = mvneta_txq_next_desc_get(txq);
@@ -2689,7 +2689,7 @@ static int mvneta_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       dev = alloc_etherdev_mq(sizeof(struct mvneta_port), 8);
+       dev = alloc_etherdev_mqs(sizeof(struct mvneta_port), txq_number, rxq_number);
        if (!dev)
                return -ENOMEM;
 
@@ -2844,4 +2844,3 @@ module_param(rxq_number, int, S_IRUGO);
 module_param(txq_number, int, S_IRUGO);
 
 module_param(rxq_def, int, S_IRUGO);
-module_param(txq_def, int, S_IRUGO);
index cd5ae88..edd63f1 100644 (file)
@@ -1500,6 +1500,12 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
                }
        } while ((adapter->ahw->linkup && ahw->has_link_events) != 1);
 
+       /* Make sure carrier is off and queue is stopped during loopback */
+       if (netif_running(netdev)) {
+               netif_carrier_off(netdev);
+               netif_stop_queue(netdev);
+       }
+
        ret = qlcnic_do_lb_test(adapter, mode);
 
        qlcnic_83xx_clear_lb_mode(adapter, mode);
@@ -2780,6 +2786,7 @@ static u64 *qlcnic_83xx_fill_stats(struct qlcnic_adapter *adapter,
 void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
 {
        struct qlcnic_cmd_args cmd;
+       struct net_device *netdev = adapter->netdev;
        int ret = 0;
 
        qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_STATISTICS);
@@ -2789,7 +2796,7 @@ void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
        data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
                                      QLC_83XX_STAT_TX, &ret);
        if (ret) {
-               dev_info(&adapter->pdev->dev, "Error getting MAC stats\n");
+               netdev_err(netdev, "Error getting Tx stats\n");
                goto out;
        }
        /* Get MAC stats */
@@ -2799,8 +2806,7 @@ void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
        data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
                                      QLC_83XX_STAT_MAC, &ret);
        if (ret) {
-               dev_info(&adapter->pdev->dev,
-                        "Error getting Rx stats\n");
+               netdev_err(netdev, "Error getting MAC stats\n");
                goto out;
        }
        /* Get Rx stats */
@@ -2810,8 +2816,7 @@ void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
        data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
                                      QLC_83XX_STAT_RX, &ret);
        if (ret)
-               dev_info(&adapter->pdev->dev,
-                        "Error getting Tx stats\n");
+               netdev_err(netdev, "Error getting Rx stats\n");
 out:
        qlcnic_free_mbx_args(&cmd);
 }
index 0e63006..5fa847f 100644 (file)
@@ -358,8 +358,7 @@ set_flags:
                memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
        }
        opcode = TX_ETHER_PKT;
-       if ((adapter->netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
-           skb_shinfo(skb)->gso_size > 0) {
+       if (skb_is_gso(skb)) {
                hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
                first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
                first_desc->total_hdr_length = hdr_len;
index 987fb6f..5ef328a 100644 (file)
@@ -200,10 +200,10 @@ beacon_err:
        }
 
        err = qlcnic_config_led(adapter, b_state, b_rate);
-       if (!err)
+       if (!err) {
                err = len;
-       else
                ahw->beacon_state = b_state;
+       }
 
        if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
                qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
index a131d7b..7e8d682 100644 (file)
@@ -18,7 +18,7 @@
  */
 #define DRV_NAME       "qlge"
 #define DRV_STRING     "QLogic 10 Gigabit PCI-E Ethernet Driver "
-#define DRV_VERSION    "v1.00.00.31"
+#define DRV_VERSION    "v1.00.00.32"
 
 #define WQ_ADDR_ALIGN  0x3     /* 4 byte alignment */
 
index 6f316ab..0780e03 100644 (file)
@@ -379,13 +379,13 @@ static int ql_get_settings(struct net_device *ndev,
 
        ecmd->supported = SUPPORTED_10000baseT_Full;
        ecmd->advertising = ADVERTISED_10000baseT_Full;
-       ecmd->autoneg = AUTONEG_ENABLE;
        ecmd->transceiver = XCVR_EXTERNAL;
        if ((qdev->link_status & STS_LINK_TYPE_MASK) ==
                                STS_LINK_TYPE_10GBASET) {
                ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
                ecmd->advertising |= (ADVERTISED_TP | ADVERTISED_Autoneg);
                ecmd->port = PORT_TP;
+               ecmd->autoneg = AUTONEG_ENABLE;
        } else {
                ecmd->supported |= SUPPORTED_FIBRE;
                ecmd->advertising |= ADVERTISED_FIBRE;
index b13ab54..8033555 100644 (file)
@@ -1434,11 +1434,13 @@ map_error:
 }
 
 /* Categorizing receive firmware frame errors */
-static void ql_categorize_rx_err(struct ql_adapter *qdev, u8 rx_err)
+static void ql_categorize_rx_err(struct ql_adapter *qdev, u8 rx_err,
+                                struct rx_ring *rx_ring)
 {
        struct nic_stats *stats = &qdev->nic_stats;
 
        stats->rx_err_count++;
+       rx_ring->rx_errors++;
 
        switch (rx_err & IB_MAC_IOCB_RSP_ERR_MASK) {
        case IB_MAC_IOCB_RSP_ERR_CODE_ERR:
@@ -1474,6 +1476,12 @@ static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev,
        struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
        struct napi_struct *napi = &rx_ring->napi;
 
+       /* Frame error, so drop the packet. */
+       if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+               ql_categorize_rx_err(qdev, ib_mac_rsp->flags2, rx_ring);
+               put_page(lbq_desc->p.pg_chunk.page);
+               return;
+       }
        napi->dev = qdev->ndev;
 
        skb = napi_get_frags(napi);
@@ -1529,6 +1537,12 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
        addr = lbq_desc->p.pg_chunk.va;
        prefetch(addr);
 
+       /* Frame error, so drop the packet. */
+       if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+               ql_categorize_rx_err(qdev, ib_mac_rsp->flags2, rx_ring);
+               goto err_out;
+       }
+
        /* The max framesize filter on this chip is set higher than
         * MTU since FCoE uses 2k frames.
         */
@@ -1614,6 +1628,13 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
        memcpy(skb_put(new_skb, length), skb->data, length);
        skb = new_skb;
 
+       /* Frame error, so drop the packet. */
+       if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+               ql_categorize_rx_err(qdev, ib_mac_rsp->flags2, rx_ring);
+               dev_kfree_skb_any(skb);
+               return;
+       }
+
        /* loopback self test for ethtool */
        if (test_bit(QL_SELFTEST, &qdev->flags)) {
                ql_check_lb_frame(qdev, skb);
@@ -1919,6 +1940,13 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
                return;
        }
 
+       /* Frame error, so drop the packet. */
+       if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+               ql_categorize_rx_err(qdev, ib_mac_rsp->flags2, rx_ring);
+               dev_kfree_skb_any(skb);
+               return;
+       }
+
        /* The max framesize filter on this chip is set higher than
         * MTU since FCoE uses 2k frames.
         */
@@ -2000,12 +2028,6 @@ static unsigned long ql_process_mac_rx_intr(struct ql_adapter *qdev,
 
        QL_DUMP_IB_MAC_RSP(ib_mac_rsp);
 
-       /* Frame error, so drop the packet. */
-       if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
-               ql_categorize_rx_err(qdev, ib_mac_rsp->flags2);
-               return (unsigned long)length;
-       }
-
        if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV) {
                /* The data and headers are split into
                 * separate buffers.
index 04393b5..656d2e2 100644 (file)
@@ -2054,16 +2054,4 @@ static struct pcmcia_driver smc91c92_cs_driver = {
        .suspend        = smc91c92_suspend,
        .resume         = smc91c92_resume,
 };
-
-static int __init init_smc91c92_cs(void)
-{
-       return pcmcia_register_driver(&smc91c92_cs_driver);
-}
-
-static void __exit exit_smc91c92_cs(void)
-{
-       pcmcia_unregister_driver(&smc91c92_cs_driver);
-}
-
-module_init(init_smc91c92_cs);
-module_exit(exit_smc91c92_cs);
+module_pcmcia_driver(smc91c92_cs_driver);
index 0c74a70..50617c5 100644 (file)
@@ -149,6 +149,7 @@ void dwmac_mmc_intr_all_mask(void __iomem *ioaddr)
 {
        writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_INTR_MASK);
        writel(MMC_DEFAULT_MASK, ioaddr + MMC_TX_INTR_MASK);
+       writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_IPC_INTR_MASK);
 }
 
 /* This reads the MAC core counters (if actaully supported).
index 80cad06..4781d3d 100644 (file)
@@ -1380,7 +1380,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                        memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
 
                if (data->dual_emac) {
-                       if (of_property_read_u32(node, "dual_emac_res_vlan",
+                       if (of_property_read_u32(slave_node, "dual_emac_res_vlan",
                                                 &prop)) {
                                pr_err("Missing dual_emac_res_vlan in DT.\n");
                                slave_data->dual_emac_res_vlan = i+1;
index 98e09d0..1025b4e 100644 (file)
@@ -1775,21 +1775,7 @@ static struct pcmcia_driver xirc2ps_cs_driver = {
        .suspend        = xirc2ps_suspend,
        .resume         = xirc2ps_resume,
 };
-
-static int __init
-init_xirc2ps_cs(void)
-{
-       return pcmcia_register_driver(&xirc2ps_cs_driver);
-}
-
-static void __exit
-exit_xirc2ps_cs(void)
-{
-       pcmcia_unregister_driver(&xirc2ps_cs_driver);
-}
-
-module_init(init_xirc2ps_cs);
-module_exit(exit_xirc2ps_cs);
+module_pcmcia_driver(xirc2ps_cs_driver);
 
 #ifndef MODULE
 static int __init setup_xirc2ps_cs(char *str)
index b7c457a..729ed53 100644 (file)
@@ -1594,7 +1594,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 
                if (tun->flags & TUN_TAP_MQ &&
                    (tun->numqueues + tun->numdisabled > 1))
-                       return err;
+                       return -EBUSY;
        }
        else {
                char *name;
index 16c8429..6bd9167 100644 (file)
@@ -134,7 +134,7 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
                goto error;
 
        if (skb) {
-               if (skb->len <= sizeof(ETH_HLEN))
+               if (skb->len <= ETH_HLEN)
                        goto error;
 
                /* mapping VLANs to MBIM sessions:
index 968d5d5..2a3579f 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
+#include <linux/etherdevice.h>
 #include <linux/mii.h>
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
@@ -52,6 +53,96 @@ struct qmi_wwan_state {
        struct usb_interface *data;
 };
 
+/* default ethernet address used by the modem */
+static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3};
+
+/* Make up an ethernet header if the packet doesn't have one.
+ *
+ * A firmware bug common among several devices cause them to send raw
+ * IP packets under some circumstances.  There is no way for the
+ * driver/host to know when this will happen.  And even when the bug
+ * hits, some packets will still arrive with an intact header.
+ *
+ * The supported devices are only capably of sending IPv4, IPv6 and
+ * ARP packets on a point-to-point link. Any packet with an ethernet
+ * header will have either our address or a broadcast/multicast
+ * address as destination.  ARP packets will always have a header.
+ *
+ * This means that this function will reliably add the appropriate
+ * header iff necessary, provided our hardware address does not start
+ * with 4 or 6.
+ *
+ * Another common firmware bug results in all packets being addressed
+ * to 00:a0:c6:00:00:00 despite the host address being different.
+ * This function will also fixup such packets.
+ */
+static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+       __be16 proto;
+
+       /* usbnet rx_complete guarantees that skb->len is at least
+        * hard_header_len, so we can inspect the dest address without
+        * checking skb->len
+        */
+       switch (skb->data[0] & 0xf0) {
+       case 0x40:
+               proto = htons(ETH_P_IP);
+               break;
+       case 0x60:
+               proto = htons(ETH_P_IPV6);
+               break;
+       case 0x00:
+               if (is_multicast_ether_addr(skb->data))
+                       return 1;
+               /* possibly bogus destination - rewrite just in case */
+               skb_reset_mac_header(skb);
+               goto fix_dest;
+       default:
+               /* pass along other packets without modifications */
+               return 1;
+       }
+       if (skb_headroom(skb) < ETH_HLEN)
+               return 0;
+       skb_push(skb, ETH_HLEN);
+       skb_reset_mac_header(skb);
+       eth_hdr(skb)->h_proto = proto;
+       memset(eth_hdr(skb)->h_source, 0, ETH_ALEN);
+fix_dest:
+       memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
+       return 1;
+}
+
+/* very simplistic detection of IPv4 or IPv6 headers */
+static bool possibly_iphdr(const char *data)
+{
+       return (data[0] & 0xd0) == 0x40;
+}
+
+/* disallow addresses which may be confused with IP headers */
+static int qmi_wwan_mac_addr(struct net_device *dev, void *p)
+{
+       int ret;
+       struct sockaddr *addr = p;
+
+       ret = eth_prepare_mac_addr_change(dev, p);
+       if (ret < 0)
+               return ret;
+       if (possibly_iphdr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+       eth_commit_mac_addr_change(dev, p);
+       return 0;
+}
+
+static const struct net_device_ops qmi_wwan_netdev_ops = {
+       .ndo_open               = usbnet_open,
+       .ndo_stop               = usbnet_stop,
+       .ndo_start_xmit         = usbnet_start_xmit,
+       .ndo_tx_timeout         = usbnet_tx_timeout,
+       .ndo_change_mtu         = usbnet_change_mtu,
+       .ndo_set_mac_address    = qmi_wwan_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /* using a counter to merge subdriver requests with our own into a combined state */
 static int qmi_wwan_manage_power(struct usbnet *dev, int on)
 {
@@ -229,6 +320,18 @@ next_desc:
                usb_driver_release_interface(driver, info->data);
        }
 
+       /* Never use the same address on both ends of the link, even
+        * if the buggy firmware told us to.
+        */
+       if (!compare_ether_addr(dev->net->dev_addr, default_modem_addr))
+               eth_hw_addr_random(dev->net);
+
+       /* make MAC addr easily distinguishable from an IP header */
+       if (possibly_iphdr(dev->net->dev_addr)) {
+               dev->net->dev_addr[0] |= 0x02;  /* set local assignment bit */
+               dev->net->dev_addr[0] &= 0xbf;  /* clear "IP" bit */
+       }
+       dev->net->netdev_ops = &qmi_wwan_netdev_ops;
 err:
        return status;
 }
@@ -307,6 +410,7 @@ static const struct driver_info     qmi_wwan_info = {
        .bind           = qmi_wwan_bind,
        .unbind         = qmi_wwan_unbind,
        .manage_power   = qmi_wwan_manage_power,
+       .rx_fixup       = qmi_wwan_rx_fixup,
 };
 
 #define HUAWEI_VENDOR_ID       0x12D1
index 956024a..14128fd 100644 (file)
@@ -180,16 +180,7 @@ static struct pcmcia_driver airo_driver = {
        .suspend        = airo_suspend,
        .resume         = airo_resume,
 };
-
-static int __init airo_cs_init(void)
-{
-       return pcmcia_register_driver(&airo_driver);
-}
-
-static void __exit airo_cs_cleanup(void)
-{
-       pcmcia_unregister_driver(&airo_driver);
-}
+module_pcmcia_driver(airo_driver);
 
 /*
     This program is free software; you can redistribute it and/or
@@ -229,6 +220,3 @@ static void __exit airo_cs_cleanup(void)
     IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     POSSIBILITY OF SUCH DAMAGE.
 */
-
-module_init(airo_cs_init);
-module_exit(airo_cs_cleanup);
index 28fd992..bdee2ed 100644 (file)
@@ -519,7 +519,7 @@ static const u32 ar9580_1p0_mac_core[][2] = {
        {0x00008258, 0x00000000},
        {0x0000825c, 0x40000000},
        {0x00008260, 0x00080922},
-       {0x00008264, 0x9bc00010},
+       {0x00008264, 0x9d400010},
        {0x00008268, 0xffffffff},
        {0x0000826c, 0x0000ffff},
        {0x00008270, 0x00000000},
index 467b600..73fe8d6 100644 (file)
@@ -143,14 +143,14 @@ channel_detector_create(struct dfs_pattern_detector *dpd, u16 freq)
        u32 sz, i;
        struct channel_detector *cd;
 
-       cd = kmalloc(sizeof(*cd), GFP_KERNEL);
+       cd = kmalloc(sizeof(*cd), GFP_ATOMIC);
        if (cd == NULL)
                goto fail;
 
        INIT_LIST_HEAD(&cd->head);
        cd->freq = freq;
        sz = sizeof(cd->detectors) * dpd->num_radar_types;
-       cd->detectors = kzalloc(sz, GFP_KERNEL);
+       cd->detectors = kzalloc(sz, GFP_ATOMIC);
        if (cd->detectors == NULL)
                goto fail;
 
index 91b8dce..5e48c55 100644 (file)
@@ -218,7 +218,7 @@ static bool pulse_queue_enqueue(struct pri_detector *pde, u64 ts)
 {
        struct pulse_elem *p = pool_get_pulse_elem();
        if (p == NULL) {
-               p = kmalloc(sizeof(*p), GFP_KERNEL);
+               p = kmalloc(sizeof(*p), GFP_ATOMIC);
                if (p == NULL) {
                        DFS_POOL_STAT_INC(pulse_alloc_error);
                        return false;
@@ -299,7 +299,7 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,
                ps.deadline_ts = ps.first_ts + ps.dur;
                new_ps = pool_get_pseq_elem();
                if (new_ps == NULL) {
-                       new_ps = kmalloc(sizeof(*new_ps), GFP_KERNEL);
+                       new_ps = kmalloc(sizeof(*new_ps), GFP_ATOMIC);
                        if (new_ps == NULL) {
                                DFS_POOL_STAT_INC(pseq_alloc_error);
                                return false;
index 716058b..a47f5e0 100644 (file)
@@ -796,7 +796,7 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
         * required version.
         */
        if (priv->fw_version_major != MAJOR_VERSION_REQ ||
-           priv->fw_version_minor != MINOR_VERSION_REQ) {
+           priv->fw_version_minor < MINOR_VERSION_REQ) {
                dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n",
                        MAJOR_VERSION_REQ, MINOR_VERSION_REQ);
                return -EINVAL;
index b42930f..5225722 100644 (file)
@@ -245,16 +245,7 @@ static struct pcmcia_driver atmel_driver = {
        .suspend        = atmel_suspend,
        .resume         = atmel_resume,
 };
-
-static int __init atmel_cs_init(void)
-{
-        return pcmcia_register_driver(&atmel_driver);
-}
-
-static void __exit atmel_cs_cleanup(void)
-{
-        pcmcia_unregister_driver(&atmel_driver);
-}
+module_pcmcia_driver(atmel_driver);
 
 /*
     This program is free software; you can redistribute it and/or
@@ -294,6 +285,3 @@ static void __exit atmel_cs_cleanup(void)
     IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     POSSIBILITY OF SUCH DAMAGE.
 */
-
-module_init(atmel_cs_init);
-module_exit(atmel_cs_cleanup);
index f2ea2ce..55f2bd7 100644 (file)
@@ -130,6 +130,10 @@ static struct pcmcia_driver b43_pcmcia_driver = {
        .resume         = b43_pcmcia_resume,
 };
 
+/*
+ * These are not module init/exit functions!
+ * The module_pcmcia_driver() helper cannot be used here.
+ */
 int b43_pcmcia_init(void)
 {
        return pcmcia_register_driver(&b43_pcmcia_driver);
index e8486c1..b70f220 100644 (file)
@@ -5165,7 +5165,8 @@ static void b43_nphy_pmu_spur_avoid(struct b43_wldev *dev, bool avoid)
 #endif
 #ifdef CONFIG_B43_SSB
        case B43_BUS_SSB:
-               /* FIXME */
+               ssb_pmu_spuravoid_pllupdate(&dev->dev->sdev->bus->chipco,
+                                           avoid);
                break;
 #endif
        }
index ec46fff..78da3ef 100644 (file)
@@ -4128,10 +4128,6 @@ static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
        },
        {
                .max = 1,
-               .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
-       },
-       {
-               .max = 1,
                .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
                         BIT(NL80211_IFTYPE_P2P_GO)
        },
@@ -4187,8 +4183,7 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
                                 BIT(NL80211_IFTYPE_ADHOC) |
                                 BIT(NL80211_IFTYPE_AP) |
                                 BIT(NL80211_IFTYPE_P2P_CLIENT) |
-                                BIT(NL80211_IFTYPE_P2P_GO) |
-                                BIT(NL80211_IFTYPE_P2P_DEVICE);
+                                BIT(NL80211_IFTYPE_P2P_GO);
        wiphy->iface_combinations = brcmf_iface_combos;
        wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
        wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
index c6451c6..e2340b2 100644 (file)
@@ -274,6 +274,130 @@ static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br)
        }
 }
 
+/**
+ * This function frees the WL per-device resources.
+ *
+ * This function frees resources owned by the WL device pointed to
+ * by the wl parameter.
+ *
+ * precondition: can both be called locked and unlocked
+ *
+ */
+static void brcms_free(struct brcms_info *wl)
+{
+       struct brcms_timer *t, *next;
+
+       /* free ucode data */
+       if (wl->fw.fw_cnt)
+               brcms_ucode_data_free(&wl->ucode);
+       if (wl->irq)
+               free_irq(wl->irq, wl);
+
+       /* kill dpc */
+       tasklet_kill(&wl->tasklet);
+
+       if (wl->pub) {
+               brcms_debugfs_detach(wl->pub);
+               brcms_c_module_unregister(wl->pub, "linux", wl);
+       }
+
+       /* free common resources */
+       if (wl->wlc) {
+               brcms_c_detach(wl->wlc);
+               wl->wlc = NULL;
+               wl->pub = NULL;
+       }
+
+       /* virtual interface deletion is deferred so we cannot spinwait */
+
+       /* wait for all pending callbacks to complete */
+       while (atomic_read(&wl->callbacks) > 0)
+               schedule();
+
+       /* free timers */
+       for (t = wl->timers; t; t = next) {
+               next = t->next;
+#ifdef DEBUG
+               kfree(t->name);
+#endif
+               kfree(t);
+       }
+}
+
+/*
+* called from both kernel as from this kernel module (error flow on attach)
+* precondition: perimeter lock is not acquired.
+*/
+static void brcms_remove(struct bcma_device *pdev)
+{
+       struct ieee80211_hw *hw = bcma_get_drvdata(pdev);
+       struct brcms_info *wl = hw->priv;
+
+       if (wl->wlc) {
+               wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
+               wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
+               ieee80211_unregister_hw(hw);
+       }
+
+       brcms_free(wl);
+
+       bcma_set_drvdata(pdev, NULL);
+       ieee80211_free_hw(hw);
+}
+
+/*
+ * Precondition: Since this function is called in brcms_pci_probe() context,
+ * no locking is required.
+ */
+static void brcms_release_fw(struct brcms_info *wl)
+{
+       int i;
+       for (i = 0; i < MAX_FW_IMAGES; i++) {
+               release_firmware(wl->fw.fw_bin[i]);
+               release_firmware(wl->fw.fw_hdr[i]);
+       }
+}
+
+/*
+ * Precondition: Since this function is called in brcms_pci_probe() context,
+ * no locking is required.
+ */
+static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev)
+{
+       int status;
+       struct device *device = &pdev->dev;
+       char fw_name[100];
+       int i;
+
+       memset(&wl->fw, 0, sizeof(struct brcms_firmware));
+       for (i = 0; i < MAX_FW_IMAGES; i++) {
+               if (brcms_firmwares[i] == NULL)
+                       break;
+               sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i],
+                       UCODE_LOADER_API_VER);
+               status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
+               if (status) {
+                       wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
+                                 KBUILD_MODNAME, fw_name);
+                       return status;
+               }
+               sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i],
+                       UCODE_LOADER_API_VER);
+               status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
+               if (status) {
+                       wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
+                                 KBUILD_MODNAME, fw_name);
+                       return status;
+               }
+               wl->fw.hdr_num_entries[i] =
+                   wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr));
+       }
+       wl->fw.fw_cnt = i;
+       status = brcms_ucode_data_init(wl, &wl->ucode);
+       brcms_release_fw(wl);
+       return status;
+}
+
 static void brcms_ops_tx(struct ieee80211_hw *hw,
                         struct ieee80211_tx_control *control,
                         struct sk_buff *skb)
@@ -306,6 +430,14 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
        if (!blocked)
                wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
 
+       if (!wl->ucode.bcm43xx_bomminor) {
+               err = brcms_request_fw(wl, wl->wlc->hw->d11core);
+               if (err) {
+                       brcms_remove(wl->wlc->hw->d11core);
+                       return -ENOENT;
+               }
+       }
+
        spin_lock_bh(&wl->lock);
        /* avoid acknowledging frames before a non-monitor device is added */
        wl->mute_tx = true;
@@ -793,128 +925,6 @@ void brcms_dpc(unsigned long data)
        wake_up(&wl->tx_flush_wq);
 }
 
-/*
- * Precondition: Since this function is called in brcms_pci_probe() context,
- * no locking is required.
- */
-static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev)
-{
-       int status;
-       struct device *device = &pdev->dev;
-       char fw_name[100];
-       int i;
-
-       memset(&wl->fw, 0, sizeof(struct brcms_firmware));
-       for (i = 0; i < MAX_FW_IMAGES; i++) {
-               if (brcms_firmwares[i] == NULL)
-                       break;
-               sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i],
-                       UCODE_LOADER_API_VER);
-               status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
-               if (status) {
-                       wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
-                                 KBUILD_MODNAME, fw_name);
-                       return status;
-               }
-               sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i],
-                       UCODE_LOADER_API_VER);
-               status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
-               if (status) {
-                       wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
-                                 KBUILD_MODNAME, fw_name);
-                       return status;
-               }
-               wl->fw.hdr_num_entries[i] =
-                   wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr));
-       }
-       wl->fw.fw_cnt = i;
-       return brcms_ucode_data_init(wl, &wl->ucode);
-}
-
-/*
- * Precondition: Since this function is called in brcms_pci_probe() context,
- * no locking is required.
- */
-static void brcms_release_fw(struct brcms_info *wl)
-{
-       int i;
-       for (i = 0; i < MAX_FW_IMAGES; i++) {
-               release_firmware(wl->fw.fw_bin[i]);
-               release_firmware(wl->fw.fw_hdr[i]);
-       }
-}
-
-/**
- * This function frees the WL per-device resources.
- *
- * This function frees resources owned by the WL device pointed to
- * by the wl parameter.
- *
- * precondition: can both be called locked and unlocked
- *
- */
-static void brcms_free(struct brcms_info *wl)
-{
-       struct brcms_timer *t, *next;
-
-       /* free ucode data */
-       if (wl->fw.fw_cnt)
-               brcms_ucode_data_free(&wl->ucode);
-       if (wl->irq)
-               free_irq(wl->irq, wl);
-
-       /* kill dpc */
-       tasklet_kill(&wl->tasklet);
-
-       if (wl->pub) {
-               brcms_debugfs_detach(wl->pub);
-               brcms_c_module_unregister(wl->pub, "linux", wl);
-       }
-
-       /* free common resources */
-       if (wl->wlc) {
-               brcms_c_detach(wl->wlc);
-               wl->wlc = NULL;
-               wl->pub = NULL;
-       }
-
-       /* virtual interface deletion is deferred so we cannot spinwait */
-
-       /* wait for all pending callbacks to complete */
-       while (atomic_read(&wl->callbacks) > 0)
-               schedule();
-
-       /* free timers */
-       for (t = wl->timers; t; t = next) {
-               next = t->next;
-#ifdef DEBUG
-               kfree(t->name);
-#endif
-               kfree(t);
-       }
-}
-
-/*
-* called from both kernel as from this kernel module (error flow on attach)
-* precondition: perimeter lock is not acquired.
-*/
-static void brcms_remove(struct bcma_device *pdev)
-{
-       struct ieee80211_hw *hw = bcma_get_drvdata(pdev);
-       struct brcms_info *wl = hw->priv;
-
-       if (wl->wlc) {
-               wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
-               wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
-               ieee80211_unregister_hw(hw);
-       }
-
-       brcms_free(wl);
-
-       bcma_set_drvdata(pdev, NULL);
-       ieee80211_free_hw(hw);
-}
-
 static irqreturn_t brcms_isr(int irq, void *dev_id)
 {
        struct brcms_info *wl;
@@ -1047,18 +1057,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
        spin_lock_init(&wl->lock);
        spin_lock_init(&wl->isr_lock);
 
-       /* prepare ucode */
-       if (brcms_request_fw(wl, pdev) < 0) {
-               wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in "
-                         "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm");
-               brcms_release_fw(wl);
-               brcms_remove(pdev);
-               return NULL;
-       }
-
        /* common load-time initialization */
        wl->wlc = brcms_c_attach((void *)wl, pdev, unit, false, &err);
-       brcms_release_fw(wl);
        if (!wl->wlc) {
                wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n",
                          KBUILD_MODNAME, err);
index 89e9d3a..56cd01c 100644 (file)
@@ -709,17 +709,4 @@ static struct pcmcia_driver hostap_driver = {
        .suspend        = hostap_cs_suspend,
        .resume         = hostap_cs_resume,
 };
-
-static int __init init_prism2_pccard(void)
-{
-       return pcmcia_register_driver(&hostap_driver);
-}
-
-static void __exit exit_prism2_pccard(void)
-{
-       pcmcia_unregister_driver(&hostap_driver);
-}
-
-
-module_init(init_prism2_pccard);
-module_exit(exit_prism2_pccard);
+module_pcmcia_driver(hostap_driver);
index 16beaf3..c94dd68 100644 (file)
@@ -999,7 +999,6 @@ static const struct pcmcia_device_id if_cs_ids[] = {
 };
 MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
 
-
 static struct pcmcia_driver lbs_driver = {
        .owner          = THIS_MODULE,
        .name           = DRV_NAME,
@@ -1007,26 +1006,4 @@ static struct pcmcia_driver lbs_driver = {
        .remove         = if_cs_detach,
        .id_table       = if_cs_ids,
 };
-
-
-static int __init if_cs_init(void)
-{
-       int ret;
-
-       lbs_deb_enter(LBS_DEB_CS);
-       ret = pcmcia_register_driver(&lbs_driver);
-       lbs_deb_leave(LBS_DEB_CS);
-       return ret;
-}
-
-
-static void __exit if_cs_exit(void)
-{
-       lbs_deb_enter(LBS_DEB_CS);
-       pcmcia_unregister_driver(&lbs_driver);
-       lbs_deb_leave(LBS_DEB_CS);
-}
-
-
-module_init(if_cs_init);
-module_exit(if_cs_exit);
+module_pcmcia_driver(lbs_driver);
index d7dbc00..d21d959 100644 (file)
@@ -338,18 +338,4 @@ static struct pcmcia_driver orinoco_driver = {
        .suspend        = orinoco_cs_suspend,
        .resume         = orinoco_cs_resume,
 };
-
-static int __init
-init_orinoco_cs(void)
-{
-       return pcmcia_register_driver(&orinoco_driver);
-}
-
-static void __exit
-exit_orinoco_cs(void)
-{
-       pcmcia_unregister_driver(&orinoco_driver);
-}
-
-module_init(init_orinoco_cs);
-module_exit(exit_orinoco_cs);
+module_pcmcia_driver(orinoco_driver);
index 6e28ee4..e2264bc 100644 (file)
@@ -318,18 +318,4 @@ static struct pcmcia_driver orinoco_driver = {
        .resume         = spectrum_cs_resume,
        .id_table       = spectrum_cs_ids,
 };
-
-static int __init
-init_spectrum_cs(void)
-{
-       return pcmcia_register_driver(&orinoco_driver);
-}
-
-static void __exit
-exit_spectrum_cs(void)
-{
-       pcmcia_unregister_driver(&orinoco_driver);
-}
-
-module_init(init_spectrum_cs);
-module_exit(exit_spectrum_cs);
+module_pcmcia_driver(orinoco_driver);
index 730186d..38d2089 100644 (file)
@@ -2013,19 +2013,7 @@ static struct pcmcia_driver wl3501_driver = {
        .suspend        = wl3501_suspend,
        .resume         = wl3501_resume,
 };
-
-static int __init wl3501_init_module(void)
-{
-       return pcmcia_register_driver(&wl3501_driver);
-}
-
-static void __exit wl3501_exit_module(void)
-{
-       pcmcia_unregister_driver(&wl3501_driver);
-}
-
-module_init(wl3501_init_module);
-module_exit(wl3501_exit_module);
+module_pcmcia_driver(wl3501_driver);
 
 MODULE_AUTHOR("Fox Chen <mhchen@golf.ccl.itri.org.tw>, "
              "Arnaldo Carvalho de Melo <acme@conectiva.com.br>,"
index ee78e0e..09503b8 100644 (file)
@@ -244,20 +244,7 @@ static struct platform_driver amiga_parallel_driver = {
        },
 };
 
-static int __init amiga_parallel_init(void)
-{
-       return platform_driver_probe(&amiga_parallel_driver,
-                                    amiga_parallel_probe);
-}
-
-module_init(amiga_parallel_init);
-
-static void __exit amiga_parallel_exit(void)
-{
-       platform_driver_unregister(&amiga_parallel_driver);
-}
-
-module_exit(amiga_parallel_exit);
+module_platform_driver_probe(amiga_parallel_driver, amiga_parallel_probe);
 
 MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
 MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
index 067ad51..e9b52e4 100644 (file)
@@ -193,16 +193,4 @@ static struct pcmcia_driver parport_cs_driver = {
        .remove         = parport_detach,
        .id_table       = parport_ids,
 };
-
-static int __init init_parport_cs(void)
-{
-       return pcmcia_register_driver(&parport_cs_driver);
-}
-
-static void __exit exit_parport_cs(void)
-{
-       pcmcia_unregister_driver(&parport_cs_driver);
-}
-
-module_init(init_parport_cs);
-module_exit(exit_parport_cs);
+module_pcmcia_driver(parport_cs_driver);
index 050773c..a5251cb 100644 (file)
@@ -246,14 +246,14 @@ struct parport *parport_gsc_probe_port(unsigned long base,
                printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
                return NULL;
        }
-       ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
+       ops = kmemdup(&parport_gsc_ops, sizeof(struct parport_operations),
+                     GFP_KERNEL);
        if (!ops) {
                printk (KERN_DEBUG "parport (0x%lx): no memory for ops!\n",
                        base);
                kfree (priv);
                return NULL;
        }
-       memcpy (ops, &parport_gsc_ops, sizeof (struct parport_operations));
        priv->ctr = 0xc;
        priv->ctr_writable = 0xff;
        priv->dma_buf = 0;
index 5c4b6a1..dffd6d0 100644 (file)
@@ -284,12 +284,11 @@ static int bpp_probe(struct platform_device *op)
        size = resource_size(&op->resource[0]);
        dma = PARPORT_DMA_NONE;
 
-       ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
+       ops = kmemdup(&parport_sunbpp_ops, sizeof(struct parport_operations),
+                     GFP_KERNEL);
         if (!ops)
                goto out_unmap;
 
-        memcpy (ops, &parport_sunbpp_ops, sizeof(struct parport_operations));
-
        dprintk(("register_port\n"));
        if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
                goto out_free_ops;
index 3f56bc0..92ed045 100644 (file)
@@ -476,10 +476,9 @@ int parport_proc_register(struct parport *port)
        struct parport_sysctl_table *t;
        int i;
 
-       t = kmalloc(sizeof(*t), GFP_KERNEL);
+       t = kmemdup(&parport_sysctl_template, sizeof(*t), GFP_KERNEL);
        if (t == NULL)
                return -ENOMEM;
-       memcpy(t, &parport_sysctl_template, sizeof(*t));
 
        t->device_dir[0].extra1 = port;
 
@@ -523,10 +522,9 @@ int parport_device_proc_register(struct pardevice *device)
        struct parport_device_sysctl_table *t;
        struct parport * port = device->port;
        
-       t = kmalloc(sizeof(*t), GFP_KERNEL);
+       t = kmemdup(&parport_device_sysctl_template, sizeof(*t), GFP_KERNEL);
        if (t == NULL)
                return -ENOMEM;
-       memcpy(t, &parport_device_sysctl_template, sizeof(*t));
 
        t->dev_dir[0].child = t->parport_dir;
        t->parport_dir[0].child = t->port_dir;
index 8647dc6..748f8f3 100644 (file)
@@ -202,20 +202,16 @@ void pci_bus_add_devices(const struct pci_bus *bus)
                if (dev->is_added)
                        continue;
                retval = pci_bus_add_device(dev);
+               if (retval)
+                       dev_err(&dev->dev, "Error adding device (%d)\n",
+                               retval);
        }
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                BUG_ON(!dev->is_added);
-
                child = dev->subordinate;
-
-               if (!child)
-                       continue;
-               pci_bus_add_devices(child);
-
-               if (child->is_added)
-                       continue;
-               child->is_added = 1;
+               if (child)
+                       pci_bus_add_devices(child);
        }
 }
 
index 13e9e63..9fcb87f 100644 (file)
@@ -52,15 +52,12 @@ config HOTPLUG_PCI_IBM
          When in doubt, say N.
 
 config HOTPLUG_PCI_ACPI
-       tristate "ACPI PCI Hotplug driver"
-       depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK)
+       bool "ACPI PCI Hotplug driver"
+       depends on HOTPLUG_PCI=y && ((!ACPI_DOCK && ACPI) || (ACPI_DOCK))
        help
          Say Y here if you have a system that supports PCI Hotplug using
          ACPI.
 
-         To compile this driver as a module, choose M here: the
-         module will be called acpiphp.
-
          When in doubt, say N.
 
 config HOTPLUG_PCI_ACPI_IBM
index b70ac00..6fdd49c 100644 (file)
@@ -73,8 +73,9 @@ static inline const char *slot_name(struct slot *slot)
  */
 struct acpiphp_bridge {
        struct list_head list;
+       struct list_head slots;
+       struct kref ref;
        acpi_handle handle;
-       struct acpiphp_slot *slots;
 
        /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
        struct acpiphp_func *func;
@@ -97,7 +98,7 @@ struct acpiphp_bridge {
  * PCI slot information for each *physical* PCI slot
  */
 struct acpiphp_slot {
-       struct acpiphp_slot *next;
+       struct list_head node;
        struct acpiphp_bridge *bridge;  /* parent */
        struct list_head funcs;         /* one slot may have different
                                           objects (i.e. for each function) */
@@ -119,7 +120,6 @@ struct acpiphp_slot {
  */
 struct acpiphp_func {
        struct acpiphp_slot *slot;      /* parent */
-       struct acpiphp_bridge *bridge;  /* Ejectable PCI-to-PCI bridge */
 
        struct list_head sibling;
        struct notifier_block nb;
@@ -146,10 +146,6 @@ struct acpiphp_attention_info
 #define ACPI_PCI_HOST_HID              "PNP0A03"
 
 /* ACPI _STA method value (ignore bit 4; battery present) */
-#define ACPI_STA_PRESENT               (0x00000001)
-#define ACPI_STA_ENABLED               (0x00000002)
-#define ACPI_STA_SHOW_IN_UI            (0x00000004)
-#define ACPI_STA_FUNCTIONING           (0x00000008)
 #define ACPI_STA_ALL                   (0x0000000f)
 
 /* bridge flags */
@@ -174,25 +170,24 @@ struct acpiphp_attention_info
 /* function prototypes */
 
 /* acpiphp_core.c */
-extern int acpiphp_register_attention(struct acpiphp_attention_info*info);
-extern int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
-extern int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot);
-extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
+int acpiphp_register_attention(struct acpiphp_attention_info*info);
+int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
+int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot);
+void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
 
 /* acpiphp_glue.c */
-extern int acpiphp_glue_init (void);
-extern void acpiphp_glue_exit (void);
 typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
 
-extern int acpiphp_enable_slot (struct acpiphp_slot *slot);
-extern int acpiphp_disable_slot (struct acpiphp_slot *slot);
-extern int acpiphp_eject_slot (struct acpiphp_slot *slot);
-extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot);
-extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot);
-extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
-extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
+int acpiphp_enable_slot(struct acpiphp_slot *slot);
+int acpiphp_disable_slot(struct acpiphp_slot *slot);
+int acpiphp_eject_slot(struct acpiphp_slot *slot);
+u8 acpiphp_get_power_status(struct acpiphp_slot *slot);
+u8 acpiphp_get_attention_status(struct acpiphp_slot *slot);
+u8 acpiphp_get_latch_status(struct acpiphp_slot *slot);
+u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot);
 
 /* variables */
 extern bool acpiphp_debug;
+extern bool acpiphp_disabled;
 
 #endif /* _ACPIPHP_H */
index c2fd309..ca81279 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/pci-acpi.h>
 #include <linux/pci_hotplug.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
@@ -48,6 +49,7 @@
 #define SLOT_NAME_SIZE  21              /* {_SUN} */
 
 bool acpiphp_debug;
+bool acpiphp_disabled;
 
 /* local variables */
 static struct acpiphp_attention_info *attention_info;
@@ -60,7 +62,9 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+MODULE_PARM_DESC(disable, "disable acpiphp driver");
 module_param_named(debug, acpiphp_debug, bool, 0644);
+module_param_named(disable, acpiphp_disabled, bool, 0444);
 
 /* export the attention callback registration methods */
 EXPORT_SYMBOL_GPL(acpiphp_register_attention);
@@ -351,27 +355,9 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
 }
 
 
-static int __init acpiphp_init(void)
+void __init acpiphp_init(void)
 {
-       info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
-
-       if (acpi_pci_disabled)
-               return 0;
-
-       /* read all the ACPI info from the system */
-       /* initialize internal data structure etc. */
-       return acpiphp_glue_init();
-}
-
-
-static void __exit acpiphp_exit(void)
-{
-       if (acpi_pci_disabled)
-               return;
-
-       /* deallocate internal data structures etc. */
-       acpiphp_glue_exit();
+       info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n",
+               acpiphp_disabled ? ", disabled by user; please report a bug"
+                                : "");
 }
-
-module_init(acpiphp_init);
-module_exit(acpiphp_exit);
index 270fdba..96fed19 100644 (file)
@@ -54,6 +54,7 @@
 #include "acpiphp.h"
 
 static LIST_HEAD(bridge_list);
+static DEFINE_MUTEX(bridge_mutex);
 
 #define MY_NAME "acpiphp_glue"
 
@@ -61,6 +62,7 @@ static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
 static void acpiphp_sanitize_bus(struct pci_bus *bus);
 static void acpiphp_set_hpp_values(struct pci_bus *bus);
 static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
+static void free_bridge(struct kref *kref);
 
 /* callback routine to check for the existence of a pci dock device */
 static acpi_status
@@ -76,6 +78,39 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
        }
 }
 
+static inline void get_bridge(struct acpiphp_bridge *bridge)
+{
+       kref_get(&bridge->ref);
+}
+
+static inline void put_bridge(struct acpiphp_bridge *bridge)
+{
+       kref_put(&bridge->ref, free_bridge);
+}
+
+static void free_bridge(struct kref *kref)
+{
+       struct acpiphp_bridge *bridge;
+       struct acpiphp_slot *slot, *next;
+       struct acpiphp_func *func, *tmp;
+
+       bridge = container_of(kref, struct acpiphp_bridge, ref);
+
+       list_for_each_entry_safe(slot, next, &bridge->slots, node) {
+               list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
+                       kfree(func);
+               }
+               kfree(slot);
+       }
+
+       /* Release reference acquired by acpiphp_bridge_handle_to_function() */
+       if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)
+               put_bridge(bridge->func->slot->bridge);
+       put_device(&bridge->pci_bus->dev);
+       pci_dev_put(bridge->pci_dev);
+       kfree(bridge);
+}
+
 /*
  * the _DCK method can do funny things... and sometimes not
  * hah-hah funny.
@@ -154,9 +189,10 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        acpi_handle tmp;
        acpi_status status = AE_OK;
        unsigned long long adr, sun;
-       int device, function, retval;
+       int device, function, retval, found = 0;
        struct pci_bus *pbus = bridge->pci_bus;
        struct pci_dev *pdev;
+       u32 val;
 
        if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
                return AE_OK;
@@ -170,7 +206,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        device = (adr >> 16) & 0xffff;
        function = adr & 0xffff;
 
-       pdev = pbus->self;
+       pdev = bridge->pci_dev;
        if (pdev && device_is_managed_by_native_pciehp(pdev))
                return AE_OK;
 
@@ -178,7 +214,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        if (!newfunc)
                return AE_NO_MEMORY;
 
-       INIT_LIST_HEAD(&newfunc->sibling);
        newfunc->handle = handle;
        newfunc->function = function;
 
@@ -207,14 +242,15 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        }
 
        /* search for objects that share the same slot */
-       for (slot = bridge->slots; slot; slot = slot->next)
+       list_for_each_entry(slot, &bridge->slots, node)
                if (slot->device == device) {
                        if (slot->sun != sun)
                                warn("sibling found, but _SUN doesn't match!\n");
+                       found = 1;
                        break;
                }
 
-       if (!slot) {
+       if (!found) {
                slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
                if (!slot) {
                        kfree(newfunc);
@@ -227,9 +263,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
                INIT_LIST_HEAD(&slot->funcs);
                mutex_init(&slot->crit_sect);
 
-               slot->next = bridge->slots;
-               bridge->slots = slot;
-
+               mutex_lock(&bridge_mutex);
+               list_add_tail(&slot->node, &bridge->slots);
+               mutex_unlock(&bridge_mutex);
                bridge->nr_slots++;
 
                dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
@@ -247,13 +283,13 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        }
 
        newfunc->slot = slot;
+       mutex_lock(&bridge_mutex);
        list_add_tail(&newfunc->sibling, &slot->funcs);
+       mutex_unlock(&bridge_mutex);
 
-       pdev = pci_get_slot(pbus, PCI_DEVFN(device, function));
-       if (pdev) {
+       if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function),
+                                      &val, 60*1000))
                slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
-               pci_dev_put(pdev);
-       }
 
        if (is_dock_device(handle)) {
                /* we don't want to call this device's _EJ0
@@ -290,7 +326,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
 
  err_exit:
        bridge->nr_slots--;
-       bridge->slots = slot->next;
+       mutex_lock(&bridge_mutex);
+       list_del(&slot->node);
+       mutex_unlock(&bridge_mutex);
        kfree(slot);
        kfree(newfunc);
 
@@ -315,13 +353,17 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
        acpi_status status;
 
        /* must be added to the list prior to calling register_slot */
+       mutex_lock(&bridge_mutex);
        list_add(&bridge->list, &bridge_list);
+       mutex_unlock(&bridge_mutex);
 
        /* register all slot objects under this bridge */
        status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
                                     register_slot, NULL, bridge, NULL);
        if (ACPI_FAILURE(status)) {
+               mutex_lock(&bridge_mutex);
                list_del(&bridge->list);
+               mutex_unlock(&bridge_mutex);
                return;
        }
 
@@ -351,178 +393,46 @@ static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle
 {
        struct acpiphp_bridge *bridge;
        struct acpiphp_slot *slot;
-       struct acpiphp_func *func;
+       struct acpiphp_func *func = NULL;
 
+       mutex_lock(&bridge_mutex);
        list_for_each_entry(bridge, &bridge_list, list) {
-               for (slot = bridge->slots; slot; slot = slot->next) {
+               list_for_each_entry(slot, &bridge->slots, node) {
                        list_for_each_entry(func, &slot->funcs, sibling) {
-                               if (func->handle == handle)
+                               if (func->handle == handle) {
+                                       get_bridge(func->slot->bridge);
+                                       mutex_unlock(&bridge_mutex);
                                        return func;
+                               }
                        }
                }
        }
+       mutex_unlock(&bridge_mutex);
 
        return NULL;
 }
 
 
-static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge)
-{
-       acpi_handle dummy_handle;
-       struct acpiphp_func *func;
-
-       if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
-                                       "_EJ0", &dummy_handle))) {
-               bridge->flags |= BRIDGE_HAS_EJ0;
-
-               dbg("found ejectable p2p bridge\n");
-
-               /* make link between PCI bridge and PCI function */
-               func = acpiphp_bridge_handle_to_function(bridge->handle);
-               if (!func)
-                       return;
-               bridge->func = func;
-               func->bridge = bridge;
-       }
-}
-
-
-/* allocate and initialize host bridge data structure */
-static void add_host_bridge(struct acpi_pci_root *root)
-{
-       struct acpiphp_bridge *bridge;
-       acpi_handle handle = root->device->handle;
-
-       bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
-       if (bridge == NULL)
-               return;
-
-       bridge->handle = handle;
-
-       bridge->pci_bus = root->bus;
-
-       init_bridge_misc(bridge);
-}
-
-
-/* allocate and initialize PCI-to-PCI bridge data structure */
-static void add_p2p_bridge(acpi_handle *handle)
-{
-       struct acpiphp_bridge *bridge;
-
-       bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
-       if (bridge == NULL) {
-               err("out of memory\n");
-               return;
-       }
-
-       bridge->handle = handle;
-       config_p2p_bridge_flags(bridge);
-
-       bridge->pci_dev = acpi_get_pci_dev(handle);
-       bridge->pci_bus = bridge->pci_dev->subordinate;
-       if (!bridge->pci_bus) {
-               err("This is not a PCI-to-PCI bridge!\n");
-               goto err;
-       }
-
-       /*
-        * Grab a ref to the subordinate PCI bus in case the bus is
-        * removed via PCI core logical hotplug. The ref pins the bus
-        * (which we access during module unload).
-        */
-       get_device(&bridge->pci_bus->dev);
-
-       init_bridge_misc(bridge);
-       return;
- err:
-       pci_dev_put(bridge->pci_dev);
-       kfree(bridge);
-       return;
-}
-
-
-/* callback routine to find P2P bridges */
-static acpi_status
-find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-       acpi_status status;
-       struct pci_dev *dev;
-
-       dev = acpi_get_pci_dev(handle);
-       if (!dev || !dev->subordinate)
-               goto out;
-
-       /* check if this bridge has ejectable slots */
-       if ((detect_ejectable_slots(handle) > 0)) {
-               dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
-               add_p2p_bridge(handle);
-       }
-
-       /* search P2P bridges under this p2p bridge */
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    find_p2p_bridge, NULL, NULL, NULL);
-       if (ACPI_FAILURE(status))
-               warn("find_p2p_bridge failed (error code = 0x%x)\n", status);
-
- out:
-       pci_dev_put(dev);
-       return AE_OK;
-}
-
-
-/* find hot-pluggable slots, and then find P2P bridge */
-static int add_bridge(struct acpi_pci_root *root)
-{
-       acpi_status status;
-       unsigned long long tmp;
-       acpi_handle dummy_handle;
-       acpi_handle handle = root->device->handle;
-
-       /* if the bridge doesn't have _STA, we assume it is always there */
-       status = acpi_get_handle(handle, "_STA", &dummy_handle);
-       if (ACPI_SUCCESS(status)) {
-               status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
-               if (ACPI_FAILURE(status)) {
-                       dbg("%s: _STA evaluation failure\n", __func__);
-                       return 0;
-               }
-               if ((tmp & ACPI_STA_FUNCTIONING) == 0)
-                       /* don't register this object */
-                       return 0;
-       }
-
-       /* check if this bridge has ejectable slots */
-       if (detect_ejectable_slots(handle) > 0) {
-               dbg("found PCI host-bus bridge with hot-pluggable slots\n");
-               add_host_bridge(root);
-       }
-
-       /* search P2P bridges under this host bridge */
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                    find_p2p_bridge, NULL, NULL, NULL);
-
-       if (ACPI_FAILURE(status))
-               warn("find_p2p_bridge failed (error code = 0x%x)\n", status);
-
-       return 0;
-}
-
 static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
 {
        struct acpiphp_bridge *bridge;
 
+       mutex_lock(&bridge_mutex);
        list_for_each_entry(bridge, &bridge_list, list)
-               if (bridge->handle == handle)
+               if (bridge->handle == handle) {
+                       get_bridge(bridge);
+                       mutex_unlock(&bridge_mutex);
                        return bridge;
+               }
+       mutex_unlock(&bridge_mutex);
 
        return NULL;
 }
 
 static void cleanup_bridge(struct acpiphp_bridge *bridge)
 {
-       struct acpiphp_slot *slot, *next;
-       struct acpiphp_func *func, *tmp;
+       struct acpiphp_slot *slot;
+       struct acpiphp_func *func;
        acpi_status status;
        acpi_handle handle = bridge->handle;
 
@@ -543,10 +453,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
                        err("failed to install interrupt notify handler\n");
        }
 
-       slot = bridge->slots;
-       while (slot) {
-               next = slot->next;
-               list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
+       list_for_each_entry(slot, &bridge->slots, node) {
+               list_for_each_entry(func, &slot->funcs, sibling) {
                        if (is_dock_device(func->handle)) {
                                unregister_hotplug_dock_device(func->handle);
                                unregister_dock_notifier(&func->nb);
@@ -558,63 +466,13 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
                                if (ACPI_FAILURE(status))
                                        err("failed to remove notify handler\n");
                        }
-                       list_del(&func->sibling);
-                       kfree(func);
                }
                acpiphp_unregister_hotplug_slot(slot);
-               list_del(&slot->funcs);
-               kfree(slot);
-               slot = next;
        }
 
-       /*
-        * Only P2P bridges have a pci_dev
-        */
-       if (bridge->pci_dev)
-               put_device(&bridge->pci_bus->dev);
-
-       pci_dev_put(bridge->pci_dev);
+       mutex_lock(&bridge_mutex);
        list_del(&bridge->list);
-       kfree(bridge);
-}
-
-static acpi_status
-cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-       struct acpiphp_bridge *bridge;
-
-       /* cleanup p2p bridges under this P2P bridge
-          in a depth-first manner */
-       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                               cleanup_p2p_bridge, NULL, NULL, NULL);
-
-       bridge = acpiphp_handle_to_bridge(handle);
-       if (bridge)
-               cleanup_bridge(bridge);
-
-       return AE_OK;
-}
-
-static void remove_bridge(struct acpi_pci_root *root)
-{
-       struct acpiphp_bridge *bridge;
-       acpi_handle handle = root->device->handle;
-
-       /* cleanup p2p bridges under this host bridge
-          in a depth-first manner */
-       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-                               (u32)1, cleanup_p2p_bridge, NULL, NULL, NULL);
-
-       /*
-        * On root bridges with hotplug slots directly underneath (ie,
-        * no p2p bridge between), we call cleanup_bridge(). 
-        *
-        * The else clause cleans up root bridges that either had no
-        * hotplug slots at all, or had a p2p bridge underneath.
-        */
-       bridge = acpiphp_handle_to_bridge(handle);
-       if (bridge)
-               cleanup_bridge(bridge);
+       mutex_unlock(&bridge_mutex);
 }
 
 static int power_on_slot(struct acpiphp_slot *slot)
@@ -798,6 +656,7 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev)
                }
        }
 }
+
 /**
  * enable_device - enable, configure a slot
  * @slot: slot to be enabled
@@ -810,9 +669,7 @@ static int __ref enable_device(struct acpiphp_slot *slot)
        struct pci_dev *dev;
        struct pci_bus *bus = slot->bridge->pci_bus;
        struct acpiphp_func *func;
-       int retval = 0;
        int num, max, pass;
-       acpi_status status;
 
        if (slot->flags & SLOT_ENABLED)
                goto err_exit;
@@ -867,23 +724,11 @@ static int __ref enable_device(struct acpiphp_slot *slot)
                        slot->flags &= (~SLOT_ENABLED);
                        continue;
                }
-
-               if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
-                   dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) {
-                       pci_dev_put(dev);
-                       continue;
-               }
-
-               status = find_p2p_bridge(func->handle, (u32)1, bus, NULL);
-               if (ACPI_FAILURE(status))
-                       warn("find_p2p_bridge failed (error code = 0x%x)\n",
-                               status);
-               pci_dev_put(dev);
        }
 
 
  err_exit:
-       return retval;
+       return 0;
 }
 
 /* return first device in slot, acquiring a reference on it */
@@ -912,23 +757,6 @@ static int disable_device(struct acpiphp_slot *slot)
 {
        struct acpiphp_func *func;
        struct pci_dev *pdev;
-       struct pci_bus *bus = slot->bridge->pci_bus;
-
-       /* The slot will be enabled when func 0 is added, so check
-          func 0 before disable the slot. */
-       pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
-       if (!pdev)
-               goto err_exit;
-       pci_dev_put(pdev);
-
-       list_for_each_entry(func, &slot->funcs, sibling) {
-               if (func->bridge) {
-                       /* cleanup p2p bridges under this P2P bridge */
-                       cleanup_p2p_bridge(func->bridge->handle,
-                                               (u32)1, NULL, NULL);
-                       func->bridge = NULL;
-               }
-       }
 
        /*
         * enable_device() enumerates all functions in this device via
@@ -947,7 +775,6 @@ static int disable_device(struct acpiphp_slot *slot)
 
        slot->flags &= (~SLOT_ENABLED);
 
-err_exit:
        return 0;
 }
 
@@ -1037,7 +864,7 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
 
        enabled = disabled = 0;
 
-       for (slot = bridge->slots; slot; slot = slot->next) {
+       list_for_each_entry(slot, &bridge->slots, node) {
                unsigned int status = get_slot_status(slot);
                if (slot->flags & SLOT_ENABLED) {
                        if (status == ACPI_STA_ALL)
@@ -1082,11 +909,11 @@ static void acpiphp_set_hpp_values(struct pci_bus *bus)
  */
 static void acpiphp_sanitize_bus(struct pci_bus *bus)
 {
-       struct pci_dev *dev;
+       struct pci_dev *dev, *tmp;
        int i;
        unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
 
-       list_for_each_entry(dev, &bus->devices, bus_list) {
+       list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
                for (i=0; i<PCI_BRIDGE_RESOURCES; i++) {
                        struct resource *res = &dev->resource[i];
                        if ((res->flags & type_mask) && !res->start &&
@@ -1118,6 +945,7 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
                dbg("%s: re-enumerating slots under %s\n",
                        __func__, objname);
                acpiphp_check_bridge(bridge);
+               put_bridge(bridge);
        }
        return AE_OK ;
 }
@@ -1195,6 +1023,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
 
        acpi_scan_lock_release();
        kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
+       put_bridge(bridge);
 }
 
 /**
@@ -1208,6 +1037,8 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
 static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
                                        void *context)
 {
+       struct acpiphp_bridge *bridge = context;
+
        /*
         * Currently the code adds all hotplug events to the kacpid_wq
         * queue when it should add hotplug events to the kacpi_hotplug_wq.
@@ -1216,6 +1047,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
         * For now just re-add this work to the kacpi_hotplug_wq so we
         * don't deadlock on hotplug actions.
         */
+       get_bridge(bridge);
        alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge);
 }
 
@@ -1270,6 +1102,7 @@ static void _handle_hotplug_event_func(struct work_struct *work)
 
        acpi_scan_lock_release();
        kfree(hp_work); /* allocated in handle_hotplug_event_func */
+       put_bridge(func->slot->bridge);
 }
 
 /**
@@ -1283,6 +1116,8 @@ static void _handle_hotplug_event_func(struct work_struct *work)
 static void handle_hotplug_event_func(acpi_handle handle, u32 type,
                                      void *context)
 {
+       struct acpiphp_func *func = context;
+
        /*
         * Currently the code adds all hotplug events to the kacpid_wq
         * queue when it should add hotplug events to the kacpi_hotplug_wq.
@@ -1291,33 +1126,69 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type,
         * For now just re-add this work to the kacpi_hotplug_wq so we
         * don't deadlock on hotplug actions.
         */
+       get_bridge(func->slot->bridge);
        alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func);
 }
 
-static struct acpi_pci_driver acpi_pci_hp_driver = {
-       .add =          add_bridge,
-       .remove =       remove_bridge,
-};
-
-/**
- * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures
+/*
+ * Create hotplug slots for the PCI bus.
+ * It should always return 0 to avoid skipping following notifiers.
  */
-int __init acpiphp_glue_init(void)
+void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle)
 {
-       acpi_pci_register_driver(&acpi_pci_hp_driver);
+       acpi_handle dummy_handle;
+       struct acpiphp_bridge *bridge;
 
-       return 0;
-}
+       if (acpiphp_disabled)
+               return;
 
+       if (detect_ejectable_slots(handle) <= 0)
+               return;
 
-/**
- * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures
- *
- * This function frees all data allocated in acpiphp_glue_init().
- */
-void  acpiphp_glue_exit(void)
+       bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
+       if (bridge == NULL) {
+               err("out of memory\n");
+               return;
+       }
+
+       INIT_LIST_HEAD(&bridge->slots);
+       kref_init(&bridge->ref);
+       bridge->handle = handle;
+       bridge->pci_dev = pci_dev_get(bus->self);
+       bridge->pci_bus = bus;
+
+       /*
+        * Grab a ref to the subordinate PCI bus in case the bus is
+        * removed via PCI core logical hotplug. The ref pins the bus
+        * (which we access during module unload).
+        */
+       get_device(&bus->dev);
+
+       if (!pci_is_root_bus(bridge->pci_bus) &&
+           ACPI_SUCCESS(acpi_get_handle(bridge->handle,
+                                       "_EJ0", &dummy_handle))) {
+               dbg("found ejectable p2p bridge\n");
+               bridge->flags |= BRIDGE_HAS_EJ0;
+               bridge->func = acpiphp_bridge_handle_to_function(handle);
+       }
+
+       init_bridge_misc(bridge);
+}
+
+/* Destroy hotplug slots associated with the PCI bus */
+void acpiphp_remove_slots(struct pci_bus *bus)
 {
-       acpi_pci_unregister_driver(&acpi_pci_hp_driver);
+       struct acpiphp_bridge *bridge, *tmp;
+
+       if (acpiphp_disabled)
+               return;
+
+       list_for_each_entry_safe(bridge, tmp, &bridge_list, list)
+               if (bridge->pci_bus == bus) {
+                       cleanup_bridge(bridge);
+                       put_bridge(bridge);
+                       break;
+               }
 }
 
 /**
@@ -1396,7 +1267,7 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
 
        sta = get_slot_status(slot);
 
-       return (sta & ACPI_STA_SHOW_IN_UI) ? 0 : 1;
+       return (sta & ACPI_STA_DEVICE_UI) ? 0 : 1;
 }
 
 
index 9fff878..1356211 100644 (file)
@@ -75,28 +75,36 @@ static inline const char *slot_name(struct slot *slot)
        return hotplug_slot_name(slot->hotplug_slot);
 }
 
-extern int cpci_hp_register_controller(struct cpci_hp_controller *controller);
-extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller);
-extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last);
-extern int cpci_hp_unregister_bus(struct pci_bus *bus);
-extern int cpci_hp_start(void);
-extern int cpci_hp_stop(void);
+int cpci_hp_register_controller(struct cpci_hp_controller *controller);
+int cpci_hp_unregister_controller(struct cpci_hp_controller *controller);
+int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last);
+int cpci_hp_unregister_bus(struct pci_bus *bus);
+int cpci_hp_start(void);
+int cpci_hp_stop(void);
 
 /*
  * Internal function prototypes, these functions should not be used by
  * board/chassis drivers.
  */
-extern u8 cpci_get_attention_status(struct slot *slot);
-extern u8 cpci_get_latch_status(struct slot *slot);
-extern u8 cpci_get_adapter_status(struct slot *slot);
-extern u16 cpci_get_hs_csr(struct slot * slot);
-extern int cpci_set_attention_status(struct slot *slot, int status);
-extern int cpci_check_and_clear_ins(struct slot * slot);
-extern int cpci_check_ext(struct slot * slot);
-extern int cpci_clear_ext(struct slot * slot);
-extern int cpci_led_on(struct slot * slot);
-extern int cpci_led_off(struct slot * slot);
-extern int cpci_configure_slot(struct slot *slot);
-extern int cpci_unconfigure_slot(struct slot *slot);
+u8 cpci_get_attention_status(struct slot *slot);
+u8 cpci_get_latch_status(struct slot *slot);
+u8 cpci_get_adapter_status(struct slot *slot);
+u16 cpci_get_hs_csr(struct slot * slot);
+int cpci_set_attention_status(struct slot *slot, int status);
+int cpci_check_and_clear_ins(struct slot * slot);
+int cpci_check_ext(struct slot * slot);
+int cpci_clear_ext(struct slot * slot);
+int cpci_led_on(struct slot * slot);
+int cpci_led_off(struct slot * slot);
+int cpci_configure_slot(struct slot *slot);
+int cpci_unconfigure_slot(struct slot *slot);
+
+#ifdef CONFIG_HOTPLUG_PCI_CPCI
+int cpci_hotplug_init(int debug);
+void cpci_hotplug_exit(void);
+#else
+static inline int cpci_hotplug_init(int debug) { return 0; }
+static inline void cpci_hotplug_exit(void) { }
+#endif
 
 #endif /* _CPCI_HOTPLUG_H */
index d8ffc73..516b877 100644 (file)
@@ -404,50 +404,44 @@ struct resource_lists {
 
 
 /* debugfs functions for the hotplug controller info */
-extern void cpqhp_initialize_debugfs(void);
-extern void cpqhp_shutdown_debugfs(void);
-extern void cpqhp_create_debugfs_files(struct controller *ctrl);
-extern void cpqhp_remove_debugfs_files(struct controller *ctrl);
+void cpqhp_initialize_debugfs(void);
+void cpqhp_shutdown_debugfs(void);
+void cpqhp_create_debugfs_files(struct controller *ctrl);
+void cpqhp_remove_debugfs_files(struct controller *ctrl);
 
 /* controller functions */
-extern void cpqhp_pushbutton_thread(unsigned long event_pointer);
-extern irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data);
-extern int cpqhp_find_available_resources(struct controller *ctrl,
-                                         void __iomem *rom_start);
-extern int cpqhp_event_start_thread(void);
-extern void cpqhp_event_stop_thread(void);
-extern struct pci_func *cpqhp_slot_create(unsigned char busnumber);
-extern struct pci_func *cpqhp_slot_find(unsigned char bus, unsigned char device,
-                                       unsigned char index);
-extern int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func);
-extern int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func);
-extern int cpqhp_hardware_test(struct controller *ctrl, int test_num);
+void cpqhp_pushbutton_thread(unsigned long event_pointer);
+irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data);
+int cpqhp_find_available_resources(struct controller *ctrl,
+                                  void __iomem *rom_start);
+int cpqhp_event_start_thread(void);
+void cpqhp_event_stop_thread(void);
+struct pci_func *cpqhp_slot_create(unsigned char busnumber);
+struct pci_func *cpqhp_slot_find(unsigned char bus, unsigned char device,
+                                unsigned char index);
+int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func);
+int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func);
+int cpqhp_hardware_test(struct controller *ctrl, int test_num);
 
 /* resource functions */
-extern int     cpqhp_resource_sort_and_combine (struct pci_resource **head);
+int    cpqhp_resource_sort_and_combine (struct pci_resource **head);
 
 /* pci functions */
-extern int cpqhp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
-extern int cpqhp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num,
-                            u8 slot);
-extern int cpqhp_save_config(struct controller *ctrl, int busnumber,
-                            int is_hot_plug);
-extern int cpqhp_save_base_addr_length(struct controller *ctrl,
-                                      struct pci_func *func);
-extern int cpqhp_save_used_resources(struct controller *ctrl,
-                                    struct pci_func *func);
-extern int cpqhp_configure_board(struct controller *ctrl,
-                                struct pci_func *func);
-extern int cpqhp_save_slot_config(struct controller *ctrl,
-                                 struct pci_func *new_slot);
-extern int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func);
-extern void cpqhp_destroy_board_resources(struct pci_func *func);
-extern int cpqhp_return_board_resources        (struct pci_func *func,
-                                        struct resource_lists *resources);
-extern void cpqhp_destroy_resource_list(struct resource_lists *resources);
-extern int cpqhp_configure_device(struct controller *ctrl,
-                                 struct pci_func *func);
-extern int cpqhp_unconfigure_device(struct pci_func *func);
+int cpqhp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
+int cpqhp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num,
+                     u8 slot);
+int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug);
+int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func *func);
+int cpqhp_save_used_resources(struct controller *ctrl, struct pci_func *func);
+int cpqhp_configure_board(struct controller *ctrl, struct pci_func *func);
+int cpqhp_save_slot_config(struct controller *ctrl, struct pci_func *new_slot);
+int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func);
+void cpqhp_destroy_board_resources(struct pci_func *func);
+int cpqhp_return_board_resources(struct pci_func *func,
+                                struct resource_lists *resources);
+void cpqhp_destroy_resource_list(struct resource_lists *resources);
+int cpqhp_configure_device(struct controller *ctrl, struct pci_func *func);
+int cpqhp_unconfigure_device(struct pci_func *func);
 
 /* Global variables */
 extern int cpqhp_debug;
index e89c070..34e4e54 100644 (file)
 
 #ifndef CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM
 
-static inline void compaq_nvram_init (void __iomem *rom_start)
+static inline void compaq_nvram_init(void __iomem *rom_start)
 {
        return;
 }
 
-static inline int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
+static inline int compaq_nvram_load(void __iomem *rom_start, struct controller *ctrl)
 {
        return 0;
 }
 
-static inline int compaq_nvram_store (void __iomem *rom_start)
+static inline int compaq_nvram_store(void __iomem *rom_start)
 {
        return 0;
 }
 
 #else
 
-extern void compaq_nvram_init  (void __iomem *rom_start);
-extern int compaq_nvram_load   (void __iomem *rom_start, struct controller *ctrl);
-extern int compaq_nvram_store  (void __iomem *rom_start);
+void compaq_nvram_init(void __iomem *rom_start);
+int compaq_nvram_load(void __iomem *rom_start, struct controller *ctrl);
+int compaq_nvram_store(void __iomem *rom_start);
 
 #endif
 
index a8d391a..8c5b258 100644 (file)
@@ -275,17 +275,17 @@ extern struct list_head ibmphp_slot_head;
 * FUNCTION PROTOTYPES                                      *
 ***********************************************************/
 
-extern void ibmphp_free_ebda_hpc_queue (void);
-extern int ibmphp_access_ebda (void);
-extern struct slot *ibmphp_get_slot_from_physical_num (u8);
-extern int ibmphp_get_total_hp_slots (void);
-extern void ibmphp_free_ibm_slot (struct slot *);
-extern void ibmphp_free_bus_info_queue (void);
-extern void ibmphp_free_ebda_pci_rsrc_queue (void);
-extern struct bus_info *ibmphp_find_same_bus_num (u32);
-extern int ibmphp_get_bus_index (u8);
-extern u16 ibmphp_get_total_controllers (void);
-extern int ibmphp_register_pci (void);
+void ibmphp_free_ebda_hpc_queue(void);
+int ibmphp_access_ebda(void);
+struct slot *ibmphp_get_slot_from_physical_num(u8);
+int ibmphp_get_total_hp_slots(void);
+void ibmphp_free_ibm_slot(struct slot *);
+void ibmphp_free_bus_info_queue(void);
+void ibmphp_free_ebda_pci_rsrc_queue(void);
+struct bus_info *ibmphp_find_same_bus_num(u32);
+int ibmphp_get_bus_index(u8);
+u16 ibmphp_get_total_controllers(void);
+int ibmphp_register_pci(void);
 
 /* passed parameters */
 #define MEM            0
@@ -381,24 +381,24 @@ struct res_needed {
 
 /* functions */
 
-extern int ibmphp_rsrc_init (void);
-extern int ibmphp_add_resource (struct resource_node *);
-extern int ibmphp_remove_resource (struct resource_node *);
-extern int ibmphp_find_resource (struct bus_node *, u32, struct resource_node **, int);
-extern int ibmphp_check_resource (struct resource_node *, u8);
-extern int ibmphp_remove_bus (struct bus_node *, u8);
-extern void ibmphp_free_resources (void);
-extern int ibmphp_add_pfmem_from_mem (struct resource_node *);
-extern struct bus_node *ibmphp_find_res_bus (u8);
-extern void ibmphp_print_test (void);  /* for debugging purposes */
+int ibmphp_rsrc_init(void);
+int ibmphp_add_resource(struct resource_node *);
+int ibmphp_remove_resource(struct resource_node *);
+int ibmphp_find_resource(struct bus_node *, u32, struct resource_node **, int);
+int ibmphp_check_resource(struct resource_node *, u8);
+int ibmphp_remove_bus(struct bus_node *, u8);
+void ibmphp_free_resources(void);
+int ibmphp_add_pfmem_from_mem(struct resource_node *);
+struct bus_node *ibmphp_find_res_bus(u8);
+void ibmphp_print_test(void);  /* for debugging purposes */
 
-extern void ibmphp_hpc_initvars (void);
-extern int ibmphp_hpc_readslot (struct slot *, u8, u8 *);
-extern int ibmphp_hpc_writeslot (struct slot *, u8);
-extern void ibmphp_lock_operations (void);
-extern void ibmphp_unlock_operations (void);
-extern int ibmphp_hpc_start_poll_thread (void);
-extern void ibmphp_hpc_stop_poll_thread (void);
+void ibmphp_hpc_initvars(void);
+int ibmphp_hpc_readslot(struct slot *, u8, u8 *);
+int ibmphp_hpc_writeslot(struct slot *, u8);
+void ibmphp_lock_operations(void);
+void ibmphp_unlock_operations(void);
+int ibmphp_hpc_start_poll_thread(void);
+void ibmphp_hpc_stop_poll_thread(void);
 
 //----------------------------------------------------------------------------
 
@@ -749,11 +749,11 @@ struct controller {
 
 /* Functions */
 
-extern int ibmphp_init_devno (struct slot **); /* This function is called from EBDA, so we need it not be static */
-extern int ibmphp_do_disable_slot (struct slot *slot_cur);
-extern int ibmphp_update_slot_info (struct slot *);    /* This function is called from HPC, so we need it to not be be static */
-extern int ibmphp_configure_card (struct pci_func *, u8);
-extern int ibmphp_unconfigure_card (struct slot **, int);
+int ibmphp_init_devno(struct slot **); /* This function is called from EBDA, so we need it not be static */
+int ibmphp_do_disable_slot(struct slot *slot_cur);
+int ibmphp_update_slot_info(struct slot *);    /* This function is called from HPC, so we need it to not be be static */
+int ibmphp_configure_card(struct pci_func *, u8);
+int ibmphp_unconfigure_card(struct slot **, int);
 extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops;
 
 #endif                         //__IBMPHP_H
index 202f4a9..ec20f74 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/pci_hotplug.h>
 #include <asm/uaccess.h>
 #include "../pci.h"
+#include "cpci_hotplug.h"
 
 #define MY_NAME        "pci_hotplug"
 
@@ -63,14 +64,6 @@ static bool debug;
 static LIST_HEAD(pci_hotplug_slot_list);
 static DEFINE_MUTEX(pci_hp_mutex);
 
-#ifdef CONFIG_HOTPLUG_PCI_CPCI
-extern int cpci_hotplug_init(int debug);
-extern void cpci_hotplug_exit(void);
-#else
-static inline int cpci_hotplug_init(int debug) { return 0; }
-static inline void cpci_hotplug_exit(void) { }
-#endif
-
 /* Weee, fun with macros... */
 #define GET_STATUS(name,type)  \
 static int get_##name (struct hotplug_slot *slot, type *value)         \
@@ -524,13 +517,11 @@ int pci_hp_deregister(struct hotplug_slot *hotplug)
  *
  * Returns 0 if successful, anything else for an error.
  */
-int __must_check pci_hp_change_slot_info(struct hotplug_slot *hotplug,
-                                        struct hotplug_slot_info *info)
+int pci_hp_change_slot_info(struct hotplug_slot *hotplug,
+                           struct hotplug_slot_info *info)
 {
-       struct pci_slot *slot;
        if (!hotplug || !info)
                return -ENODEV;
-       slot = hotplug->pci_slot;
 
        memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info));
 
index 2c113de..7fb3269 100644 (file)
@@ -127,15 +127,15 @@ struct controller {
 #define NO_CMD_CMPL(ctrl)      ((ctrl)->slot_cap & PCI_EXP_SLTCAP_NCCS)
 #define PSN(ctrl)              ((ctrl)->slot_cap >> 19)
 
-extern int pciehp_sysfs_enable_slot(struct slot *slot);
-extern int pciehp_sysfs_disable_slot(struct slot *slot);
-extern u8 pciehp_handle_attention_button(struct slot *p_slot);
-extern u8 pciehp_handle_switch_change(struct slot *p_slot);
-extern u8 pciehp_handle_presence_change(struct slot *p_slot);
-extern u8 pciehp_handle_power_fault(struct slot *p_slot);
-extern int pciehp_configure_device(struct slot *p_slot);
-extern int pciehp_unconfigure_device(struct slot *p_slot);
-extern void pciehp_queue_pushbutton_work(struct work_struct *work);
+int pciehp_sysfs_enable_slot(struct slot *slot);
+int pciehp_sysfs_disable_slot(struct slot *slot);
+u8 pciehp_handle_attention_button(struct slot *p_slot);
+u8 pciehp_handle_switch_change(struct slot *p_slot);
+u8 pciehp_handle_presence_change(struct slot *p_slot);
+u8 pciehp_handle_power_fault(struct slot *p_slot);
+int pciehp_configure_device(struct slot *p_slot);
+int pciehp_unconfigure_device(struct slot *p_slot);
+void pciehp_queue_pushbutton_work(struct work_struct *work);
 struct controller *pcie_init(struct pcie_device *dev);
 int pcie_init_notification(struct controller *ctrl);
 int pciehp_enable_slot(struct slot *p_slot);
@@ -166,8 +166,8 @@ static inline const char *slot_name(struct slot *slot)
 #include <acpi/acpi_bus.h>
 #include <linux/pci-acpi.h>
 
-extern void __init pciehp_acpi_slot_detection_init(void);
-extern int pciehp_acpi_slot_detection_check(struct pci_dev *dev);
+void __init pciehp_acpi_slot_detection_init(void);
+int pciehp_acpi_slot_detection_check(struct pci_dev *dev);
 
 static inline void pciehp_firmware_init(void)
 {
index 24d709b..ead7c53 100644 (file)
@@ -90,7 +90,7 @@ static int __init dummy_probe(struct pcie_device *dev)
        slot = kzalloc(sizeof(*slot), GFP_KERNEL);
        if (!slot)
                return -ENOMEM;
-       slot->number = slot_cap >> 19;
+       slot->number = (slot_cap & PCI_EXP_SLTCAP_PSN) >> 19;
        list_for_each_entry(tmp, &dummy_slots, list) {
                if (tmp->number == slot->number)
                        dup_slot_id++;
index 4a0a59b..81df939 100644 (file)
 #ifndef _RPADLPAR_IO_H_
 #define _RPADLPAR_IO_H_
 
-extern int dlpar_sysfs_init(void);
-extern void dlpar_sysfs_exit(void);
+int dlpar_sysfs_init(void);
+void dlpar_sysfs_exit(void);
 
-extern int dlpar_add_slot(char *drc_name);
-extern int dlpar_remove_slot(char *drc_name);
+int dlpar_add_slot(char *drc_name);
+int dlpar_remove_slot(char *drc_name);
 
 #endif
index df56774..3135856 100644 (file)
@@ -86,18 +86,18 @@ extern struct list_head rpaphp_slot_head;
 /* function prototypes */
 
 /* rpaphp_pci.c */
-extern int rpaphp_enable_slot(struct slot *slot);
-extern int rpaphp_get_sensor_state(struct slot *slot, int *state);
+int rpaphp_enable_slot(struct slot *slot);
+int rpaphp_get_sensor_state(struct slot *slot, int *state);
 
 /* rpaphp_core.c */
-extern int rpaphp_add_slot(struct device_node *dn);
-extern int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
+int rpaphp_add_slot(struct device_node *dn);
+int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
                char **drc_name, char **drc_type, int *drc_power_domain);
 
 /* rpaphp_slot.c */
-extern void dealloc_slot_struct(struct slot *slot);
-extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain);
-extern int rpaphp_register_slot(struct slot *slot);
-extern int rpaphp_deregister_slot(struct slot *slot);
+void dealloc_slot_struct(struct slot *slot);
+struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain);
+int rpaphp_register_slot(struct slot *slot);
+int rpaphp_deregister_slot(struct slot *slot);
        
 #endif                         /* _PPC64PHP_H */
index 7db249a..46a7b73 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <linux/init.h>
+#include <asm/pci_debug.h>
 #include <asm/sclp.h>
 
 #define SLOT_NAME_SIZE 10
@@ -49,6 +50,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
                return -EIO;
 
        rc = sclp_pci_configure(slot->zdev->fid);
+       zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, rc);
        if (!rc) {
                slot->zdev->state = ZPCI_FN_STATE_CONFIGURED;
                /* automatically scan the device after is was configured */
@@ -66,16 +68,16 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
        if (!zpci_fn_configured(slot->zdev->state))
                return -EIO;
 
+       rc = zpci_disable_device(slot->zdev);
+       if (rc)
+               return rc;
        /* TODO: we rely on the user to unbind/remove the device, is that plausible
         *       or do we need to trigger that here?
         */
        rc = sclp_pci_deconfigure(slot->zdev->fid);
-       if (!rc) {
-               /* Fixme: better call List-PCI to find the disabled FH
-                  for the FID since the FH should be opaque... */
-               slot->zdev->fh &= 0x7fffffff;
+       zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, rc);
+       if (!rc)
                slot->zdev->state = ZPCI_FN_STATE_STANDBY;
-       }
        return rc;
 }
 
index b849f99..e260f20 100644 (file)
@@ -168,19 +168,19 @@ struct controller {
 #define WRONG_BUS_FREQUENCY            0x0000000D
 #define POWER_FAILURE                  0x0000000E
 
-extern int __must_check shpchp_create_ctrl_files(struct controller *ctrl);
-extern void shpchp_remove_ctrl_files(struct controller *ctrl);
-extern int shpchp_sysfs_enable_slot(struct slot *slot);
-extern int shpchp_sysfs_disable_slot(struct slot *slot);
-extern u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
-extern u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
-extern u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
-extern u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
-extern int shpchp_configure_device(struct slot *p_slot);
-extern int shpchp_unconfigure_device(struct slot *p_slot);
-extern void cleanup_slots(struct controller *ctrl);
-extern void shpchp_queue_pushbutton_work(struct work_struct *work);
-extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
+int __must_check shpchp_create_ctrl_files(struct controller *ctrl);
+void shpchp_remove_ctrl_files(struct controller *ctrl);
+int shpchp_sysfs_enable_slot(struct slot *slot);
+int shpchp_sysfs_disable_slot(struct slot *slot);
+u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
+u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
+u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
+u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
+int shpchp_configure_device(struct slot *p_slot);
+int shpchp_unconfigure_device(struct slot *p_slot);
+void cleanup_slots(struct controller *ctrl);
+void shpchp_queue_pushbutton_work(struct work_struct *work);
+int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
 
 static inline const char *slot_name(struct slot *slot)
 {
index eeb23ce..e8c31fe 100644 (file)
@@ -85,7 +85,7 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
 }
 static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL);
 
-int __must_check shpchp_create_ctrl_files (struct controller *ctrl)
+int shpchp_create_ctrl_files (struct controller *ctrl)
 {
        return device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl);
 }
index 00cc78c..d40bed7 100644 (file)
 #include <linux/slab.h>
 
 #include "pci.h"
-#include "msi.h"
 
 static int pci_msi_enable = 1;
 
+#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1)
+
+
 /* Arch hooks */
 
 #ifndef arch_msi_check_device
@@ -111,32 +113,26 @@ void default_restore_msi_irqs(struct pci_dev *dev, int irq)
 }
 #endif
 
-static void msi_set_enable(struct pci_dev *dev, int pos, int enable)
+static void msi_set_enable(struct pci_dev *dev, int enable)
 {
        u16 control;
 
-       BUG_ON(!pos);
-
-       pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
+       pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
        control &= ~PCI_MSI_FLAGS_ENABLE;
        if (enable)
                control |= PCI_MSI_FLAGS_ENABLE;
-       pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
+       pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
 }
 
 static void msix_set_enable(struct pci_dev *dev, int enable)
 {
-       int pos;
        u16 control;
 
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-       if (pos) {
-               pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
-               control &= ~PCI_MSIX_FLAGS_ENABLE;
-               if (enable)
-                       control |= PCI_MSIX_FLAGS_ENABLE;
-               pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
-       }
+       pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
+       control &= ~PCI_MSIX_FLAGS_ENABLE;
+       if (enable)
+               control |= PCI_MSIX_FLAGS_ENABLE;
+       pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
 }
 
 static inline __attribute_const__ u32 msi_mask(unsigned x)
@@ -247,18 +243,18 @@ void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
                msg->data = readl(base + PCI_MSIX_ENTRY_DATA);
        } else {
                struct pci_dev *dev = entry->dev;
-               int pos = entry->msi_attrib.pos;
+               int pos = dev->msi_cap;
                u16 data;
 
-               pci_read_config_dword(dev, msi_lower_address_reg(pos),
-                                       &msg->address_lo);
+               pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
+                                     &msg->address_lo);
                if (entry->msi_attrib.is_64) {
-                       pci_read_config_dword(dev, msi_upper_address_reg(pos),
-                                               &msg->address_hi);
-                       pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+                       pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
+                                             &msg->address_hi);
+                       pci_read_config_word(dev, pos + PCI_MSI_DATA_64, &data);
                } else {
                        msg->address_hi = 0;
-                       pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
+                       pci_read_config_word(dev, pos + PCI_MSI_DATA_32, &data);
                }
                msg->data = data;
        }
@@ -302,24 +298,24 @@ void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
                writel(msg->data, base + PCI_MSIX_ENTRY_DATA);
        } else {
                struct pci_dev *dev = entry->dev;
-               int pos = entry->msi_attrib.pos;
+               int pos = dev->msi_cap;
                u16 msgctl;
 
-               pci_read_config_word(dev, msi_control_reg(pos), &msgctl);
+               pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
                msgctl &= ~PCI_MSI_FLAGS_QSIZE;
                msgctl |= entry->msi_attrib.multiple << 4;
-               pci_write_config_word(dev, msi_control_reg(pos), msgctl);
+               pci_write_config_word(dev, pos + PCI_MSI_FLAGS, msgctl);
 
-               pci_write_config_dword(dev, msi_lower_address_reg(pos),
-                                       msg->address_lo);
+               pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
+                                      msg->address_lo);
                if (entry->msi_attrib.is_64) {
-                       pci_write_config_dword(dev, msi_upper_address_reg(pos),
-                                               msg->address_hi);
-                       pci_write_config_word(dev, msi_data_reg(pos, 1),
-                                               msg->data);
+                       pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
+                                              msg->address_hi);
+                       pci_write_config_word(dev, pos + PCI_MSI_DATA_64,
+                                             msg->data);
                } else {
-                       pci_write_config_word(dev, msi_data_reg(pos, 0),
-                                               msg->data);
+                       pci_write_config_word(dev, pos + PCI_MSI_DATA_32,
+                                             msg->data);
                }
        }
        entry->msg = *msg;
@@ -391,7 +387,6 @@ static void pci_intx_for_msi(struct pci_dev *dev, int enable)
 
 static void __pci_restore_msi_state(struct pci_dev *dev)
 {
-       int pos;
        u16 control;
        struct msi_desc *entry;
 
@@ -399,22 +394,20 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
                return;
 
        entry = irq_get_msi_desc(dev->irq);
-       pos = entry->msi_attrib.pos;
 
        pci_intx_for_msi(dev, 0);
-       msi_set_enable(dev, pos, 0);
+       msi_set_enable(dev, 0);
        arch_restore_msi_irqs(dev, dev->irq);
 
-       pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
+       pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
        msi_mask_irq(entry, msi_capable_mask(control), entry->masked);
        control &= ~PCI_MSI_FLAGS_QSIZE;
        control |= (entry->msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE;
-       pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
+       pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
 }
 
 static void __pci_restore_msix_state(struct pci_dev *dev)
 {
-       int pos;
        struct msi_desc *entry;
        u16 control;
 
@@ -422,13 +415,12 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
                return;
        BUG_ON(list_empty(&dev->msi_list));
        entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
-       pos = entry->msi_attrib.pos;
-       pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
+       pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
 
        /* route the table */
        pci_intx_for_msi(dev, 0);
        control |= PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL;
-       pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+       pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
 
        list_for_each_entry(entry, &dev->msi_list, list) {
                arch_restore_msi_irqs(dev, entry->irq);
@@ -436,7 +428,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
        }
 
        control &= ~PCI_MSIX_FLAGS_MASKALL;
-       pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+       pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
 }
 
 void pci_restore_msi_state(struct pci_dev *dev)
@@ -484,12 +476,12 @@ static struct msi_attribute mode_attribute =
        __ATTR(mode, S_IRUGO, show_msi_mode, NULL);
 
 
-struct attribute *msi_irq_default_attrs[] = {
+static struct attribute *msi_irq_default_attrs[] = {
        &mode_attribute.attr,
        NULL
 };
 
-void msi_kobj_release(struct kobject *kobj)
+static void msi_kobj_release(struct kobject *kobj)
 {
        struct msi_desc *entry = to_msi_desc(kobj);
 
@@ -552,27 +544,27 @@ out_unroll:
 static int msi_capability_init(struct pci_dev *dev, int nvec)
 {
        struct msi_desc *entry;
-       int pos, ret;
+       int ret;
        u16 control;
        unsigned mask;
 
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-       msi_set_enable(dev, pos, 0);    /* Disable MSI during set up */
+       msi_set_enable(dev, 0); /* Disable MSI during set up */
 
-       pci_read_config_word(dev, msi_control_reg(pos), &control);
+       pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
        /* MSI Entry Initialization */
        entry = alloc_msi_entry(dev);
        if (!entry)
                return -ENOMEM;
 
        entry->msi_attrib.is_msix       = 0;
-       entry->msi_attrib.is_64         = is_64bit_address(control);
+       entry->msi_attrib.is_64         = !!(control & PCI_MSI_FLAGS_64BIT);
        entry->msi_attrib.entry_nr      = 0;
-       entry->msi_attrib.maskbit       = is_mask_bit_support(control);
+       entry->msi_attrib.maskbit       = !!(control & PCI_MSI_FLAGS_MASKBIT);
        entry->msi_attrib.default_irq   = dev->irq;     /* Save IOAPIC IRQ */
-       entry->msi_attrib.pos           = pos;
+       entry->msi_attrib.pos           = dev->msi_cap;
 
-       entry->mask_pos = msi_mask_reg(pos, entry->msi_attrib.is_64);
+       entry->mask_pos = dev->msi_cap + (control & PCI_MSI_FLAGS_64BIT) ?
+               PCI_MSI_MASK_64 : PCI_MSI_MASK_32;
        /* All MSIs are unmasked by default, Mask them all */
        if (entry->msi_attrib.maskbit)
                pci_read_config_dword(dev, entry->mask_pos, &entry->masked);
@@ -598,31 +590,30 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
 
        /* Set MSI enabled bits  */
        pci_intx_for_msi(dev, 0);
-       msi_set_enable(dev, pos, 1);
+       msi_set_enable(dev, 1);
        dev->msi_enabled = 1;
 
        dev->irq = entry->irq;
        return 0;
 }
 
-static void __iomem *msix_map_region(struct pci_dev *dev, unsigned pos,
-                                                       unsigned nr_entries)
+static void __iomem *msix_map_region(struct pci_dev *dev, unsigned nr_entries)
 {
        resource_size_t phys_addr;
        u32 table_offset;
        u8 bir;
 
-       pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset);
-       bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
-       table_offset &= ~PCI_MSIX_FLAGS_BIRMASK;
+       pci_read_config_dword(dev, dev->msix_cap + PCI_MSIX_TABLE,
+                             &table_offset);
+       bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR);
+       table_offset &= PCI_MSIX_TABLE_OFFSET;
        phys_addr = pci_resource_start(dev, bir) + table_offset;
 
        return ioremap_nocache(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
 }
 
-static int msix_setup_entries(struct pci_dev *dev, unsigned pos,
-                               void __iomem *base, struct msix_entry *entries,
-                               int nvec)
+static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
+                             struct msix_entry *entries, int nvec)
 {
        struct msi_desc *entry;
        int i;
@@ -642,7 +633,7 @@ static int msix_setup_entries(struct pci_dev *dev, unsigned pos,
                entry->msi_attrib.is_64         = 1;
                entry->msi_attrib.entry_nr      = entries[i].entry;
                entry->msi_attrib.default_irq   = dev->irq;
-               entry->msi_attrib.pos           = pos;
+               entry->msi_attrib.pos           = dev->msix_cap;
                entry->mask_base                = base;
 
                list_add_tail(&entry->list, &dev->msi_list);
@@ -652,7 +643,7 @@ static int msix_setup_entries(struct pci_dev *dev, unsigned pos,
 }
 
 static void msix_program_entries(struct pci_dev *dev,
-                                       struct msix_entry *entries)
+                                struct msix_entry *entries)
 {
        struct msi_desc *entry;
        int i = 0;
@@ -682,23 +673,22 @@ static void msix_program_entries(struct pci_dev *dev,
 static int msix_capability_init(struct pci_dev *dev,
                                struct msix_entry *entries, int nvec)
 {
-       int pos, ret;
+       int ret;
        u16 control;
        void __iomem *base;
 
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-       pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
+       pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
 
        /* Ensure MSI-X is disabled while it is set up */
        control &= ~PCI_MSIX_FLAGS_ENABLE;
-       pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+       pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
 
        /* Request & Map MSI-X table region */
-       base = msix_map_region(dev, pos, multi_msix_capable(control));
+       base = msix_map_region(dev, msix_table_size(control));
        if (!base)
                return -ENOMEM;
 
-       ret = msix_setup_entries(dev, pos, base, entries, nvec);
+       ret = msix_setup_entries(dev, base, entries, nvec);
        if (ret)
                return ret;
 
@@ -712,7 +702,7 @@ static int msix_capability_init(struct pci_dev *dev,
         * interrupts coming in before they're fully set up.
         */
        control |= PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE;
-       pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+       pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
 
        msix_program_entries(dev, entries);
 
@@ -727,7 +717,7 @@ static int msix_capability_init(struct pci_dev *dev,
        dev->msix_enabled = 1;
 
        control &= ~PCI_MSIX_FLAGS_MASKALL;
-       pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+       pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
 
        return 0;
 
@@ -795,9 +785,6 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
        if (ret)
                return ret;
 
-       if (!pci_find_capability(dev, type))
-               return -EINVAL;
-
        return 0;
 }
 
@@ -816,13 +803,13 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
  */
 int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
 {
-       int status, pos, maxvec;
+       int status, maxvec;
        u16 msgctl;
 
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-       if (!pos)
+       if (!dev->msi_cap)
                return -EINVAL;
-       pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+
+       pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
        maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
        if (nvec > maxvec)
                return maxvec;
@@ -847,14 +834,13 @@ EXPORT_SYMBOL(pci_enable_msi_block);
 
 int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec)
 {
-       int ret, pos, nvec;
+       int ret, nvec;
        u16 msgctl;
 
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-       if (!pos)
+       if (!dev->msi_cap)
                return -EINVAL;
 
-       pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+       pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
        ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
 
        if (maxvec)
@@ -876,21 +862,19 @@ void pci_msi_shutdown(struct pci_dev *dev)
        struct msi_desc *desc;
        u32 mask;
        u16 ctrl;
-       unsigned pos;
 
        if (!pci_msi_enable || !dev || !dev->msi_enabled)
                return;
 
        BUG_ON(list_empty(&dev->msi_list));
        desc = list_first_entry(&dev->msi_list, struct msi_desc, list);
-       pos = desc->msi_attrib.pos;
 
-       msi_set_enable(dev, pos, 0);
+       msi_set_enable(dev, 0);
        pci_intx_for_msi(dev, 1);
        dev->msi_enabled = 0;
 
        /* Return the device with MSI unmasked as initial states */
-       pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &ctrl);
+       pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
        mask = msi_capable_mask(ctrl);
        /* Keep cached state to be restored */
        __msi_mask_irq(desc, mask, ~mask);
@@ -917,15 +901,13 @@ EXPORT_SYMBOL(pci_disable_msi);
  */
 int pci_msix_table_size(struct pci_dev *dev)
 {
-       int pos;
        u16 control;
 
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-       if (!pos)
+       if (!dev->msix_cap)
                return 0;
 
-       pci_read_config_word(dev, msi_control_reg(pos), &control);
-       return multi_msix_capable(control);
+       pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
+       return msix_table_size(control);
 }
 
 /**
@@ -948,7 +930,7 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
        int status, nr_entries;
        int i, j;
 
-       if (!entries)
+       if (!entries || !dev->msix_cap)
                return -EINVAL;
 
        status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX);
@@ -1048,15 +1030,17 @@ EXPORT_SYMBOL(pci_msi_enabled);
 
 void pci_msi_init_pci_dev(struct pci_dev *dev)
 {
-       int pos;
        INIT_LIST_HEAD(&dev->msi_list);
 
        /* Disable the msi hardware to avoid screaming interrupts
         * during boot.  This is the power on reset default so
         * usually this should be a noop.
         */
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-       if (pos)
-               msi_set_enable(dev, pos, 0);
-       msix_set_enable(dev, 0);
+       dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
+       if (dev->msi_cap)
+               msi_set_enable(dev, 0);
+
+       dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+       if (dev->msix_cap)
+               msix_set_enable(dev, 0);
 }
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
deleted file mode 100644 (file)
index 65c42f8..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef MSI_H
-#define MSI_H
-
-#define msi_control_reg(base)          (base + PCI_MSI_FLAGS)
-#define msi_lower_address_reg(base)    (base + PCI_MSI_ADDRESS_LO)
-#define msi_upper_address_reg(base)    (base + PCI_MSI_ADDRESS_HI)
-#define msi_data_reg(base, is64bit)    \
-       (base + ((is64bit == 1) ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32))
-#define msi_mask_reg(base, is64bit)    \
-       (base + ((is64bit == 1) ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32))
-#define is_64bit_address(control)      (!!(control & PCI_MSI_FLAGS_64BIT))
-#define is_mask_bit_support(control)   (!!(control & PCI_MSI_FLAGS_MASKBIT))
-
-#define msix_table_offset_reg(base)    (base + PCI_MSIX_TABLE)
-#define msix_pba_offset_reg(base)      (base + PCI_MSIX_PBA)
-#define msix_table_size(control)       ((control & PCI_MSIX_FLAGS_QSIZE)+1)
-#define multi_msix_capable(control)    msix_table_size((control))
-
-#endif /* MSI_H */
index 5147c21..e4b1fb2 100644 (file)
@@ -288,6 +288,32 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = {
        .run_wake = acpi_pci_run_wake,
 };
 
+void acpi_pci_add_bus(struct pci_bus *bus)
+{
+       acpi_handle handle = NULL;
+
+       if (bus->bridge)
+               handle = ACPI_HANDLE(bus->bridge);
+       if (acpi_pci_disabled || handle == NULL)
+               return;
+
+       acpi_pci_slot_enumerate(bus, handle);
+       acpiphp_enumerate_slots(bus, handle);
+}
+
+void acpi_pci_remove_bus(struct pci_bus *bus)
+{
+       /*
+        * bus->bridge->acpi_node.handle has already been reset to NULL
+        * when acpi_pci_remove_bus() is called, so don't check ACPI handle.
+        */
+       if (acpi_pci_disabled)
+               return;
+
+       acpiphp_remove_slots(bus);
+       acpi_pci_slot_remove(bus);
+}
+
 /* ACPI bus type */
 static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
 {
@@ -362,7 +388,11 @@ static int __init acpi_pci_init(void)
        ret = register_acpi_bus_type(&acpi_pci_bus);
        if (ret)
                return 0;
+
        pci_set_platform_pm(&acpi_pci_platform_pm);
+       acpi_pci_slot_init();
+       acpiphp_init();
+
        return 0;
 }
 arch_initcall(acpi_pci_init);
index 9c6e9bb..5b4a9d9 100644 (file)
@@ -897,7 +897,7 @@ int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
 
        if (pci_resource_len(pdev, resno) == 0)
                return 0;
-       nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+       nr = vma_pages(vma);
        start = vma->vm_pgoff;
        size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
        pci_start = (mmap_api == PCI_MMAP_PROCFS) ?
index b099e00..a899d8b 100644 (file)
@@ -646,15 +646,11 @@ static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
                error = platform_pci_set_power_state(dev, state);
                if (!error)
                        pci_update_current_state(dev, state);
-               /* Fall back to PCI_D0 if native PM is not supported */
-               if (!dev->pm_cap)
-                       dev->current_state = PCI_D0;
-       } else {
+       } else
                error = -ENODEV;
-               /* Fall back to PCI_D0 if native PM is not supported */
-               if (!dev->pm_cap)
-                       dev->current_state = PCI_D0;
-       }
+
+       if (error && !dev->pm_cap) /* Fall back to PCI_D0 */
+               dev->current_state = PCI_D0;
 
        return error;
 }
@@ -1575,7 +1571,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
 {
        u16 pmcsr;
 
-       if (!dev->pm_cap)
+       if (!dev->pme_support)
                return;
 
        pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
@@ -1924,6 +1920,7 @@ void pci_pm_init(struct pci_dev *dev)
        dev->wakeup_prepared = false;
 
        dev->pm_cap = 0;
+       dev->pme_support = 0;
 
        /* find PCI PM capability in list */
        pm = pci_find_capability(dev, PCI_CAP_ID_PM);
@@ -1975,8 +1972,6 @@ void pci_pm_init(struct pci_dev *dev)
                device_set_wakeup_capable(&dev->dev, true);
                /* Disable the PME# generation functionality */
                pci_pme_active(dev, false);
-       } else {
-               dev->pme_support = 0;
        }
 }
 
@@ -2619,7 +2614,7 @@ void pci_release_selected_regions(struct pci_dev *pdev, int bars)
                        pci_release_region(pdev, i);
 }
 
-int __pci_request_selected_regions(struct pci_dev *pdev, int bars,
+static int __pci_request_selected_regions(struct pci_dev *pdev, int bars,
                                 const char *res_name, int excl)
 {
        int i;
@@ -3699,7 +3694,7 @@ static DEFINE_SPINLOCK(resource_alignment_lock);
  * RETURNS: Resource alignment if it is specified.
  *          Zero if it is not specified.
  */
-resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
+static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
 {
        int seg, bus, slot, func, align_order, count;
        resource_size_t align = 0;
@@ -3812,7 +3807,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
        }
 }
 
-ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
+static ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
 {
        if (count > RESOURCE_ALIGNMENT_PARAM_SIZE - 1)
                count = RESOURCE_ALIGNMENT_PARAM_SIZE - 1;
@@ -3823,7 +3818,7 @@ ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
        return count;
 }
 
-ssize_t pci_get_resource_alignment_param(char *buf, size_t size)
+static ssize_t pci_get_resource_alignment_param(char *buf, size_t size)
 {
        size_t count;
        spin_lock(&resource_alignment_lock);
index 7346ee6..68678ed 100644 (file)
@@ -8,26 +8,25 @@
 
 /* Functions internal to the PCI core code */
 
-extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
-extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
+int pci_create_sysfs_dev_files(struct pci_dev *pdev);
+void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
 #if !defined(CONFIG_DMI) && !defined(CONFIG_ACPI)
 static inline void pci_create_firmware_label_files(struct pci_dev *pdev)
 { return; }
 static inline void pci_remove_firmware_label_files(struct pci_dev *pdev)
 { return; }
 #else
-extern void pci_create_firmware_label_files(struct pci_dev *pdev);
-extern void pci_remove_firmware_label_files(struct pci_dev *pdev);
+void pci_create_firmware_label_files(struct pci_dev *pdev);
+void pci_remove_firmware_label_files(struct pci_dev *pdev);
 #endif
-extern void pci_cleanup_rom(struct pci_dev *dev);
+void pci_cleanup_rom(struct pci_dev *dev);
 #ifdef HAVE_PCI_MMAP
 enum pci_mmap_api {
        PCI_MMAP_SYSFS, /* mmap on /sys/bus/pci/devices/<BDF>/resource<N> */
        PCI_MMAP_PROCFS /* mmap on /proc/bus/pci/<BDF> */
 };
-extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
-                        struct vm_area_struct *vmai,
-                        enum pci_mmap_api mmap_api);
+int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vmai,
+                 enum pci_mmap_api mmap_api);
 #endif
 int pci_probe_reset_function(struct pci_dev *dev);
 
@@ -60,17 +59,17 @@ struct pci_platform_pm_ops {
        int (*run_wake)(struct pci_dev *dev, bool enable);
 };
 
-extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
-extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
-extern void pci_power_up(struct pci_dev *dev);
-extern void pci_disable_enabled_device(struct pci_dev *dev);
-extern int pci_finish_runtime_suspend(struct pci_dev *dev);
-extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
-extern void pci_wakeup_bus(struct pci_bus *bus);
-extern void pci_config_pm_runtime_get(struct pci_dev *dev);
-extern void pci_config_pm_runtime_put(struct pci_dev *dev);
-extern void pci_pm_init(struct pci_dev *dev);
-extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
+int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
+void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
+void pci_power_up(struct pci_dev *dev);
+void pci_disable_enabled_device(struct pci_dev *dev);
+int pci_finish_runtime_suspend(struct pci_dev *dev);
+int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
+void pci_wakeup_bus(struct pci_bus *bus);
+void pci_config_pm_runtime_get(struct pci_dev *dev);
+void pci_config_pm_runtime_put(struct pci_dev *dev);
+void pci_pm_init(struct pci_dev *dev);
+void pci_allocate_cap_save_buffers(struct pci_dev *dev);
 void pci_free_cap_save_buffers(struct pci_dev *dev);
 
 static inline void pci_wakeup_event(struct pci_dev *dev)
@@ -96,7 +95,7 @@ struct pci_vpd {
        struct bin_attribute *attr; /* descriptor for sysfs VPD entry */
 };
 
-extern int pci_vpd_pci22_init(struct pci_dev *dev);
+int pci_vpd_pci22_init(struct pci_dev *dev);
 static inline void pci_vpd_release(struct pci_dev *dev)
 {
        if (dev->vpd)
@@ -105,9 +104,9 @@ static inline void pci_vpd_release(struct pci_dev *dev)
 
 /* PCI /proc functions */
 #ifdef CONFIG_PROC_FS
-extern int pci_proc_attach_device(struct pci_dev *dev);
-extern int pci_proc_detach_device(struct pci_dev *dev);
-extern int pci_proc_detach_bus(struct pci_bus *bus);
+int pci_proc_attach_device(struct pci_dev *dev);
+int pci_proc_detach_device(struct pci_dev *dev);
+int pci_proc_detach_bus(struct pci_bus *bus);
 #else
 static inline int pci_proc_attach_device(struct pci_dev *dev) { return 0; }
 static inline int pci_proc_detach_device(struct pci_dev *dev) { return 0; }
@@ -118,8 +117,8 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; }
 int pci_hp_add_bridge(struct pci_dev *dev);
 
 #ifdef HAVE_PCI_LEGACY
-extern void pci_create_legacy_files(struct pci_bus *bus);
-extern void pci_remove_legacy_files(struct pci_bus *bus);
+void pci_create_legacy_files(struct pci_bus *bus);
+void pci_remove_legacy_files(struct pci_bus *bus);
 #else
 static inline void pci_create_legacy_files(struct pci_bus *bus) { return; }
 static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; }
@@ -134,7 +133,7 @@ extern unsigned int pci_pm_d3_delay;
 
 #ifdef CONFIG_PCI_MSI
 void pci_no_msi(void);
-extern void pci_msi_init_pci_dev(struct pci_dev *dev);
+void pci_msi_init_pci_dev(struct pci_dev *dev);
 #else
 static inline void pci_no_msi(void) { }
 static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
@@ -198,12 +197,11 @@ enum pci_bar_type {
 
 bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
                                int crs_timeout);
-extern int pci_setup_device(struct pci_dev *dev);
-extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
-                               struct resource *res, unsigned int reg);
-extern int pci_resource_bar(struct pci_dev *dev, int resno,
-                           enum pci_bar_type *type);
-extern void pci_configure_ari(struct pci_dev *dev);
+int pci_setup_device(struct pci_dev *dev);
+int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
+                   struct resource *res, unsigned int reg);
+int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type);
+void pci_configure_ari(struct pci_dev *dev);
 
 /**
  * pci_ari_enabled - query ARI forwarding status
@@ -217,7 +215,7 @@ static inline int pci_ari_enabled(struct pci_bus *bus)
 }
 
 void pci_reassigndev_resource_alignment(struct pci_dev *dev);
-extern void pci_disable_bridge_window(struct pci_dev *dev);
+void pci_disable_bridge_window(struct pci_dev *dev);
 
 /* Single Root I/O Virtualization */
 struct pci_sriov {
@@ -241,7 +239,7 @@ struct pci_sriov {
 };
 
 #ifdef CONFIG_PCI_ATS
-extern void pci_restore_ats_state(struct pci_dev *dev);
+void pci_restore_ats_state(struct pci_dev *dev);
 #else
 static inline void pci_restore_ats_state(struct pci_dev *dev)
 {
@@ -249,14 +247,13 @@ static inline void pci_restore_ats_state(struct pci_dev *dev)
 #endif /* CONFIG_PCI_ATS */
 
 #ifdef CONFIG_PCI_IOV
-extern int pci_iov_init(struct pci_dev *dev);
-extern void pci_iov_release(struct pci_dev *dev);
-extern int pci_iov_resource_bar(struct pci_dev *dev, int resno,
-                               enum pci_bar_type *type);
-extern resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev,
-                                                   int resno);
-extern void pci_restore_iov_state(struct pci_dev *dev);
-extern int pci_iov_bus_range(struct pci_bus *bus);
+int pci_iov_init(struct pci_dev *dev);
+void pci_iov_release(struct pci_dev *dev);
+int pci_iov_resource_bar(struct pci_dev *dev, int resno,
+                        enum pci_bar_type *type);
+resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
+void pci_restore_iov_state(struct pci_dev *dev);
+int pci_iov_bus_range(struct pci_bus *bus);
 
 #else
 static inline int pci_iov_init(struct pci_dev *dev)
@@ -282,10 +279,10 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
 
 #endif /* CONFIG_PCI_IOV */
 
-extern unsigned long pci_cardbus_resource_alignment(struct resource *);
+unsigned long pci_cardbus_resource_alignment(struct resource *);
 
 static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
-                                        struct resource *res)
+                                                    struct resource *res)
 {
 #ifdef CONFIG_PCI_IOV
        int resno = res - dev->resource;
@@ -298,7 +295,7 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
        return resource_alignment(res);
 }
 
-extern void pci_enable_acs(struct pci_dev *dev);
+void pci_enable_acs(struct pci_dev *dev);
 
 struct pci_dev_reset_methods {
        u16 vendor;
@@ -307,7 +304,7 @@ struct pci_dev_reset_methods {
 };
 
 #ifdef CONFIG_PCI_QUIRKS
-extern int pci_dev_specific_reset(struct pci_dev *dev, int probe);
+int pci_dev_specific_reset(struct pci_dev *dev, int probe);
 #else
 static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
 {
index fde4a32..569f82f 100644 (file)
@@ -82,4 +82,4 @@ endchoice
 
 config PCIE_PME
        def_bool y
-       depends on PCIEPORTBUS && PM_RUNTIME && ACPI
+       depends on PCIEPORTBUS && PM_RUNTIME
index 4e24cb8..587e7e8 100644 (file)
@@ -212,8 +212,8 @@ out:
        return ops->read(bus, devfn, where, size, val);
 }
 
-int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, int size,
-                 u32 val)
+static int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where,
+                        int size, u32 val)
 {
        u32 *sim;
        struct aer_error *err;
@@ -334,13 +334,13 @@ static int aer_inject(struct aer_error_inj *einj)
                return -ENODEV;
        rpdev = pcie_find_root_port(dev);
        if (!rpdev) {
-               ret = -ENOTTY;
+               ret = -ENODEV;
                goto out_put;
        }
 
        pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
        if (!pos_cap_err) {
-               ret = -ENOTTY;
+               ret = -EPERM;
                goto out_put;
        }
        pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever);
@@ -350,7 +350,7 @@ static int aer_inject(struct aer_error_inj *einj)
 
        rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR);
        if (!rp_pos_cap_err) {
-               ret = -ENOTTY;
+               ret = -EPERM;
                goto out_put;
        }
 
index 22f840f..d12c77c 100644 (file)
@@ -110,15 +110,15 @@ static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
 }
 
 extern struct bus_type pcie_port_bus_type;
-extern void aer_do_secondary_bus_reset(struct pci_dev *dev);
-extern int aer_init(struct pcie_device *dev);
-extern void aer_isr(struct work_struct *work);
-extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
-extern void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info);
-extern irqreturn_t aer_irq(int irq, void *context);
+void aer_do_secondary_bus_reset(struct pci_dev *dev);
+int aer_init(struct pcie_device *dev);
+void aer_isr(struct work_struct *work);
+void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
+void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info);
+irqreturn_t aer_irq(int irq, void *context);
 
 #ifdef CONFIG_ACPI_APEI
-extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
+int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
 #else
 static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
 {
index 564d97f..8ec8b4f 100644 (file)
@@ -89,8 +89,6 @@ static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev)
        return -ENOSPC;
 }
 
-#define        PCI_BUS(x)      (((x) >> 8) & 0xff)
-
 /**
  * is_error_source - check whether the device is source of reported error
  * @dev: pointer to pci_dev to be checked
@@ -106,7 +104,7 @@ static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)
         * When bus id is equal to 0, it might be a bad id
         * reported by root port.
         */
-       if (!nosourceid && (PCI_BUS(e_info->id) != 0)) {
+       if (!nosourceid && (PCI_BUS_NUM(e_info->id) != 0)) {
                /* Device ID match? */
                if (e_info->id == ((dev->bus->number << 8) | dev->devfn))
                        return true;
index 9ca0dc9..795db1f 100644 (file)
@@ -19,8 +19,6 @@
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/pcieport_if.h>
-#include <linux/acpi.h>
-#include <linux/pci-acpi.h>
 #include <linux/pm_runtime.h>
 
 #include "../pci.h"
index eea2ca2..d2eb80a 100644 (file)
 #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
 
 extern struct bus_type pcie_port_bus_type;
-extern int pcie_port_device_register(struct pci_dev *dev);
+int pcie_port_device_register(struct pci_dev *dev);
 #ifdef CONFIG_PM
-extern int pcie_port_device_suspend(struct device *dev);
-extern int pcie_port_device_resume(struct device *dev);
+int pcie_port_device_suspend(struct device *dev);
+int pcie_port_device_resume(struct device *dev);
 #endif
-extern void pcie_port_device_remove(struct pci_dev *dev);
-extern int __must_check pcie_port_bus_register(void);
-extern void pcie_port_bus_unregister(void);
+void pcie_port_device_remove(struct pci_dev *dev);
+int __must_check pcie_port_bus_register(void);
+void pcie_port_bus_unregister(void);
 
 struct pci_dev;
 
-extern void pcie_clear_root_pme_status(struct pci_dev *dev);
+void pcie_clear_root_pme_status(struct pci_dev *dev);
 
 #ifdef CONFIG_HOTPLUG_PCI_PCIE
 extern bool pciehp_msi_disabled;
@@ -59,7 +59,7 @@ static inline bool pcie_pme_no_msi(void)
        return pcie_pme_msi_disabled;
 }
 
-extern void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable);
+void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable);
 #else /* !CONFIG_PCIE_PME */
 static inline void pcie_pme_disable_msi(void) {}
 static inline bool pcie_pme_no_msi(void) { return false; }
@@ -67,7 +67,7 @@ static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {}
 #endif /* !CONFIG_PCIE_PME */
 
 #ifdef CONFIG_ACPI
-extern int pcie_port_acpi_setup(struct pci_dev *port, int *mask);
+int pcie_port_acpi_setup(struct pci_dev *port, int *mask);
 
 static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
 {
index a86b56e..b4d2894 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "aer/aerdrv.h"
 #include "../pci.h"
+#include "portdrv.h"
 
 /**
  * pcie_port_acpi_setup - Request the BIOS to release control of PCIe services.
index ed4d094..696caed 100644 (file)
@@ -259,11 +259,9 @@ static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
                                        enum pci_channel_state error)
 {
        struct aer_broadcast_data data = {error, PCI_ERS_RESULT_CAN_RECOVER};
-       int ret;
-
-       /* can not fail */
-       ret = device_for_each_child(&dev->dev, &data, error_detected_iter);
 
+       /* get true return value from &data */
+       device_for_each_child(&dev->dev, &data, error_detected_iter);
        return data.result;
 }
 
@@ -295,10 +293,9 @@ static int mmio_enabled_iter(struct device *device, void *data)
 static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev)
 {
        pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
-       int retval;
 
        /* get true return value from &status */
-       retval = device_for_each_child(&dev->dev, &status, mmio_enabled_iter);
+       device_for_each_child(&dev->dev, &status, mmio_enabled_iter);
        return status;
 }
 
@@ -330,7 +327,6 @@ static int slot_reset_iter(struct device *device, void *data)
 static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
 {
        pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
-       int retval;
 
        /* If fatal, restore cfg space for possible link reset at upstream */
        if (dev->error_state == pci_channel_io_frozen) {
@@ -341,8 +337,7 @@ static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
        }
 
        /* get true return value from &status */
-       retval = device_for_each_child(&dev->dev, &status, slot_reset_iter);
-
+       device_for_each_child(&dev->dev, &status, slot_reset_iter);
        return status;
 }
 
@@ -368,9 +363,7 @@ static int resume_iter(struct device *device, void *data)
 
 static void pcie_portdrv_err_resume(struct pci_dev *dev)
 {
-       int retval;
-       /* nothing to do with error value, if it ever happens */
-       retval = device_for_each_child(&dev->dev, NULL, resume_iter);
+       device_for_each_child(&dev->dev, NULL, resume_iter);
 }
 
 /*
index b494066..43ece5d 100644 (file)
@@ -673,6 +673,8 @@ add_dev:
        ret = device_register(&child->dev);
        WARN_ON(ret < 0);
 
+       pcibios_add_bus(child);
+
        /* Create legacy_io and legacy_mem files for this bus */
        pci_create_legacy_files(child);
 
@@ -1627,8 +1629,7 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
        if (!bus->is_added) {
                dev_dbg(&bus->dev, "fixups for bus\n");
                pcibios_fixup_bus(bus);
-               if (pci_is_root_bus(bus))
-                       bus->is_added = 1;
+               bus->is_added = 1;
        }
 
        for (pass=0; pass < 2; pass++)
@@ -1661,6 +1662,14 @@ int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
        return 0;
 }
 
+void __weak pcibios_add_bus(struct pci_bus *bus)
+{
+}
+
+void __weak pcibios_remove_bus(struct pci_bus *bus)
+{
+}
+
 struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
                struct pci_ops *ops, void *sysdata, struct list_head *resources)
 {
@@ -1715,6 +1724,8 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
        if (error)
                goto class_dev_reg_err;
 
+       pcibios_add_bus(b);
+
        /* Create legacy_io and legacy_mem files for this bus */
        pci_create_legacy_files(b);
 
index 0369fb6..7d68aee 100644 (file)
@@ -324,29 +324,30 @@ static void quirk_cs5536_vsa(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_cs5536_vsa);
 
-static void quirk_io_region(struct pci_dev *dev, unsigned region,
-       unsigned size, int nr, const char *name)
+static void quirk_io_region(struct pci_dev *dev, int port,
+                               unsigned size, int nr, const char *name)
 {
-       region &= ~(size-1);
-       if (region) {
-               struct pci_bus_region bus_region;
-               struct resource *res = dev->resource + nr;
+       u16 region;
+       struct pci_bus_region bus_region;
+       struct resource *res = dev->resource + nr;
 
-               res->name = pci_name(dev);
-               res->start = region;
-               res->end = region + size - 1;
-               res->flags = IORESOURCE_IO;
+       pci_read_config_word(dev, port, &region);
+       region &= ~(size - 1);
 
-               /* Convert from PCI bus to resource space.  */
-               bus_region.start = res->start;
-               bus_region.end = res->end;
-               pcibios_bus_to_resource(dev, res, &bus_region);
+       if (!region)
+               return;
 
-               if (pci_claim_resource(dev, nr) == 0)
-                       dev_info(&dev->dev, "quirk: %pR claimed by %s\n",
-                                res, name);
-       }
-}      
+       res->name = pci_name(dev);
+       res->flags = IORESOURCE_IO;
+
+       /* Convert from PCI bus to resource space */
+       bus_region.start = region;
+       bus_region.end = region + size - 1;
+       pcibios_bus_to_resource(dev, res, &bus_region);
+
+       if (!pci_claim_resource(dev, nr))
+               dev_info(&dev->dev, "quirk: %pR claimed by %s\n", res, name);
+}
 
 /*
  *     ATI Northbridge setups MCE the processor if you even
@@ -374,12 +375,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100,   quirk_ati_
  */
 static void quirk_ali7101_acpi(struct pci_dev *dev)
 {
-       u16 region;
-
-       pci_read_config_word(dev, 0xE0, &region);
-       quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES, "ali7101 ACPI");
-       pci_read_config_word(dev, 0xE2, &region);
-       quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB");
+       quirk_io_region(dev, 0xE0, 64, PCI_BRIDGE_RESOURCES, "ali7101 ACPI");
+       quirk_io_region(dev, 0xE2, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB");
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL,     PCI_DEVICE_ID_AL_M7101,         quirk_ali7101_acpi);
 
@@ -442,12 +439,10 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int
  */
 static void quirk_piix4_acpi(struct pci_dev *dev)
 {
-       u32 region, res_a;
+       u32 res_a;
 
-       pci_read_config_dword(dev, 0x40, &region);
-       quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES, "PIIX4 ACPI");
-       pci_read_config_dword(dev, 0x90, &region);
-       quirk_io_region(dev, region, 16, PCI_BRIDGE_RESOURCES+1, "PIIX4 SMB");
+       quirk_io_region(dev, 0x40, 64, PCI_BRIDGE_RESOURCES, "PIIX4 ACPI");
+       quirk_io_region(dev, 0x90, 16, PCI_BRIDGE_RESOURCES+1, "PIIX4 SMB");
 
        /* Device resource A has enables for some of the other ones */
        pci_read_config_dword(dev, 0x5c, &res_a);
@@ -491,7 +486,6 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,       PCI_DEVICE_ID_INTEL_82443MX_3,  qui
  */
 static void quirk_ich4_lpc_acpi(struct pci_dev *dev)
 {
-       u32 region;
        u8 enable;
 
        /*
@@ -503,22 +497,14 @@ static void quirk_ich4_lpc_acpi(struct pci_dev *dev)
        */
 
        pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable);
-       if (enable & ICH4_ACPI_EN) {
-               pci_read_config_dword(dev, ICH_PMBASE, &region);
-               region &= PCI_BASE_ADDRESS_IO_MASK;
-               if (region >= PCIBIOS_MIN_IO)
-                       quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES,
-                                       "ICH4 ACPI/GPIO/TCO");
-       }
+       if (enable & ICH4_ACPI_EN)
+               quirk_io_region(dev, ICH_PMBASE, 128, PCI_BRIDGE_RESOURCES,
+                                "ICH4 ACPI/GPIO/TCO");
 
        pci_read_config_byte(dev, ICH4_GPIO_CNTL, &enable);
-       if (enable & ICH4_GPIO_EN) {
-               pci_read_config_dword(dev, ICH4_GPIOBASE, &region);
-               region &= PCI_BASE_ADDRESS_IO_MASK;
-               if (region >= PCIBIOS_MIN_IO)
-                       quirk_io_region(dev, region, 64,
-                                       PCI_BRIDGE_RESOURCES + 1, "ICH4 GPIO");
-       }
+       if (enable & ICH4_GPIO_EN)
+               quirk_io_region(dev, ICH4_GPIOBASE, 64, PCI_BRIDGE_RESOURCES+1,
+                               "ICH4 GPIO");
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801AA_0,                quirk_ich4_lpc_acpi);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801AB_0,                quirk_ich4_lpc_acpi);
@@ -533,26 +519,17 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ESB_1,               qui
 
 static void ich6_lpc_acpi_gpio(struct pci_dev *dev)
 {
-       u32 region;
        u8 enable;
 
        pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable);
-       if (enable & ICH6_ACPI_EN) {
-               pci_read_config_dword(dev, ICH_PMBASE, &region);
-               region &= PCI_BASE_ADDRESS_IO_MASK;
-               if (region >= PCIBIOS_MIN_IO)
-                       quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES,
-                                       "ICH6 ACPI/GPIO/TCO");
-       }
+       if (enable & ICH6_ACPI_EN)
+               quirk_io_region(dev, ICH_PMBASE, 128, PCI_BRIDGE_RESOURCES,
+                                "ICH6 ACPI/GPIO/TCO");
 
        pci_read_config_byte(dev, ICH6_GPIO_CNTL, &enable);
-       if (enable & ICH6_GPIO_EN) {
-               pci_read_config_dword(dev, ICH6_GPIOBASE, &region);
-               region &= PCI_BASE_ADDRESS_IO_MASK;
-               if (region >= PCIBIOS_MIN_IO)
-                       quirk_io_region(dev, region, 64,
-                                       PCI_BRIDGE_RESOURCES + 1, "ICH6 GPIO");
-       }
+       if (enable & ICH6_GPIO_EN)
+               quirk_io_region(dev, ICH6_GPIOBASE, 64, PCI_BRIDGE_RESOURCES+1,
+                               "ICH6 GPIO");
 }
 
 static void ich6_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name, int dynsize)
@@ -650,13 +627,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_ICH10_1, qui
  */
 static void quirk_vt82c586_acpi(struct pci_dev *dev)
 {
-       u32 region;
-
-       if (dev->revision & 0x10) {
-               pci_read_config_dword(dev, 0x48, &region);
-               region &= PCI_BASE_ADDRESS_IO_MASK;
-               quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI");
-       }
+       if (dev->revision & 0x10)
+               quirk_io_region(dev, 0x48, 256, PCI_BRIDGE_RESOURCES,
+                               "vt82c586 ACPI");
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C586_3,     quirk_vt82c586_acpi);
 
@@ -668,18 +641,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,       PCI_DEVICE_ID_VIA_82C586_3,     quirk_vt
  */
 static void quirk_vt82c686_acpi(struct pci_dev *dev)
 {
-       u16 hm;
-       u32 smb;
-
        quirk_vt82c586_acpi(dev);
 
-       pci_read_config_word(dev, 0x70, &hm);
-       hm &= PCI_BASE_ADDRESS_IO_MASK;
-       quirk_io_region(dev, hm, 128, PCI_BRIDGE_RESOURCES + 1, "vt82c686 HW-mon");
+       quirk_io_region(dev, 0x70, 128, PCI_BRIDGE_RESOURCES+1,
+                                "vt82c686 HW-mon");
 
-       pci_read_config_dword(dev, 0x90, &smb);
-       smb &= PCI_BASE_ADDRESS_IO_MASK;
-       quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2, "vt82c686 SMB");
+       quirk_io_region(dev, 0x90, 16, PCI_BRIDGE_RESOURCES+2, "vt82c686 SMB");
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C686_4,     quirk_vt82c686_acpi);
 
@@ -690,15 +657,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,        PCI_DEVICE_ID_VIA_82C686_4,     quirk_vt
  */
 static void quirk_vt8235_acpi(struct pci_dev *dev)
 {
-       u16 pm, smb;
-
-       pci_read_config_word(dev, 0x88, &pm);
-       pm &= PCI_BASE_ADDRESS_IO_MASK;
-       quirk_io_region(dev, pm, 128, PCI_BRIDGE_RESOURCES, "vt8235 PM");
-
-       pci_read_config_word(dev, 0xd0, &smb);
-       smb &= PCI_BASE_ADDRESS_IO_MASK;
-       quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 1, "vt8235 SMB");
+       quirk_io_region(dev, 0x88, 128, PCI_BRIDGE_RESOURCES, "vt8235 PM");
+       quirk_io_region(dev, 0xd0, 16, PCI_BRIDGE_RESOURCES+1, "vt8235 SMB");
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8235, quirk_vt8235_acpi);
 
@@ -2594,6 +2554,14 @@ static void quirk_msi_intx_disable_ati_bug(struct pci_dev *dev)
                dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
        pci_dev_put(p);
 }
+static void quirk_msi_intx_disable_qca_bug(struct pci_dev *dev)
+{
+       /* AR816X/AR817X/E210X MSI is fixed at HW level from revision 0x18 */
+       if (dev->revision < 0x18) {
+               dev_info(&dev->dev, "set MSI_INTX_DISABLE_BUG flag\n");
+               dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
+       }
+}
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
                        PCI_DEVICE_ID_TIGON3_5780,
                        quirk_msi_intx_disable_bug);
@@ -2643,6 +2611,16 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1073,
                        quirk_msi_intx_disable_bug);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1083,
                        quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1090,
+                       quirk_msi_intx_disable_qca_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1091,
+                       quirk_msi_intx_disable_qca_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x10a0,
+                       quirk_msi_intx_disable_qca_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x10a1,
+                       quirk_msi_intx_disable_qca_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0xe091,
+                       quirk_msi_intx_disable_qca_bug);
 #endif /* CONFIG_PCI_MSI */
 
 /* Allow manual resource allocation for PCI hotplug bridges
index cc875e6..8fc54b7 100644 (file)
@@ -50,10 +50,8 @@ void pci_remove_bus(struct pci_bus *bus)
        list_del(&bus->node);
        pci_bus_release_busn_res(bus);
        up_write(&pci_bus_sem);
-       if (!bus->is_added)
-               return;
-
        pci_remove_legacy_files(bus);
+       pcibios_remove_bus(bus);
        device_unregister(&bus->dev);
 }
 EXPORT_SYMBOL(pci_remove_bus);
index 7e8739e..16abaaa 100644 (file)
@@ -1044,7 +1044,7 @@ handle_done:
        ;
 }
 
-void __ref __pci_bus_size_bridges(struct pci_bus *bus,
+static void __ref __pci_bus_size_bridges(struct pci_bus *bus,
                        struct list_head *realloc_head)
 {
        struct pci_dev *dev;
@@ -1545,6 +1545,8 @@ again:
 
 enable_all:
        retval = pci_reenable_device(bridge);
+       if (retval)
+               dev_err(&bridge->dev, "Error reenabling bridge (%d)\n", retval);
        pci_set_master(bridge);
        pci_enable_bridges(parent);
 }
index 81b88bd..07f2edd 100644 (file)
@@ -261,7 +261,6 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
 {
        struct resource *res = dev->resource + resno;
        resource_size_t align, size;
-       struct pci_bus *bus;
        int ret;
 
        align = pci_resource_alignment(dev, res);
@@ -271,7 +270,6 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
                return -EINVAL;
        }
 
-       bus = dev->bus;
        size = resource_size(res);
        ret = _pci_assign_resource(dev, resno, size, align);
 
index ac6412f..c1e9284 100644 (file)
@@ -377,14 +377,17 @@ void pci_hp_create_module_link(struct pci_slot *pci_slot)
 {
        struct hotplug_slot *slot = pci_slot->hotplug;
        struct kobject *kobj = NULL;
-       int no_warn;
+       int ret;
 
        if (!slot || !slot->ops)
                return;
        kobj = kset_find_obj(module_kset, slot->ops->mod_name);
        if (!kobj)
                return;
-       no_warn = sysfs_create_link(&pci_slot->kobj, kobj, "module");
+       ret = sysfs_create_link(&pci_slot->kobj, kobj, "module");
+       if (ret)
+               dev_err(&pci_slot->bus->dev, "Error creating sysfs link (%d)\n",
+                       ret);
        kobject_put(kobj);
 }
 EXPORT_SYMBOL_GPL(pci_hp_create_module_link);
index 34f51d2..f910962 100644 (file)
@@ -106,20 +106,11 @@ config PINCTRL_LANTIQ
        select PINMUX
        select PINCONF
 
-config PINCTRL_PXA3xx
-       bool
-       select PINMUX
-
 config PINCTRL_FALCON
        bool
        depends on SOC_FALCON
        depends on PINCTRL_LANTIQ
 
-config PINCTRL_MMP2
-       bool "MMP2 pin controller driver"
-       depends on ARCH_MMP
-       select PINCTRL_PXA3xx
-
 config PINCTRL_MXS
        bool
        select PINMUX
@@ -151,21 +142,12 @@ config PINCTRL_DB8540
        bool "DB8540 pin controller driver"
        depends on PINCTRL_NOMADIK && ARCH_U8500
 
-config PINCTRL_PXA168
-       bool "PXA168 pin controller driver"
-       depends on ARCH_MMP
-       select PINCTRL_PXA3xx
-
-config PINCTRL_PXA910
-       bool "PXA910 pin controller driver"
-       depends on ARCH_MMP
-       select PINCTRL_PXA3xx
-
 config PINCTRL_SINGLE
        tristate "One-register-per-pin type device tree based pinctrl driver"
        depends on OF
        select PINMUX
        select PINCONF
+       select GENERIC_PINCONF
        help
          This selects the device tree based generic pinctrl driver.
 
@@ -226,6 +208,11 @@ config PINCTRL_EXYNOS5440
        select PINMUX
        select PINCONF
 
+config PINCTRL_S3C64XX
+       bool "Samsung S3C64XX SoC pinctrl driver"
+       depends on ARCH_S3C64XX
+       select PINCTRL_SAMSUNG
+
 source "drivers/pinctrl/mvebu/Kconfig"
 source "drivers/pinctrl/sh-pfc/Kconfig"
 source "drivers/pinctrl/spear/Kconfig"
index f82cc5b..988279a 100644 (file)
@@ -21,9 +21,7 @@ obj-$(CONFIG_PINCTRL_IMX35)   += pinctrl-imx35.o
 obj-$(CONFIG_PINCTRL_IMX51)    += pinctrl-imx51.o
 obj-$(CONFIG_PINCTRL_IMX53)    += pinctrl-imx53.o
 obj-$(CONFIG_PINCTRL_IMX6Q)    += pinctrl-imx6q.o
-obj-$(CONFIG_PINCTRL_PXA3xx)   += pinctrl-pxa3xx.o
 obj-$(CONFIG_PINCTRL_FALCON)   += pinctrl-falcon.o
-obj-$(CONFIG_PINCTRL_MMP2)     += pinctrl-mmp2.o
 obj-$(CONFIG_PINCTRL_MXS)      += pinctrl-mxs.o
 obj-$(CONFIG_PINCTRL_IMX23)    += pinctrl-imx23.o
 obj-$(CONFIG_PINCTRL_IMX28)    += pinctrl-imx28.o
@@ -31,8 +29,6 @@ obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o
 obj-$(CONFIG_PINCTRL_STN8815)  += pinctrl-nomadik-stn8815.o
 obj-$(CONFIG_PINCTRL_DB8500)   += pinctrl-nomadik-db8500.o
 obj-$(CONFIG_PINCTRL_DB8540)   += pinctrl-nomadik-db8540.o
-obj-$(CONFIG_PINCTRL_PXA168)   += pinctrl-pxa168.o
-obj-$(CONFIG_PINCTRL_PXA910)   += pinctrl-pxa910.o
 obj-$(CONFIG_PINCTRL_SINGLE)   += pinctrl-single.o
 obj-$(CONFIG_PINCTRL_SIRF)     += pinctrl-sirf.o
 obj-$(CONFIG_PINCTRL_SUNXI)    += pinctrl-sunxi.o
@@ -45,6 +41,7 @@ obj-$(CONFIG_PINCTRL_COH901)  += pinctrl-coh901.o
 obj-$(CONFIG_PINCTRL_SAMSUNG)  += pinctrl-samsung.o
 obj-$(CONFIG_PINCTRL_EXYNOS)   += pinctrl-exynos.o
 obj-$(CONFIG_PINCTRL_EXYNOS5440)       += pinctrl-exynos5440.o
+obj-$(CONFIG_PINCTRL_S3C64XX)  += pinctrl-s3c64xx.o
 obj-$(CONFIG_PINCTRL_XWAY)     += pinctrl-xway.o
 obj-$(CONFIG_PINCTRL_LANTIQ)   += pinctrl-lantiq.o
 
index b0de6e7..c3d222e 100644 (file)
 #include <linux/pinctrl/consumer.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/machine.h>
+
+#ifdef CONFIG_GPIOLIB
+#include <asm-generic/gpio.h>
+#endif
+
 #include "core.h"
 #include "devicetree.h"
 #include "pinmux.h"
 
 static bool pinctrl_dummy_state;
 
-/* Mutex taken by all entry points */
-DEFINE_MUTEX(pinctrl_mutex);
+/* Mutex taken to protect pinctrl_list */
+DEFINE_MUTEX(pinctrl_list_mutex);
+
+/* Mutex taken to protect pinctrl_maps */
+DEFINE_MUTEX(pinctrl_maps_mutex);
+
+/* Mutex taken to protect pinctrldev_list */
+DEFINE_MUTEX(pinctrldev_list_mutex);
 
 /* Global list of pin control devices (struct pinctrl_dev) */
-LIST_HEAD(pinctrldev_list);
+static LIST_HEAD(pinctrldev_list);
 
 /* List of pin controller handles (struct pinctrl) */
 static LIST_HEAD(pinctrl_list);
@@ -106,6 +117,23 @@ struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *devname)
        return found ? pctldev : NULL;
 }
 
+struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np)
+{
+       struct pinctrl_dev *pctldev;
+
+       mutex_lock(&pinctrldev_list_mutex);
+
+       list_for_each_entry(pctldev, &pinctrldev_list, node)
+               if (pctldev->dev->of_node == np) {
+                       mutex_unlock(&pinctrldev_list_mutex);
+                       return pctldev;
+               }
+
+       mutex_lock(&pinctrldev_list_mutex);
+
+       return NULL;
+}
+
 /**
  * pin_get_from_name() - look up a pin number from a name
  * @pctldev: the pin control device to lookup the pin on
@@ -165,9 +193,9 @@ bool pin_is_valid(struct pinctrl_dev *pctldev, int pin)
        if (pin < 0)
                return false;
 
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pctldev->mutex);
        pindesc = pin_desc_get(pctldev, pin);
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
 
        return pindesc != NULL;
 }
@@ -264,19 +292,58 @@ pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio)
 {
        struct pinctrl_gpio_range *range = NULL;
 
+       mutex_lock(&pctldev->mutex);
        /* Loop over the ranges */
        list_for_each_entry(range, &pctldev->gpio_ranges, node) {
                /* Check if we're in the valid range */
                if (gpio >= range->base &&
                    gpio < range->base + range->npins) {
+                       mutex_unlock(&pctldev->mutex);
                        return range;
                }
        }
-
+       mutex_unlock(&pctldev->mutex);
        return NULL;
 }
 
 /**
+ * pinctrl_ready_for_gpio_range() - check if other GPIO pins of
+ * the same GPIO chip are in range
+ * @gpio: gpio pin to check taken from the global GPIO pin space
+ *
+ * This function is complement of pinctrl_match_gpio_range(). If the return
+ * value of pinctrl_match_gpio_range() is NULL, this function could be used
+ * to check whether pinctrl device is ready or not. Maybe some GPIO pins
+ * of the same GPIO chip don't have back-end pinctrl interface.
+ * If the return value is true, it means that pinctrl device is ready & the
+ * certain GPIO pin doesn't have back-end pinctrl device. If the return value
+ * is false, it means that pinctrl device may not be ready.
+ */
+#ifdef CONFIG_GPIOLIB
+static bool pinctrl_ready_for_gpio_range(unsigned gpio)
+{
+       struct pinctrl_dev *pctldev;
+       struct pinctrl_gpio_range *range = NULL;
+       struct gpio_chip *chip = gpio_to_chip(gpio);
+
+       /* Loop over the pin controllers */
+       list_for_each_entry(pctldev, &pinctrldev_list, node) {
+               /* Loop over the ranges */
+               list_for_each_entry(range, &pctldev->gpio_ranges, node) {
+                       /* Check if any gpio range overlapped with gpio chip */
+                       if (range->base + range->npins - 1 < chip->base ||
+                           range->base > chip->base + chip->ngpio - 1)
+                               continue;
+                       return true;
+               }
+       }
+       return false;
+}
+#else
+static bool pinctrl_ready_for_gpio_range(unsigned gpio) { return true; }
+#endif
+
+/**
  * pinctrl_get_device_gpio_range() - find device for GPIO range
  * @gpio: the pin to locate the pin controller for
  * @outdev: the pin control device if found
@@ -319,9 +386,9 @@ static int pinctrl_get_device_gpio_range(unsigned gpio,
 void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
                            struct pinctrl_gpio_range *range)
 {
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pctldev->mutex);
        list_add_tail(&range->node, &pctldev->gpio_ranges);
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
 }
 EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
 
@@ -339,17 +406,25 @@ EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges);
 struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
                struct pinctrl_gpio_range *range)
 {
-       struct pinctrl_dev *pctldev = get_pinctrl_dev_from_devname(devname);
+       struct pinctrl_dev *pctldev;
+
+       mutex_lock(&pinctrldev_list_mutex);
+
+       pctldev = get_pinctrl_dev_from_devname(devname);
 
        /*
         * If we can't find this device, let's assume that is because
         * it has not probed yet, so the driver trying to register this
         * range need to defer probing.
         */
-       if (!pctldev)
+       if (!pctldev) {
+               mutex_unlock(&pinctrldev_list_mutex);
                return ERR_PTR(-EPROBE_DEFER);
-
+       }
        pinctrl_add_gpio_range(pctldev, range);
+
+       mutex_unlock(&pinctrldev_list_mutex);
+
        return pctldev;
 }
 EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range);
@@ -365,14 +440,17 @@ pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
 {
        struct pinctrl_gpio_range *range = NULL;
 
+       mutex_lock(&pctldev->mutex);
        /* Loop over the ranges */
        list_for_each_entry(range, &pctldev->gpio_ranges, node) {
                /* Check if we're in the valid range */
                if (pin >= range->pin_base &&
                    pin < range->pin_base + range->npins) {
+                       mutex_unlock(&pctldev->mutex);
                        return range;
                }
        }
+       mutex_unlock(&pctldev->mutex);
 
        return NULL;
 }
@@ -386,9 +464,9 @@ EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin);
 void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
                               struct pinctrl_gpio_range *range)
 {
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pctldev->mutex);
        list_del(&range->node);
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
 }
 EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
 
@@ -439,11 +517,13 @@ int pinctrl_request_gpio(unsigned gpio)
        int ret;
        int pin;
 
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pinctrldev_list_mutex);
 
        ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
        if (ret) {
-               mutex_unlock(&pinctrl_mutex);
+               if (pinctrl_ready_for_gpio_range(gpio))
+                       ret = 0;
+               mutex_unlock(&pinctrldev_list_mutex);
                return ret;
        }
 
@@ -452,7 +532,7 @@ int pinctrl_request_gpio(unsigned gpio)
 
        ret = pinmux_request_gpio(pctldev, range, pin, gpio);
 
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pinctrldev_list_mutex);
        return ret;
 }
 EXPORT_SYMBOL_GPL(pinctrl_request_gpio);
@@ -472,20 +552,22 @@ void pinctrl_free_gpio(unsigned gpio)
        int ret;
        int pin;
 
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pinctrldev_list_mutex);
 
        ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
        if (ret) {
-               mutex_unlock(&pinctrl_mutex);
+               mutex_unlock(&pinctrldev_list_mutex);
                return;
        }
+       mutex_lock(&pctldev->mutex);
 
        /* Convert to the pin controllers number space */
        pin = gpio - range->base + range->pin_base;
 
        pinmux_free_gpio(pctldev, pin, range);
 
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
+       mutex_unlock(&pinctrldev_list_mutex);
 }
 EXPORT_SYMBOL_GPL(pinctrl_free_gpio);
 
@@ -496,14 +578,24 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input)
        int ret;
        int pin;
 
+       mutex_lock(&pinctrldev_list_mutex);
+
        ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
-       if (ret)
+       if (ret) {
+               mutex_unlock(&pinctrldev_list_mutex);
                return ret;
+       }
+
+       mutex_lock(&pctldev->mutex);
 
        /* Convert to the pin controllers number space */
        pin = gpio - range->base + range->pin_base;
+       ret = pinmux_gpio_direction(pctldev, range, pin, input);
+
+       mutex_unlock(&pctldev->mutex);
+       mutex_unlock(&pinctrldev_list_mutex);
 
-       return pinmux_gpio_direction(pctldev, range, pin, input);
+       return ret;
 }
 
 /**
@@ -516,11 +608,7 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input)
  */
 int pinctrl_gpio_direction_input(unsigned gpio)
 {
-       int ret;
-       mutex_lock(&pinctrl_mutex);
-       ret = pinctrl_gpio_direction(gpio, true);
-       mutex_unlock(&pinctrl_mutex);
-       return ret;
+       return pinctrl_gpio_direction(gpio, true);
 }
 EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_input);
 
@@ -534,11 +622,7 @@ EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_input);
  */
 int pinctrl_gpio_direction_output(unsigned gpio)
 {
-       int ret;
-       mutex_lock(&pinctrl_mutex);
-       ret = pinctrl_gpio_direction(gpio, false);
-       mutex_unlock(&pinctrl_mutex);
-       return ret;
+       return pinctrl_gpio_direction(gpio, false);
 }
 EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_output);
 
@@ -641,14 +725,18 @@ static struct pinctrl *find_pinctrl(struct device *dev)
 {
        struct pinctrl *p;
 
+       mutex_lock(&pinctrl_list_mutex);
        list_for_each_entry(p, &pinctrl_list, node)
-               if (p->dev == dev)
+               if (p->dev == dev) {
+                       mutex_unlock(&pinctrl_list_mutex);
                        return p;
+               }
 
+       mutex_unlock(&pinctrl_list_mutex);
        return NULL;
 }
 
-static void pinctrl_put_locked(struct pinctrl *p, bool inlist);
+static void pinctrl_free(struct pinctrl *p, bool inlist);
 
 static struct pinctrl *create_pinctrl(struct device *dev)
 {
@@ -681,6 +769,7 @@ static struct pinctrl *create_pinctrl(struct device *dev)
 
        devname = dev_name(dev);
 
+       mutex_lock(&pinctrl_maps_mutex);
        /* Iterate over the pin control maps to locate the right ones */
        for_each_maps(maps_node, i, map) {
                /* Map must be for this device */
@@ -702,13 +791,16 @@ static struct pinctrl *create_pinctrl(struct device *dev)
                 * an -EPROBE_DEFER later, as that is the worst case.
                 */
                if (ret == -EPROBE_DEFER) {
-                       pinctrl_put_locked(p, false);
+                       pinctrl_free(p, false);
+                       mutex_unlock(&pinctrl_maps_mutex);
                        return ERR_PTR(ret);
                }
        }
+       mutex_unlock(&pinctrl_maps_mutex);
+
        if (ret < 0) {
                /* If some other error than deferral occured, return here */
-               pinctrl_put_locked(p, false);
+               pinctrl_free(p, false);
                return ERR_PTR(ret);
        }
 
@@ -720,7 +812,11 @@ static struct pinctrl *create_pinctrl(struct device *dev)
        return p;
 }
 
-static struct pinctrl *pinctrl_get_locked(struct device *dev)
+/**
+ * pinctrl_get() - retrieves the pinctrl handle for a device
+ * @dev: the device to obtain the handle for
+ */
+struct pinctrl *pinctrl_get(struct device *dev)
 {
        struct pinctrl *p;
 
@@ -741,43 +837,35 @@ static struct pinctrl *pinctrl_get_locked(struct device *dev)
 
        return create_pinctrl(dev);
 }
+EXPORT_SYMBOL_GPL(pinctrl_get);
 
-/**
- * pinctrl_get() - retrieves the pinctrl handle for a device
- * @dev: the device to obtain the handle for
- */
-struct pinctrl *pinctrl_get(struct device *dev)
+static void pinctrl_free_setting(bool disable_setting,
+                                struct pinctrl_setting *setting)
 {
-       struct pinctrl *p;
-
-       mutex_lock(&pinctrl_mutex);
-       p = pinctrl_get_locked(dev);
-       mutex_unlock(&pinctrl_mutex);
-
-       return p;
+       switch (setting->type) {
+       case PIN_MAP_TYPE_MUX_GROUP:
+               if (disable_setting)
+                       pinmux_disable_setting(setting);
+               pinmux_free_setting(setting);
+               break;
+       case PIN_MAP_TYPE_CONFIGS_PIN:
+       case PIN_MAP_TYPE_CONFIGS_GROUP:
+               pinconf_free_setting(setting);
+               break;
+       default:
+               break;
+       }
 }
-EXPORT_SYMBOL_GPL(pinctrl_get);
 
-static void pinctrl_put_locked(struct pinctrl *p, bool inlist)
+static void pinctrl_free(struct pinctrl *p, bool inlist)
 {
        struct pinctrl_state *state, *n1;
        struct pinctrl_setting *setting, *n2;
 
+       mutex_lock(&pinctrl_list_mutex);
        list_for_each_entry_safe(state, n1, &p->states, node) {
                list_for_each_entry_safe(setting, n2, &state->settings, node) {
-                       switch (setting->type) {
-                       case PIN_MAP_TYPE_MUX_GROUP:
-                               if (state == p->state)
-                                       pinmux_disable_setting(setting);
-                               pinmux_free_setting(setting);
-                               break;
-                       case PIN_MAP_TYPE_CONFIGS_PIN:
-                       case PIN_MAP_TYPE_CONFIGS_GROUP:
-                               pinconf_free_setting(setting);
-                               break;
-                       default:
-                               break;
-                       }
+                       pinctrl_free_setting(state == p->state, setting);
                        list_del(&setting->node);
                        kfree(setting);
                }
@@ -790,6 +878,7 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist)
        if (inlist)
                list_del(&p->node);
        kfree(p);
+       mutex_unlock(&pinctrl_list_mutex);
 }
 
 /**
@@ -800,7 +889,7 @@ static void pinctrl_release(struct kref *kref)
 {
        struct pinctrl *p = container_of(kref, struct pinctrl, users);
 
-       pinctrl_put_locked(p, true);
+       pinctrl_free(p, true);
 }
 
 /**
@@ -809,14 +898,17 @@ static void pinctrl_release(struct kref *kref)
  */
 void pinctrl_put(struct pinctrl *p)
 {
-       mutex_lock(&pinctrl_mutex);
        kref_put(&p->users, pinctrl_release);
-       mutex_unlock(&pinctrl_mutex);
 }
 EXPORT_SYMBOL_GPL(pinctrl_put);
 
-static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p,
-                                                        const char *name)
+/**
+ * pinctrl_lookup_state() - retrieves a state handle from a pinctrl handle
+ * @p: the pinctrl handle to retrieve the state from
+ * @name: the state name to retrieve
+ */
+struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p,
+                                                const char *name)
 {
        struct pinctrl_state *state;
 
@@ -833,28 +925,17 @@ static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p,
 
        return state;
 }
+EXPORT_SYMBOL_GPL(pinctrl_lookup_state);
 
 /**
- * pinctrl_lookup_state() - retrieves a state handle from a pinctrl handle
- * @p: the pinctrl handle to retrieve the state from
- * @name: the state name to retrieve
+ * pinctrl_select_state() - select/activate/program a pinctrl state to HW
+ * @p: the pinctrl handle for the device that requests configuration
+ * @state: the state handle to select/activate/program
  */
-struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name)
-{
-       struct pinctrl_state *s;
-
-       mutex_lock(&pinctrl_mutex);
-       s = pinctrl_lookup_state_locked(p, name);
-       mutex_unlock(&pinctrl_mutex);
-
-       return s;
-}
-EXPORT_SYMBOL_GPL(pinctrl_lookup_state);
-
-static int pinctrl_select_state_locked(struct pinctrl *p,
-                                      struct pinctrl_state *state)
+int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
 {
        struct pinctrl_setting *setting, *setting2;
+       struct pinctrl_state *old_state = p->state;
        int ret;
 
        if (p->state == state)
@@ -888,7 +969,7 @@ static int pinctrl_select_state_locked(struct pinctrl *p,
                }
        }
 
-       p->state = state;
+       p->state = NULL;
 
        /* Apply all the settings for the new state */
        list_for_each_entry(setting, &state->settings, node) {
@@ -904,27 +985,36 @@ static int pinctrl_select_state_locked(struct pinctrl *p,
                        ret = -EINVAL;
                        break;
                }
+
                if (ret < 0) {
-                       /* FIXME: Difficult to return to prev state */
-                       return ret;
+                       goto unapply_new_state;
                }
        }
 
+       p->state = state;
+
        return 0;
-}
 
-/**
- * pinctrl_select() - select/activate/program a pinctrl state to HW
- * @p: the pinctrl handle for the device that requests configuratio
- * @state: the state handle to select/activate/program
- */
-int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
-{
-       int ret;
+unapply_new_state:
+       dev_err(p->dev, "Error applying setting, reverse things back\n");
 
-       mutex_lock(&pinctrl_mutex);
-       ret = pinctrl_select_state_locked(p, state);
-       mutex_unlock(&pinctrl_mutex);
+       list_for_each_entry(setting2, &state->settings, node) {
+               if (&setting2->node == &setting->node)
+                       break;
+               /*
+                * All we can do here is pinmux_disable_setting.
+                * That means that some pins are muxed differently now
+                * than they were before applying the setting (We can't
+                * "unmux a pin"!), but it's not a big deal since the pins
+                * are free to be muxed by another apply_setting.
+                */
+               if (setting2->type == PIN_MAP_TYPE_MUX_GROUP)
+                       pinmux_disable_setting(setting2);
+       }
+
+       /* There's no infinite recursive loop here because p->state is NULL */
+       if (old_state)
+               pinctrl_select_state(p, old_state);
 
        return ret;
 }
@@ -979,9 +1069,8 @@ static int devm_pinctrl_match(struct device *dev, void *res, void *data)
  */
 void devm_pinctrl_put(struct pinctrl *p)
 {
-       WARN_ON(devres_destroy(p->dev, devm_pinctrl_release,
+       WARN_ON(devres_release(p->dev, devm_pinctrl_release,
                               devm_pinctrl_match, p));
-       pinctrl_put(p);
 }
 EXPORT_SYMBOL_GPL(devm_pinctrl_put);
 
@@ -1055,10 +1144,10 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
        }
 
        if (!locked)
-               mutex_lock(&pinctrl_mutex);
+               mutex_lock(&pinctrl_maps_mutex);
        list_add_tail(&maps_node->node, &pinctrl_maps);
        if (!locked)
-               mutex_unlock(&pinctrl_mutex);
+               mutex_unlock(&pinctrl_maps_mutex);
 
        return 0;
 }
@@ -1080,12 +1169,15 @@ void pinctrl_unregister_map(struct pinctrl_map const *map)
 {
        struct pinctrl_maps *maps_node;
 
+       mutex_lock(&pinctrl_maps_mutex);
        list_for_each_entry(maps_node, &pinctrl_maps, node) {
                if (maps_node->maps == map) {
                        list_del(&maps_node->node);
+                       mutex_unlock(&pinctrl_maps_mutex);
                        return;
                }
        }
+       mutex_unlock(&pinctrl_maps_mutex);
 }
 
 /**
@@ -1122,7 +1214,7 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
 
        seq_printf(s, "registered pins: %d\n", pctldev->desc->npins);
 
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pctldev->mutex);
 
        /* The pin number can be retrived from the pin controller descriptor */
        for (i = 0; i < pctldev->desc->npins; i++) {
@@ -1144,7 +1236,7 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
                seq_puts(s, "\n");
        }
 
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
 
        return 0;
 }
@@ -1155,8 +1247,9 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
        const struct pinctrl_ops *ops = pctldev->desc->pctlops;
        unsigned ngroups, selector = 0;
 
+       mutex_lock(&pctldev->mutex);
+
        ngroups = ops->get_groups_count(pctldev);
-       mutex_lock(&pinctrl_mutex);
 
        seq_puts(s, "registered pin groups:\n");
        while (selector < ngroups) {
@@ -1177,7 +1270,7 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
                        for (i = 0; i < num_pins; i++) {
                                pname = pin_get_name(pctldev, pins[i]);
                                if (WARN_ON(!pname)) {
-                                       mutex_unlock(&pinctrl_mutex);
+                                       mutex_unlock(&pctldev->mutex);
                                        return -EINVAL;
                                }
                                seq_printf(s, "pin %d (%s)\n", pins[i], pname);
@@ -1187,7 +1280,7 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
                selector++;
        }
 
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
 
        return 0;
 }
@@ -1199,7 +1292,7 @@ static int pinctrl_gpioranges_show(struct seq_file *s, void *what)
 
        seq_puts(s, "GPIO ranges handled:\n");
 
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pctldev->mutex);
 
        /* Loop over the ranges */
        list_for_each_entry(range, &pctldev->gpio_ranges, node) {
@@ -1210,7 +1303,7 @@ static int pinctrl_gpioranges_show(struct seq_file *s, void *what)
                           (range->pin_base + range->npins - 1));
        }
 
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
 
        return 0;
 }
@@ -1221,7 +1314,7 @@ static int pinctrl_devices_show(struct seq_file *s, void *what)
 
        seq_puts(s, "name [pinmux] [pinconf]\n");
 
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pinctrldev_list_mutex);
 
        list_for_each_entry(pctldev, &pinctrldev_list, node) {
                seq_printf(s, "%s ", pctldev->desc->name);
@@ -1236,7 +1329,7 @@ static int pinctrl_devices_show(struct seq_file *s, void *what)
                seq_puts(s, "\n");
        }
 
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pinctrldev_list_mutex);
 
        return 0;
 }
@@ -1265,8 +1358,7 @@ static int pinctrl_maps_show(struct seq_file *s, void *what)
 
        seq_puts(s, "Pinctrl maps:\n");
 
-       mutex_lock(&pinctrl_mutex);
-
+       mutex_lock(&pinctrl_maps_mutex);
        for_each_maps(maps_node, i, map) {
                seq_printf(s, "device %s\nstate %s\ntype %s (%d)\n",
                           map->dev_name, map->name, map_type(map->type),
@@ -1290,8 +1382,7 @@ static int pinctrl_maps_show(struct seq_file *s, void *what)
 
                seq_printf(s, "\n");
        }
-
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pinctrl_maps_mutex);
 
        return 0;
 }
@@ -1304,7 +1395,7 @@ static int pinctrl_show(struct seq_file *s, void *what)
 
        seq_puts(s, "Requested pin control handlers their pinmux maps:\n");
 
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pinctrl_list_mutex);
 
        list_for_each_entry(p, &pinctrl_list, node) {
                seq_printf(s, "device: %s current state: %s\n",
@@ -1336,7 +1427,7 @@ static int pinctrl_show(struct seq_file *s, void *what)
                }
        }
 
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pinctrl_list_mutex);
 
        return 0;
 }
@@ -1522,6 +1613,7 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
        INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
        INIT_LIST_HEAD(&pctldev->gpio_ranges);
        pctldev->dev = dev;
+       mutex_init(&pctldev->mutex);
 
        /* check core ops for sanity */
        if (pinctrl_check_ops(pctldev)) {
@@ -1551,38 +1643,37 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
                goto out_err;
        }
 
-       mutex_lock(&pinctrl_mutex);
-
+       mutex_lock(&pinctrldev_list_mutex);
        list_add_tail(&pctldev->node, &pinctrldev_list);
+       mutex_unlock(&pinctrldev_list_mutex);
+
+       pctldev->p = pinctrl_get(pctldev->dev);
 
-       pctldev->p = pinctrl_get_locked(pctldev->dev);
        if (!IS_ERR(pctldev->p)) {
                pctldev->hog_default =
-                       pinctrl_lookup_state_locked(pctldev->p,
-                                                   PINCTRL_STATE_DEFAULT);
+                       pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
                if (IS_ERR(pctldev->hog_default)) {
                        dev_dbg(dev, "failed to lookup the default state\n");
                } else {
-                       if (pinctrl_select_state_locked(pctldev->p,
+                       if (pinctrl_select_state(pctldev->p,
                                                pctldev->hog_default))
                                dev_err(dev,
                                        "failed to select default state\n");
                }
 
                pctldev->hog_sleep =
-                       pinctrl_lookup_state_locked(pctldev->p,
+                       pinctrl_lookup_state(pctldev->p,
                                                    PINCTRL_STATE_SLEEP);
                if (IS_ERR(pctldev->hog_sleep))
                        dev_dbg(dev, "failed to lookup the sleep state\n");
        }
 
-       mutex_unlock(&pinctrl_mutex);
-
        pinctrl_init_device_debugfs(pctldev);
 
        return pctldev;
 
 out_err:
+       mutex_destroy(&pctldev->mutex);
        kfree(pctldev);
        return NULL;
 }
@@ -1600,12 +1691,13 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
        if (pctldev == NULL)
                return;
 
-       pinctrl_remove_device_debugfs(pctldev);
+       mutex_lock(&pinctrldev_list_mutex);
+       mutex_lock(&pctldev->mutex);
 
-       mutex_lock(&pinctrl_mutex);
+       pinctrl_remove_device_debugfs(pctldev);
 
        if (!IS_ERR(pctldev->p))
-               pinctrl_put_locked(pctldev->p, true);
+               pinctrl_put(pctldev->p);
 
        /* TODO: check that no pinmuxes are still active? */
        list_del(&pctldev->node);
@@ -1616,9 +1708,10 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
        list_for_each_entry_safe(range, n, &pctldev->gpio_ranges, node)
                list_del(&range->node);
 
+       mutex_unlock(&pctldev->mutex);
+       mutex_destroy(&pctldev->mutex);
        kfree(pctldev);
-
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pinctrldev_list_mutex);
 }
 EXPORT_SYMBOL_GPL(pinctrl_unregister);
 
index ee72f1f..75476b3 100644 (file)
@@ -33,6 +33,7 @@ struct pinctrl_gpio_range;
  * @p: result of pinctrl_get() for this device
  * @hog_default: default state for pins hogged by this device
  * @hog_sleep: sleep state for pins hogged by this device
+ * @mutex: mutex taken on each pin controller specific action
  * @device_root: debugfs root for this device
  */
 struct pinctrl_dev {
@@ -46,6 +47,7 @@ struct pinctrl_dev {
        struct pinctrl *p;
        struct pinctrl_state *hog_default;
        struct pinctrl_state *hog_sleep;
+       struct mutex mutex;
 #ifdef CONFIG_DEBUG_FS
        struct dentry *device_root;
 #endif
@@ -72,7 +74,7 @@ struct pinctrl {
 
 /**
  * struct pinctrl_state - a pinctrl state for a device
- * @node: list not for struct pinctrl's @states field
+ * @node: list node for struct pinctrl's @states field
  * @name: the name of this state
  * @settings: a list of settings for this state
  */
@@ -168,6 +170,7 @@ struct pinctrl_maps {
 };
 
 struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
+struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np);
 int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
 const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin);
 int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
@@ -186,8 +189,7 @@ void pinctrl_unregister_map(struct pinctrl_map const *map);
 extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev);
 extern int pinctrl_force_default(struct pinctrl_dev *pctldev);
 
-extern struct mutex pinctrl_mutex;
-extern struct list_head pinctrldev_list;
+extern struct mutex pinctrl_maps_mutex;
 extern struct list_head pinctrl_maps;
 
 #define for_each_maps(_maps_node_, _i_, _map_) \
index fd40a11..340fb4e 100644 (file)
@@ -41,7 +41,7 @@ static void dt_free_map(struct pinctrl_dev *pctldev,
                     struct pinctrl_map *map, unsigned num_maps)
 {
        if (pctldev) {
-               struct pinctrl_ops *ops = pctldev->desc->pctlops;
+               const struct pinctrl_ops *ops = pctldev->desc->pctlops;
                ops->dt_free_map(pctldev, map, num_maps);
        } else {
                /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
@@ -95,22 +95,11 @@ static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
        return pinctrl_register_map(map, num_maps, false, true);
 }
 
-static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
-{
-       struct pinctrl_dev *pctldev;
-
-       list_for_each_entry(pctldev, &pinctrldev_list, node)
-               if (pctldev->dev->of_node == np)
-                       return pctldev;
-
-       return NULL;
-}
-
 struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
 {
        struct pinctrl_dev *pctldev;
 
-       pctldev = find_pinctrl_by_of_node(np);
+       pctldev = get_pinctrl_dev_from_of_node(np);
        if (!pctldev)
                return NULL;
 
@@ -122,7 +111,7 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
 {
        struct device_node *np_pctldev;
        struct pinctrl_dev *pctldev;
-       struct pinctrl_ops *ops;
+       const struct pinctrl_ops *ops;
        int ret;
        struct pinctrl_map *map;
        unsigned num_maps;
@@ -138,7 +127,7 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
                        /* OK let's just assume this will appear later then */
                        return -EPROBE_DEFER;
                }
-               pctldev = find_pinctrl_by_of_node(np_pctldev);
+               pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
                if (pctldev)
                        break;
                /* Do not defer probing of hogs (circular loop) */
index 2d2f0a4..bb7ddb1 100644 (file)
@@ -263,7 +263,7 @@ static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
        return;
 }
 
-static struct pinconf_ops mvebu_pinconf_ops = {
+static const struct pinconf_ops mvebu_pinconf_ops = {
        .pin_config_group_get = mvebu_pinconf_group_get,
        .pin_config_group_set = mvebu_pinconf_group_set,
        .pin_config_group_dbg_show = mvebu_pinconf_group_dbg_show,
@@ -369,7 +369,7 @@ static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
        return -ENOTSUPP;
 }
 
-static struct pinmux_ops mvebu_pinmux_ops = {
+static const struct pinmux_ops mvebu_pinmux_ops = {
        .get_functions_count = mvebu_pinmux_get_funcs_count,
        .get_function_name = mvebu_pinmux_get_func_name,
        .get_function_groups = mvebu_pinmux_get_groups,
@@ -470,7 +470,7 @@ static void mvebu_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
        kfree(map);
 }
 
-static struct pinctrl_ops mvebu_pinctrl_ops = {
+static const struct pinctrl_ops mvebu_pinctrl_ops = {
        .get_groups_count = mvebu_pinctrl_get_groups_count,
        .get_group_name = mvebu_pinctrl_get_group_name,
        .get_group_pins = mvebu_pinctrl_get_group_pins,
@@ -478,8 +478,12 @@ static struct pinctrl_ops mvebu_pinctrl_ops = {
        .dt_free_map = mvebu_pinctrl_dt_free_map,
 };
 
-static int _add_function(struct mvebu_pinctrl_function *funcs, const char *name)
+static int _add_function(struct mvebu_pinctrl_function *funcs, int *funcsize,
+                       const char *name)
 {
+       if (*funcsize <= 0)
+               return -EOVERFLOW;
+
        while (funcs->num_groups) {
                /* function already there */
                if (strcmp(funcs->name, name) == 0) {
@@ -488,8 +492,12 @@ static int _add_function(struct mvebu_pinctrl_function *funcs, const char *name)
                }
                funcs++;
        }
+
+       /* append new unique function */
        funcs->name = name;
        funcs->num_groups = 1;
+       (*funcsize)--;
+
        return 0;
 }
 
@@ -497,12 +505,12 @@ static int mvebu_pinctrl_build_functions(struct platform_device *pdev,
                                         struct mvebu_pinctrl *pctl)
 {
        struct mvebu_pinctrl_function *funcs;
-       int num = 0;
+       int num = 0, funcsize = pctl->desc.npins;
        int n, s;
 
        /* we allocate functions for number of pins and hope
-        * there are less unique functions than pins available */
-       funcs = devm_kzalloc(&pdev->dev, pctl->desc.npins *
+        * there are fewer unique functions than pins available */
+       funcs = devm_kzalloc(&pdev->dev, funcsize *
                             sizeof(struct mvebu_pinctrl_function), GFP_KERNEL);
        if (!funcs)
                return -ENOMEM;
@@ -510,26 +518,27 @@ static int mvebu_pinctrl_build_functions(struct platform_device *pdev,
        for (n = 0; n < pctl->num_groups; n++) {
                struct mvebu_pinctrl_group *grp = &pctl->groups[n];
                for (s = 0; s < grp->num_settings; s++) {
+                       int ret;
+
                        /* skip unsupported settings on this variant */
                        if (pctl->variant &&
                            !(pctl->variant & grp->settings[s].variant))
                                continue;
 
                        /* check for unique functions and count groups */
-                       if (_add_function(funcs, grp->settings[s].name))
+                       ret = _add_function(funcs, &funcsize,
+                                           grp->settings[s].name);
+                       if (ret == -EOVERFLOW)
+                               dev_err(&pdev->dev,
+                                       "More functions than pins(%d)\n",
+                                       pctl->desc.npins);
+                       if (ret < 0)
                                continue;
 
                        num++;
                }
        }
 
-       /* with the number of unique functions and it's groups known,
-          reallocate functions and assign group names */
-       funcs = krealloc(funcs, num * sizeof(struct mvebu_pinctrl_function),
-                        GFP_KERNEL);
-       if (!funcs)
-               return -ENOMEM;
-
        pctl->num_functions = num;
        pctl->functions = funcs;
 
index 06c304a..2ad5a8d 100644 (file)
@@ -12,6 +12,7 @@
 #define pr_fmt(fmt) "generic pinconfig core: " fmt
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/slab.h>
@@ -33,7 +34,7 @@ struct pin_config_item {
 
 #define PCONFDUMP(a, b, c) { .param = a, .display = b, .format = c }
 
-struct pin_config_item conf_items[] = {
+static struct pin_config_item conf_items[] = {
        PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL),
        PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL),
        PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL),
@@ -59,7 +60,7 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
        if (!ops->is_generic)
                return;
 
-       for(i = 0; i < ARRAY_SIZE(conf_items); i++) {
+       for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
                unsigned long config;
                int ret;
 
@@ -94,7 +95,7 @@ void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
        if (!ops->is_generic)
                return;
 
-       for(i = 0; i < ARRAY_SIZE(conf_items); i++) {
+       for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
                unsigned long config;
                int ret;
 
@@ -120,4 +121,17 @@ void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
        }
 }
 
+void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
+                                struct seq_file *s, unsigned long config)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
+               if (pinconf_to_config_param(config) != conf_items[i].param)
+                       continue;
+               seq_printf(s, "%s: 0x%x", conf_items[i].display,
+                          pinconf_to_config_argument(config));
+       }
+}
+EXPORT_SYMBOL_GPL(pinconf_generic_dump_config);
 #endif
index d611ecf..c67c37e 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/uaccess.h>
 #include <linux/pinctrl/machine.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinconf.h>
@@ -88,14 +89,14 @@ int pin_config_get(const char *dev_name, const char *name,
        struct pinctrl_dev *pctldev;
        int pin;
 
-       mutex_lock(&pinctrl_mutex);
-
        pctldev = get_pinctrl_dev_from_devname(dev_name);
        if (!pctldev) {
                pin = -EINVAL;
-               goto unlock;
+               return pin;
        }
 
+       mutex_lock(&pctldev->mutex);
+
        pin = pin_get_from_name(pctldev, name);
        if (pin < 0)
                goto unlock;
@@ -103,7 +104,7 @@ int pin_config_get(const char *dev_name, const char *name,
        pin = pin_config_get_for_pin(pctldev, pin, config);
 
 unlock:
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
        return pin;
 }
 EXPORT_SYMBOL(pin_config_get);
@@ -144,14 +145,14 @@ int pin_config_set(const char *dev_name, const char *name,
        struct pinctrl_dev *pctldev;
        int pin, ret;
 
-       mutex_lock(&pinctrl_mutex);
-
        pctldev = get_pinctrl_dev_from_devname(dev_name);
        if (!pctldev) {
                ret = -EINVAL;
-               goto unlock;
+               return ret;
        }
 
+       mutex_lock(&pctldev->mutex);
+
        pin = pin_get_from_name(pctldev, name);
        if (pin < 0) {
                ret = pin;
@@ -161,7 +162,7 @@ int pin_config_set(const char *dev_name, const char *name,
        ret = pin_config_set_for_pin(pctldev, pin, config);
 
 unlock:
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
        return ret;
 }
 EXPORT_SYMBOL(pin_config_set);
@@ -173,13 +174,14 @@ int pin_config_group_get(const char *dev_name, const char *pin_group,
        const struct pinconf_ops *ops;
        int selector, ret;
 
-       mutex_lock(&pinctrl_mutex);
-
        pctldev = get_pinctrl_dev_from_devname(dev_name);
        if (!pctldev) {
                ret = -EINVAL;
-               goto unlock;
+               return ret;
        }
+
+       mutex_lock(&pctldev->mutex);
+
        ops = pctldev->desc->confops;
 
        if (!ops || !ops->pin_config_group_get) {
@@ -199,7 +201,7 @@ int pin_config_group_get(const char *dev_name, const char *pin_group,
        ret = ops->pin_config_group_get(pctldev, selector, config);
 
 unlock:
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
        return ret;
 }
 EXPORT_SYMBOL(pin_config_group_get);
@@ -216,13 +218,14 @@ int pin_config_group_set(const char *dev_name, const char *pin_group,
        int ret;
        int i;
 
-       mutex_lock(&pinctrl_mutex);
-
        pctldev = get_pinctrl_dev_from_devname(dev_name);
        if (!pctldev) {
                ret = -EINVAL;
-               goto unlock;
+               return ret;
        }
+
+       mutex_lock(&pctldev->mutex);
+
        ops = pctldev->desc->confops;
        pctlops = pctldev->desc->pctlops;
 
@@ -278,7 +281,7 @@ int pin_config_group_set(const char *dev_name, const char *pin_group,
        ret = 0;
 
 unlock:
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
 
        return ret;
 }
@@ -486,7 +489,7 @@ static int pinconf_pins_show(struct seq_file *s, void *what)
        seq_puts(s, "Pin config settings per pin\n");
        seq_puts(s, "Format: pin (name): configs\n");
 
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pctldev->mutex);
 
        /* The pin number can be retrived from the pin controller descriptor */
        for (i = 0; i < pctldev->desc->npins; i++) {
@@ -506,7 +509,7 @@ static int pinconf_pins_show(struct seq_file *s, void *what)
                seq_printf(s, "\n");
        }
 
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
 
        return 0;
 }
@@ -574,122 +577,58 @@ static const struct file_operations pinconf_groups_ops = {
        .release        = single_release,
 };
 
-/* 32bit read/write ressources */
-#define MAX_NAME_LEN 16
-char dbg_pinname[MAX_NAME_LEN]; /* shared: name of the state of the pin*/
-char dbg_state_name[MAX_NAME_LEN]; /* shared: state of the pin*/
-static u32 dbg_config; /* shared: config to be read/set for the pin & state*/
-
-static int pinconf_dbg_pinname_print(struct seq_file *s, void *d)
-{
-       if (strlen(dbg_pinname))
-               seq_printf(s, "%s\n", dbg_pinname);
-       else
-               seq_printf(s, "No pin name set\n");
-       return 0;
-}
-
-static int pinconf_dbg_pinname_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, pinconf_dbg_pinname_print, inode->i_private);
-}
-
-static int pinconf_dbg_pinname_write(struct file *file,
-       const char __user *user_buf, size_t count, loff_t *ppos)
-{
-       int err;
-
-       if (count > MAX_NAME_LEN)
-               return -EINVAL;
-
-       err = sscanf(user_buf, "%15s", dbg_pinname);
-
-       if (err != 1)
-               return -EINVAL;
-
-       return count;
-}
+#define MAX_NAME_LEN 15
 
-static const struct file_operations pinconf_dbg_pinname_fops = {
-       .open = pinconf_dbg_pinname_open,
-       .write = pinconf_dbg_pinname_write,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
+struct dbg_cfg {
+       enum pinctrl_map_type map_type;
+       char dev_name[MAX_NAME_LEN+1];
+       char state_name[MAX_NAME_LEN+1];
+       char pin_name[MAX_NAME_LEN+1];
 };
 
-static int pinconf_dbg_state_print(struct seq_file *s, void *d)
-{
-       if (strlen(dbg_state_name))
-               seq_printf(s, "%s\n", dbg_state_name);
-       else
-               seq_printf(s, "No pin state set\n");
-       return 0;
-}
-
-static int pinconf_dbg_state_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, pinconf_dbg_state_print, inode->i_private);
-}
-
-static int pinconf_dbg_state_write(struct file *file,
-       const char __user *user_buf, size_t count, loff_t *ppos)
-{
-       int err;
-
-       if (count > MAX_NAME_LEN)
-               return -EINVAL;
-
-       err = sscanf(user_buf, "%15s", dbg_state_name);
-
-       if (err != 1)
-               return -EINVAL;
-
-       return count;
-}
-
-static const struct file_operations pinconf_dbg_pinstate_fops = {
-       .open = pinconf_dbg_state_open,
-       .write = pinconf_dbg_state_write,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
-};
+/*
+ * Goal is to keep this structure as global in order to simply read the
+ * pinconf-config file after a write to check config is as expected
+ */
+static struct dbg_cfg pinconf_dbg_conf;
 
 /**
  * pinconf_dbg_config_print() - display the pinctrl config from the pinctrl
- * map, of a pin/state pair based on pinname and state that have been
- * selected with the debugfs entries pinconf-name and pinconf-state
- * @s: contains the 32bits config to be written
+ * map, of the dev/pin/state that was last written to pinconf-config file.
+ * @s: string filled in  with config description
  * @d: not used
  */
 static int pinconf_dbg_config_print(struct seq_file *s, void *d)
 {
        struct pinctrl_maps *maps_node;
-       struct pinctrl_map const *map;
+       const struct pinctrl_map *map;
        struct pinctrl_dev *pctldev = NULL;
-       struct pinconf_ops *confops = NULL;
+       const struct pinconf_ops *confops = NULL;
+       const struct pinctrl_map_configs *configs;
+       struct dbg_cfg *dbg = &pinconf_dbg_conf;
        int i, j;
        bool found = false;
+       unsigned long config;
 
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pctldev->mutex);
 
        /* Parse the pinctrl map and look for the elected pin/state */
        for_each_maps(maps_node, i, map) {
-               if (map->type != PIN_MAP_TYPE_CONFIGS_PIN)
+               if (map->type != dbg->map_type)
                        continue;
-
-               if (strncmp(map->name, dbg_state_name, MAX_NAME_LEN) > 0)
+               if (strcmp(map->dev_name, dbg->dev_name))
+                       continue;
+               if (strcmp(map->name, dbg->state_name))
                        continue;
 
                for (j = 0; j < map->data.configs.num_configs; j++) {
-                       if (0 == strncmp(map->data.configs.group_or_pin,
-                                               dbg_pinname, MAX_NAME_LEN)) {
-                               /* We found the right pin / state, read the
-                                * config and store the pctldev */
-                               dbg_config = map->data.configs.configs[j];
+                       if (!strcmp(map->data.configs.group_or_pin,
+                                       dbg->pin_name)) {
+                               /*
+                                * We found the right pin / state, read the
+                                * config and he pctldev for later use
+                                */
+                               configs = &map->data.configs;
                                pctldev = get_pinctrl_dev_from_devname
                                        (map->ctrl_dev_name);
                                found = true;
@@ -698,74 +637,166 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d)
                }
        }
 
-       mutex_unlock(&pinctrl_mutex);
+       if (!found) {
+               seq_printf(s, "No config found for dev/state/pin, expected:\n");
+               seq_printf(s, "Searched dev:%s\n", dbg->dev_name);
+               seq_printf(s, "Searched state:%s\n", dbg->state_name);
+               seq_printf(s, "Searched pin:%s\n", dbg->pin_name);
+               seq_printf(s, "Use: modify config_pin <devname> "\
+                               "<state> <pinname> <value>\n");
+               goto exit;
+       }
 
-       if (found) {
-               seq_printf(s, "Config of %s in state %s: 0x%08X\n", dbg_pinname,
-                                dbg_state_name, dbg_config);
+       config = *(configs->configs);
+       seq_printf(s, "Dev %s has config of %s in state %s: 0x%08lX\n",
+                       dbg->dev_name, dbg->pin_name,
+                       dbg->state_name, config);
 
-               if (pctldev)
-                       confops = pctldev->desc->confops;
+       if (pctldev)
+               confops = pctldev->desc->confops;
 
-               if (confops && confops->pin_config_config_dbg_show)
-                       confops->pin_config_config_dbg_show(pctldev,
-                                       s, dbg_config);
-       } else {
-               seq_printf(s, "No pin found for defined name/state\n");
-       }
+       if (confops && confops->pin_config_config_dbg_show)
+               confops->pin_config_config_dbg_show(pctldev, s, config);
 
-       return 0;
-}
+exit:
+       mutex_unlock(&pctldev->mutex);
 
-static int pinconf_dbg_config_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, pinconf_dbg_config_print, inode->i_private);
+       return 0;
 }
 
 /**
- * pinconf_dbg_config_write() - overwrite the pinctrl config in thepinctrl
- * map, of a pin/state pair based on pinname and state that have been
- * selected with the debugfs entries pinconf-name and pinconf-state
+ * pinconf_dbg_config_write() - modify the pinctrl config in the pinctrl
+ * map, of a dev/pin/state entry based on user entries to pinconf-config
+ * @user_buf: contains the modification request with expected format:
+ *     modify config_pin <devicename> <state> <pinname> <newvalue>
+ * modify is literal string, alternatives like add/delete not supported yet
+ * config_pin is literal, alternatives like config_mux not supported yet
+ * <devicename> <state> <pinname> are values that should match the pinctrl-maps
+ * <newvalue> reflects the new config and is driver dependant
  */
 static int pinconf_dbg_config_write(struct file *file,
        const char __user *user_buf, size_t count, loff_t *ppos)
 {
-       int err;
-       unsigned long config;
        struct pinctrl_maps *maps_node;
-       struct pinctrl_map const *map;
-       int i, j;
+       const struct pinctrl_map *map;
+       struct pinctrl_dev *pctldev = NULL;
+       const struct pinconf_ops *confops = NULL;
+       struct dbg_cfg *dbg = &pinconf_dbg_conf;
+       const struct pinctrl_map_configs *configs;
+       char config[MAX_NAME_LEN+1];
+       bool found = false;
+       char buf[128];
+       char *b = &buf[0];
+       int buf_size;
+       char *token;
+       int i;
+
+       /* Get userspace string and assure termination */
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       /*
+        * need to parse entry and extract parameters:
+        * modify configs_pin devicename state pinname newvalue
+        */
+
+       /* Get arg: 'modify' */
+       token = strsep(&b, " ");
+       if (!token)
+               return -EINVAL;
+       if (strcmp(token, "modify"))
+               return -EINVAL;
 
-       err = kstrtoul_from_user(user_buf, count, 0, &config);
+       /* Get arg type: "config_pin" type supported so far */
+       token = strsep(&b, " ");
+       if (!token)
+               return -EINVAL;
+       if (strcmp(token, "config_pin"))
+               return -EINVAL;
+       dbg->map_type = PIN_MAP_TYPE_CONFIGS_PIN;
 
-       if (err)
-               return err;
+       /* get arg 'device_name' */
+       token = strsep(&b, " ");
+       if (token == NULL)
+               return -EINVAL;
+       if (strlen(token) >= MAX_NAME_LEN)
+               return -EINVAL;
+       strncpy(dbg->dev_name, token, MAX_NAME_LEN);
 
-       dbg_config = config;
+       /* get arg 'state_name' */
+       token = strsep(&b, " ");
+       if (token == NULL)
+               return -EINVAL;
+       if (strlen(token) >= MAX_NAME_LEN)
+               return -EINVAL;
+       strncpy(dbg->state_name, token, MAX_NAME_LEN);
 
-       mutex_lock(&pinctrl_mutex);
+       /* get arg 'pin_name' */
+       token = strsep(&b, " ");
+       if (token == NULL)
+               return -EINVAL;
+       if (strlen(token) >= MAX_NAME_LEN)
+               return -EINVAL;
+       strncpy(dbg->pin_name, token, MAX_NAME_LEN);
 
-       /* Parse the pinctrl map and look for the selected pin/state */
+       /* get new_value of config' */
+       token = strsep(&b, " ");
+       if (token == NULL)
+               return -EINVAL;
+       if (strlen(token) >= MAX_NAME_LEN)
+               return -EINVAL;
+       strncpy(config, token, MAX_NAME_LEN);
+
+       mutex_lock(&pinctrl_maps_mutex);
+
+       /* Parse the pinctrl map and look for the selected dev/state/pin */
        for_each_maps(maps_node, i, map) {
-               if (map->type != PIN_MAP_TYPE_CONFIGS_PIN)
+               if (strcmp(map->dev_name, dbg->dev_name))
                        continue;
-
-               if (strncmp(map->name, dbg_state_name, MAX_NAME_LEN) > 0)
+               if (map->type != dbg->map_type)
+                       continue;
+               if (strcmp(map->name, dbg->state_name))
                        continue;
 
                /*  we found the right pin / state, so overwrite config */
-               for (j = 0; j < map->data.configs.num_configs; j++) {
-                       if (strncmp(map->data.configs.group_or_pin, dbg_pinname,
-                                               MAX_NAME_LEN) == 0)
-                               map->data.configs.configs[j] = dbg_config;
+               if (!strcmp(map->data.configs.group_or_pin, dbg->pin_name)) {
+                       found = true;
+                       pctldev = get_pinctrl_dev_from_devname(
+                                       map->ctrl_dev_name);
+                       configs = &map->data.configs;
+                       break;
                }
        }
 
-       mutex_unlock(&pinctrl_mutex);
+       if (!found) {
+               count = -EINVAL;
+               goto exit;
+       }
+
+       if (pctldev)
+               confops = pctldev->desc->confops;
+
+       if (confops && confops->pin_config_dbg_parse_modify) {
+               for (i = 0; i < configs->num_configs; i++) {
+                       confops->pin_config_dbg_parse_modify(pctldev,
+                                                    config,
+                                                    &configs->configs[i]);
+               }
+       }
+
+exit:
+       mutex_unlock(&pinctrl_maps_mutex);
 
        return count;
 }
 
+static int pinconf_dbg_config_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, pinconf_dbg_config_print, inode->i_private);
+}
+
 static const struct file_operations pinconf_dbg_pinconfig_fops = {
        .open = pinconf_dbg_config_open,
        .write = pinconf_dbg_config_write,
@@ -782,10 +813,6 @@ void pinconf_init_device_debugfs(struct dentry *devroot,
                            devroot, pctldev, &pinconf_pins_ops);
        debugfs_create_file("pinconf-groups", S_IFREG | S_IRUGO,
                            devroot, pctldev, &pinconf_groups_ops);
-       debugfs_create_file("pinconf-name", (S_IRUGO | S_IWUSR | S_IWGRP),
-                           devroot, pctldev, &pinconf_dbg_pinname_fops);
-       debugfs_create_file("pinconf-state",  (S_IRUGO | S_IWUSR | S_IWGRP),
-                           devroot, pctldev, &pinconf_dbg_pinstate_fops);
        debugfs_create_file("pinconf-config",  (S_IRUGO | S_IWUSR | S_IWGRP),
                            devroot, pctldev, &pinconf_dbg_pinconfig_fops);
 }
index bfda73d..92c7267 100644 (file)
@@ -98,6 +98,8 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
 void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
                              struct seq_file *s, const char *gname);
 
+void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
+                                struct seq_file *s, unsigned long config);
 #else
 
 static inline void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
@@ -114,4 +116,10 @@ static inline void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
        return;
 }
 
+static inline void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
+                                              struct seq_file *s,
+                                              unsigned long config)
+{
+       return;
+}
 #endif
index 3b471d8..2ac2d0a 100644 (file)
@@ -389,7 +389,8 @@ static const struct abx500_function ab8500_functions[] = {
  *     alt_A   |       1       |          0          |          0
  */
 
-struct alternate_functions ab8500_alternate_functions[AB8500_GPIO_MAX_NUMBER + 1] = {
+static struct
+alternate_functions ab8500_alternate_functions[AB8500_GPIO_MAX_NUMBER + 1] = {
        ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
        ALTERNATE_FUNCTIONS(1,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
        ALTERNATE_FUNCTIONS(2,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
@@ -455,7 +456,7 @@ struct alternate_functions ab8500_alternate_functions[AB8500_GPIO_MAX_NUMBER + 1
  *     GPIO24 and GPIO25
  *     GPIO36 to GPIO41
  */
-struct abx500_gpio_irq_cluster ab8500_gpio_irq_cluster[] = {
+static struct abx500_gpio_irq_cluster ab8500_gpio_irq_cluster[] = {
        GPIO_IRQ_CLUSTER(6,  13, AB8500_INT_GPIO6R),
        GPIO_IRQ_CLUSTER(24, 25, AB8500_INT_GPIO24R),
        GPIO_IRQ_CLUSTER(36, 41, AB8500_INT_GPIO36R),
index 3a4238e..bf0ef4a 100644 (file)
@@ -271,7 +271,8 @@ static const struct abx500_function ab8505_functions[] = {
  *     alt_A   |       1       |          0          |          0
  */
 
-struct alternate_functions ab8505_alternate_functions[AB8505_GPIO_MAX_NUMBER + 1] = {
+static struct
+alternate_functions ab8505_alternate_functions[AB8505_GPIO_MAX_NUMBER + 1] = {
        ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
        ALTERNATE_FUNCTIONS(1,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
        ALTERNATE_FUNCTIONS(2,      1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
@@ -284,7 +285,7 @@ struct alternate_functions ab8505_alternate_functions[AB8505_GPIO_MAX_NUMBER + 1
 
        ALTERNATE_FUNCTIONS(9, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO9, bit 0 reserved */
        ALTERNATE_FUNCTIONS(10,      1,      0, UNUSED, 1, 0, 0), /* GPIO10, altA and altB controlled by bit 0 */
-       ALTERNATE_FUNCTIONS(11,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 2 */
+       ALTERNATE_FUNCTIONS(11,      2,      1, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 2 */
        ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12, bit3 reseved */
        ALTERNATE_FUNCTIONS(13,      4,      3,      4, 1, 0, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */
        ALTERNATE_FUNCTIONS(14,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
@@ -348,7 +349,7 @@ struct alternate_functions ab8505_alternate_functions[AB8505_GPIO_MAX_NUMBER + 1
  *     GPIO50
  *     GPIO52 to GPIO53
  */
-struct abx500_gpio_irq_cluster ab8505_gpio_irq_cluster[] = {
+static struct abx500_gpio_irq_cluster ab8505_gpio_irq_cluster[] = {
        GPIO_IRQ_CLUSTER(10, 11, AB8500_INT_GPIO10R),
        GPIO_IRQ_CLUSTER(13, 13, AB8500_INT_GPIO13R),
        GPIO_IRQ_CLUSTER(40, 41, AB8500_INT_GPIO40R),
index 8ee1e8d..9867535 100644 (file)
@@ -299,7 +299,8 @@ static const struct abx500_function ab8540_functions[] = {
  *
  */
 
-struct alternate_functions ab8540_alternate_functions[AB8540_GPIO_MAX_NUMBER + 1] = {
+static struct
+alternate_functions ab8540_alternate_functions[AB8540_GPIO_MAX_NUMBER + 1] = {
        /* GPIOSEL1 - bit 4-7 reserved */
        ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
        ALTERNATE_FUNCTIONS(1,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
@@ -376,7 +377,7 @@ static struct pullud ab8540_pullud = {
  *     GPIO43 to GPIO44
  *     GPIO51 to GPIO54
  */
-struct abx500_gpio_irq_cluster ab8540_gpio_irq_cluster[] = {
+static struct abx500_gpio_irq_cluster ab8540_gpio_irq_cluster[] = {
        GPIO_IRQ_CLUSTER(43, 43, AB8540_INT_GPIO43F),
        GPIO_IRQ_CLUSTER(44, 44, AB8540_INT_GPIO44F),
        GPIO_IRQ_CLUSTER(51, 54, AB9540_INT_GPIO51R),
index 7610bd0..1a281ca 100644 (file)
@@ -379,7 +379,8 @@ static const struct abx500_function ab9540_functions[] = {
  *     alt_A   |       1       |          0          |          0
  */
 
-struct alternate_functions ab9540alternate_functions[AB9540_GPIO_MAX_NUMBER + 1] = {
+static struct
+alternate_functions ab9540alternate_functions[AB9540_GPIO_MAX_NUMBER + 1] = {
        /* GPIOSEL1 - bits 4-7 are reserved */
        ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
        ALTERNATE_FUNCTIONS(1,      0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
@@ -393,7 +394,7 @@ struct alternate_functions ab9540alternate_functions[AB9540_GPIO_MAX_NUMBER + 1]
        /* GPIOSEL2 - bits 0 and 3 are reserved */
        ALTERNATE_FUNCTIONS(9, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO9 */
        ALTERNATE_FUNCTIONS(10,      1,      0, UNUSED, 1, 0, 0), /* GPIO10, altA and altB controlled by bit 0 */
-       ALTERNATE_FUNCTIONS(11,      2, UNUSED, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 1 */
+       ALTERNATE_FUNCTIONS(11,      2,      1, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 1 */
        ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12 */
        ALTERNATE_FUNCTIONS(13,      4,      3,      4, 1, 0, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */
        ALTERNATE_FUNCTIONS(14,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
@@ -454,7 +455,7 @@ struct alternate_functions ab9540alternate_functions[AB9540_GPIO_MAX_NUMBER + 1]
        ALTERNATE_FUNCTIONS(54,      5, UNUSED, UNUSED, 0, 0, 0), /* GPIO54 = GPIO60, altA controlled by bit 5 */
 };
 
-struct abx500_gpio_irq_cluster ab9540_gpio_irq_cluster[] = {
+static struct abx500_gpio_irq_cluster ab9540_gpio_irq_cluster[] = {
        GPIO_IRQ_CLUSTER(10, 13, AB8500_INT_GPIO10R),
        GPIO_IRQ_CLUSTER(24, 25, AB8500_INT_GPIO24R),
        GPIO_IRQ_CLUSTER(40, 41, AB8500_INT_GPIO40R),
index c542a97..aa17f75 100644 (file)
@@ -517,14 +517,14 @@ static inline void abx500_gpio_dbg_show_one(struct seq_file *s,
 #define abx500_gpio_dbg_show   NULL
 #endif
 
-int abx500_gpio_request(struct gpio_chip *chip, unsigned offset)
+static int abx500_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
        int gpio = chip->base + offset;
 
        return pinctrl_request_gpio(gpio);
 }
 
-void abx500_gpio_free(struct gpio_chip *chip, unsigned offset)
+static void abx500_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
        int gpio = chip->base + offset;
 
@@ -611,7 +611,7 @@ static void abx500_pmx_disable(struct pinctrl_dev *pctldev,
        dev_dbg(pct->dev, "disable group %s, %u pins\n", g->name, g->npins);
 }
 
-int abx500_gpio_request_enable(struct pinctrl_dev *pctldev,
+static int abx500_gpio_request_enable(struct pinctrl_dev *pctldev,
                               struct pinctrl_gpio_range *range,
                               unsigned offset)
 {
@@ -656,7 +656,7 @@ static void abx500_gpio_disable_free(struct pinctrl_dev *pctldev,
 {
 }
 
-static struct pinmux_ops abx500_pinmux_ops = {
+static const struct pinmux_ops abx500_pinmux_ops = {
        .get_functions_count = abx500_pmx_get_funcs_cnt,
        .get_function_name = abx500_pmx_get_func_name,
        .get_function_groups = abx500_pmx_get_func_groups,
@@ -704,21 +704,21 @@ static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev,
                                 chip->base + offset - 1);
 }
 
-static struct pinctrl_ops abx500_pinctrl_ops = {
+static const struct pinctrl_ops abx500_pinctrl_ops = {
        .get_groups_count = abx500_get_groups_cnt,
        .get_group_name = abx500_get_group_name,
        .get_group_pins = abx500_get_group_pins,
        .pin_dbg_show = abx500_pin_dbg_show,
 };
 
-int abx500_pin_config_get(struct pinctrl_dev *pctldev,
+static int abx500_pin_config_get(struct pinctrl_dev *pctldev,
                          unsigned pin,
                          unsigned long *config)
 {
        return -ENOSYS;
 }
 
-int abx500_pin_config_set(struct pinctrl_dev *pctldev,
+static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
                          unsigned pin,
                          unsigned long config)
 {
@@ -778,7 +778,7 @@ int abx500_pin_config_set(struct pinctrl_dev *pctldev,
        return ret;
 }
 
-static struct pinconf_ops abx500_pinconf_ops = {
+static const struct pinconf_ops abx500_pinconf_ops = {
        .pin_config_get = abx500_pin_config_get,
        .pin_config_set = abx500_pin_config_set,
 };
@@ -834,6 +834,7 @@ static const struct of_device_id abx500_gpio_match[] = {
        { .compatible = "stericsson,ab8505-gpio", .data = (void *)PINCTRL_AB8505, },
        { .compatible = "stericsson,ab8540-gpio", .data = (void *)PINCTRL_AB8540, },
        { .compatible = "stericsson,ab9540-gpio", .data = (void *)PINCTRL_AB9540, },
+       { }
 };
 
 static int abx500_gpio_probe(struct platform_device *pdev)
@@ -879,7 +880,6 @@ static int abx500_gpio_probe(struct platform_device *pdev)
        pct->parent = dev_get_drvdata(pdev->dev.parent);
        pct->chip = abx500gpio_chip;
        pct->chip.dev = &pdev->dev;
-       pct->chip.base = pdata->gpio_base;
        pct->chip.base = (np) ? -1 : pdata->gpio_base;
 
        /* initialize the lock */
index efb7f10..4d7f531 100644 (file)
@@ -294,7 +294,7 @@ static void at91_dt_free_map(struct pinctrl_dev *pctldev,
 {
 }
 
-static struct pinctrl_ops at91_pctrl_ops = {
+static const struct pinctrl_ops at91_pctrl_ops = {
        .get_groups_count       = at91_get_groups_count,
        .get_group_name         = at91_get_group_name,
        .get_group_pins         = at91_get_group_pins,
@@ -303,7 +303,7 @@ static struct pinctrl_ops at91_pctrl_ops = {
        .dt_free_map            = at91_dt_free_map,
 };
 
-static void __iomem * pin_to_controller(struct at91_pinctrl *info,
+static void __iomem *pin_to_controller(struct at91_pinctrl *info,
                                 unsigned int bank)
 {
        return gpio_chips[bank]->regbase;
@@ -501,7 +501,7 @@ static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pi
        }
 }
 
-static int pin_check_config(struct at91_pinctrl *info, const charname,
+static int pin_check_config(struct at91_pinctrl *info, const char *name,
                            int index, const struct at91_pmx_pin *pin)
 {
        int mux;
@@ -579,7 +579,7 @@ static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
                pio = pin_to_controller(info, pin->bank);
                mask = pin_to_mask(pin->pin);
                at91_mux_disable_interrupt(pio, mask);
-               switch(pin->mux) {
+               switch (pin->mux) {
                case AT91_MUX_GPIO:
                        at91_mux_gpio_enable(pio, mask, 1);
                        break;
@@ -696,7 +696,7 @@ static void at91_gpio_disable_free(struct pinctrl_dev *pctldev,
        /* Set the pin to some default state, GPIO is usually default */
 }
 
-static struct pinmux_ops at91_pmx_ops = {
+static const struct pinmux_ops at91_pmx_ops = {
        .get_functions_count    = at91_pmx_get_funcs_count,
        .get_function_name      = at91_pmx_get_func_name,
        .get_function_groups    = at91_pmx_get_groups,
@@ -776,7 +776,7 @@ static void at91_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
 {
 }
 
-static struct pinconf_ops at91_pinconf_ops = {
+static const struct pinconf_ops at91_pinconf_ops = {
        .pin_config_get                 = at91_pinconf_get,
        .pin_config_set                 = at91_pinconf_set,
        .pin_config_dbg_show            = at91_pinconf_dbg_show,
@@ -812,7 +812,7 @@ static int at91_pinctrl_mux_mask(struct at91_pinctrl *info,
 {
        int ret = 0;
        int size;
-       const const __be32 *list;
+       const __be32 *list;
 
        list = of_get_property(np, "atmel,mux-mask", &size);
        if (!list) {
@@ -846,7 +846,7 @@ static int at91_pinctrl_parse_groups(struct device_node *np,
 {
        struct at91_pmx_pin *pin;
        int size;
-       const const __be32 *list;
+       const __be32 *list;
        int i, j;
 
        dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
@@ -944,7 +944,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev,
                return -ENODEV;
 
        info->dev = &pdev->dev;
-       info->ops = (struct at91_pinctrl_mux_ops*)
+       info->ops = (struct at91_pinctrl_mux_ops *)
                of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
        at91_pinctrl_child_count(info, np);
 
@@ -1002,7 +1002,7 @@ static int at91_pinctrl_probe(struct platform_device *pdev)
 {
        struct at91_pinctrl *info;
        struct pinctrl_pin_desc *pdesc;
-       int ret, i, j ,k;
+       int ret, i, jk;
 
        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
@@ -1568,7 +1568,7 @@ static int at91_gpio_probe(struct platform_device *pdev)
                goto err;
        }
 
-       at91_chip->ops = (struct at91_pinctrl_mux_ops*)
+       at91_chip->ops = (struct at91_pinctrl_mux_ops *)
                of_match_device(at91_gpio_of_match, &pdev->dev)->data;
        at91_chip->pioc_virq = irq;
        at91_chip->pioc_idx = alias_idx;
@@ -1605,7 +1605,8 @@ static int at91_gpio_probe(struct platform_device *pdev)
                        chip->ngpio = ngpio;
        }
 
-       names = devm_kzalloc(&pdev->dev, sizeof(char*) * chip->ngpio, GFP_KERNEL);
+       names = devm_kzalloc(&pdev->dev, sizeof(char *) * chip->ngpio,
+                            GFP_KERNEL);
 
        if (!names) {
                ret = -ENOMEM;
@@ -1615,7 +1616,7 @@ static int at91_gpio_probe(struct platform_device *pdev)
        for (i = 0; i < chip->ngpio; i++)
                names[i] = kasprintf(GFP_KERNEL, "pio%c%d", alias_idx + 'A', i);
 
-       chip->names = (const char*const*)names;
+       chip->names = (const char *const *)names;
 
        range = &at91_chip->range;
        range->name = chip->label;
index 4eb6d2c..f28d4b0 100644 (file)
@@ -795,7 +795,7 @@ out:
        return err;
 }
 
-static struct pinctrl_ops bcm2835_pctl_ops = {
+static const struct pinctrl_ops bcm2835_pctl_ops = {
        .get_groups_count = bcm2835_pctl_get_groups_count,
        .get_group_name = bcm2835_pctl_get_group_name,
        .get_group_pins = bcm2835_pctl_get_group_pins,
@@ -872,7 +872,7 @@ static int bcm2835_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
        return 0;
 }
 
-static struct pinmux_ops bcm2835_pmx_ops = {
+static const struct pinmux_ops bcm2835_pmx_ops = {
        .get_functions_count = bcm2835_pmx_get_functions_count,
        .get_function_name = bcm2835_pmx_get_function_name,
        .get_function_groups = bcm2835_pmx_get_function_groups,
@@ -916,7 +916,7 @@ static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev,
        return 0;
 }
 
-static struct pinconf_ops bcm2835_pinconf_ops = {
+static const struct pinconf_ops bcm2835_pinconf_ops = {
        .pin_config_get = bcm2835_pinconf_get,
        .pin_config_set = bcm2835_pinconf_set,
 };
index 8b7e7bc..edde3ac 100644 (file)
@@ -318,13 +318,16 @@ static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
        struct u300_gpio_port *port = NULL;
        struct list_head *p;
        int retirq;
+       bool found = false;
 
        list_for_each(p, &gpio->port_list) {
                port = list_entry(p, struct u300_gpio_port, node);
-               if (port->number == portno)
+               if (port->number == portno) {
+                       found = true;
                        break;
+               }
        }
-       if (port == NULL) {
+       if (!found) {
                dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n",
                        offset);
                return -EINVAL;
@@ -359,7 +362,7 @@ int u300_gpio_config_get(struct gpio_chip *chip,
        drmode &= (U300_GPIO_PXPCR_PIN_MODE_MASK << ((offset & 0x07) << 1));
        drmode >>= ((offset & 0x07) << 1);
 
-       switch(param) {
+       switch (param) {
        case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
                *config = 0;
                if (biasmode)
index 538b9dd..8b10b1a 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/of_irq.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <linux/err.h>
 
 #include <asm/mach/irq.h>
 #include "pinctrl-samsung.h"
 #include "pinctrl-exynos.h"
 
+
+static struct samsung_pin_bank_type bank_type_off = {
+       .fld_width = { 4, 1, 2, 2, 2, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, },
+};
+
+static struct samsung_pin_bank_type bank_type_alive = {
+       .fld_width = { 4, 1, 2, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, 0x0c, },
+};
+
 /* list of external wakeup controllers supported */
 static const struct of_device_id exynos_wkup_irq_ids[] = {
        { .compatible = "samsung,exynos4210-wakeup-eint", },
@@ -75,12 +87,14 @@ static void exynos_gpio_irq_ack(struct irq_data *irqd)
 static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
 {
        struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pin_bank_type *bank_type = bank->type;
        struct samsung_pinctrl_drv_data *d = bank->drvdata;
        struct samsung_pin_ctrl *ctrl = d->ctrl;
        unsigned int pin = irqd->hwirq;
        unsigned int shift = EXYNOS_EINT_CON_LEN * pin;
        unsigned int con, trig_type;
        unsigned long reg_con = ctrl->geint_con + bank->eint_offset;
+       unsigned long flags;
        unsigned int mask;
 
        switch (type) {
@@ -114,15 +128,19 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
        con |= trig_type << shift;
        writel(con, d->virt_base + reg_con);
 
-       reg_con = bank->pctl_offset;
-       shift = pin * bank->func_width;
-       mask = (1 << bank->func_width) - 1;
+       reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC];
+       shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC];
+       mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+
+       spin_lock_irqsave(&bank->slock, flags);
 
        con = readl(d->virt_base + reg_con);
        con &= ~(mask << shift);
        con |= EXYNOS_EINT_FUNC << shift;
        writel(con, d->virt_base + reg_con);
 
+       spin_unlock_irqrestore(&bank->slock, flags);
+
        return 0;
 }
 
@@ -253,11 +271,13 @@ static void exynos_wkup_irq_ack(struct irq_data *irqd)
 static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type)
 {
        struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pin_bank_type *bank_type = bank->type;
        struct samsung_pinctrl_drv_data *d = bank->drvdata;
        unsigned int pin = irqd->hwirq;
        unsigned long reg_con = d->ctrl->weint_con + bank->eint_offset;
        unsigned long shift = EXYNOS_EINT_CON_LEN * pin;
        unsigned long con, trig_type;
+       unsigned long flags;
        unsigned int mask;
 
        switch (type) {
@@ -291,15 +311,19 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type)
        con |= trig_type << shift;
        writel(con, d->virt_base + reg_con);
 
-       reg_con = bank->pctl_offset;
-       shift = pin * bank->func_width;
-       mask = (1 << bank->func_width) - 1;
+       reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC];
+       shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC];
+       mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+
+       spin_lock_irqsave(&bank->slock, flags);
 
        con = readl(d->virt_base + reg_con);
        con &= ~(mask << shift);
        con |= EXYNOS_EINT_FUNC << shift;
        writel(con, d->virt_base + reg_con);
 
+       spin_unlock_irqrestore(&bank->slock, flags);
+
        return 0;
 }
 
index 0a70889..9b1f77a 100644 (file)
 
 #define EXYNOS_PIN_BANK_EINTN(pins, reg, id)           \
        {                                               \
+               .type           = &bank_type_off,       \
                .pctl_offset    = reg,                  \
                .nr_pins        = pins,                 \
-               .func_width     = 4,                    \
-               .pud_width      = 2,                    \
-               .drv_width      = 2,                    \
-               .conpdn_width   = 2,                    \
-               .pudpdn_width   = 2,                    \
                .eint_type      = EINT_TYPE_NONE,       \
                .name           = id                    \
        }
 
 #define EXYNOS_PIN_BANK_EINTG(pins, reg, id, offs)     \
        {                                               \
+               .type           = &bank_type_off,       \
                .pctl_offset    = reg,                  \
                .nr_pins        = pins,                 \
-               .func_width     = 4,                    \
-               .pud_width      = 2,                    \
-               .drv_width      = 2,                    \
-               .conpdn_width   = 2,                    \
-               .pudpdn_width   = 2,                    \
                .eint_type      = EINT_TYPE_GPIO,       \
                .eint_offset    = offs,                 \
                .name           = id                    \
 
 #define EXYNOS_PIN_BANK_EINTW(pins, reg, id, offs)     \
        {                                               \
+               .type           = &bank_type_alive,     \
                .pctl_offset    = reg,                  \
                .nr_pins        = pins,                 \
-               .func_width     = 4,                    \
-               .pud_width      = 2,                    \
-               .drv_width      = 2,                    \
                .eint_type      = EINT_TYPE_WKUP,       \
                .eint_offset    = offs,                 \
                .name           = id                    \
index 1376eb7..6038503 100644 (file)
@@ -20,6 +20,9 @@
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
 #include <linux/pinctrl/pinconf.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
 #include "core.h"
 
 /* EXYNOS5440 GPIO and Pinctrl register offsets */
@@ -37,6 +40,7 @@
 #define GPIO_DS1               0x2C
 
 #define EXYNOS5440_MAX_PINS            23
+#define EXYNOS5440_MAX_GPIO_INT        8
 #define PIN_NAME_LENGTH                10
 
 #define GROUP_SUFFIX           "-grp"
@@ -109,6 +113,7 @@ struct exynos5440_pmx_func {
 struct exynos5440_pinctrl_priv_data {
        void __iomem                    *reg_base;
        struct gpio_chip                *gc;
+       struct irq_domain               *irq_domain;
 
        const struct exynos5440_pin_group       *pin_groups;
        unsigned int                    nr_groups;
@@ -116,6 +121,16 @@ struct exynos5440_pinctrl_priv_data {
        unsigned int                    nr_functions;
 };
 
+/**
+ * struct exynos5440_gpio_intr_data: private data for gpio interrupts.
+ * @priv: driver's private runtime data.
+ * @gpio_int: gpio interrupt number.
+ */
+struct exynos5440_gpio_intr_data {
+       struct exynos5440_pinctrl_priv_data     *priv;
+       unsigned int                            gpio_int;
+};
+
 /* list of all possible config options supported */
 static struct pin_config {
        char            *prop_cfg;
@@ -286,7 +301,7 @@ static void exynos5440_dt_free_map(struct pinctrl_dev *pctldev,
 }
 
 /* list of pinctrl callbacks for the pinctrl core */
-static struct pinctrl_ops exynos5440_pctrl_ops = {
+static const struct pinctrl_ops exynos5440_pctrl_ops = {
        .get_groups_count       = exynos5440_get_group_count,
        .get_group_name         = exynos5440_get_group_name,
        .get_group_pins         = exynos5440_get_group_pins,
@@ -374,7 +389,7 @@ static int exynos5440_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
 }
 
 /* list of pinmux callbacks for the pinmux vertical in pinctrl core */
-static struct pinmux_ops exynos5440_pinmux_ops = {
+static const struct pinmux_ops exynos5440_pinmux_ops = {
        .get_functions_count    = exynos5440_get_functions_count,
        .get_function_name      = exynos5440_pinmux_get_fname,
        .get_function_groups    = exynos5440_pinmux_get_groups,
@@ -523,7 +538,7 @@ static int exynos5440_pinconf_group_get(struct pinctrl_dev *pctldev,
 }
 
 /* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
-static struct pinconf_ops exynos5440_pinconf_ops = {
+static const struct pinconf_ops exynos5440_pinconf_ops = {
        .pin_config_get         = exynos5440_pinconf_get,
        .pin_config_set         = exynos5440_pinconf_set,
        .pin_config_group_get   = exynos5440_pinconf_group_get,
@@ -598,6 +613,22 @@ static int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offse
        return 0;
 }
 
+/* gpiolib gpio_to_irq callback function */
+static int exynos5440_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+       struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+       unsigned int virq;
+
+       if (offset < 16 || offset > 23)
+               return -ENXIO;
+
+       if (!priv->irq_domain)
+               return -ENXIO;
+
+       virq = irq_create_mapping(priv->irq_domain, offset - 16);
+       return virq ? : -ENXIO;
+}
+
 /* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */
 static int exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev,
                        struct device_node *cfg_np, unsigned int **pin_list,
@@ -670,8 +701,10 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
 
                ret = exynos5440_pinctrl_parse_dt_pins(pdev, cfg_np,
                                        &pin_list, &npins);
-               if (ret)
-                       return ret;
+               if (ret) {
+                       gname = NULL;
+                       goto skip_to_pin_function;
+               }
 
                /* derive pin group name from the node name */
                gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN,
@@ -687,6 +720,7 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
                grp->num_pins = npins;
                grp++;
 
+skip_to_pin_function:
                ret = of_property_read_u32(cfg_np, "samsung,exynos5440-pin-function",
                                                &function);
                if (ret)
@@ -709,7 +743,7 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
                        return -ENOMEM;
                }
                func->groups[0] = gname;
-               func->num_groups = 1;
+               func->num_groups = gname ? 1 : 0;
                func->function = function;
                func++;
                func_idx++;
@@ -818,6 +852,7 @@ static int exynos5440_gpiolib_register(struct platform_device *pdev,
        gc->get = exynos5440_gpio_get;
        gc->direction_input = exynos5440_gpio_direction_input;
        gc->direction_output = exynos5440_gpio_direction_output;
+       gc->to_irq = exynos5440_gpio_to_irq;
        gc->label = "gpiolib-exynos5440";
        gc->owner = THIS_MODULE;
        ret = gpiochip_add(gc);
@@ -842,6 +877,110 @@ static int exynos5440_gpiolib_unregister(struct platform_device *pdev,
        return 0;
 }
 
+static void exynos5440_gpio_irq_unmask(struct irq_data *irqd)
+{
+       struct exynos5440_pinctrl_priv_data *d;
+       unsigned long gpio_int;
+
+       d = irq_data_get_irq_chip_data(irqd);
+       gpio_int = readl(d->reg_base + GPIO_INT);
+       gpio_int |= 1 << irqd->hwirq;
+       writel(gpio_int, d->reg_base + GPIO_INT);
+}
+
+static void exynos5440_gpio_irq_mask(struct irq_data *irqd)
+{
+       struct exynos5440_pinctrl_priv_data *d;
+       unsigned long gpio_int;
+
+       d = irq_data_get_irq_chip_data(irqd);
+       gpio_int = readl(d->reg_base + GPIO_INT);
+       gpio_int &= ~(1 << irqd->hwirq);
+       writel(gpio_int, d->reg_base + GPIO_INT);
+}
+
+/* irq_chip for gpio interrupts */
+static struct irq_chip exynos5440_gpio_irq_chip = {
+       .name           = "exynos5440_gpio_irq_chip",
+       .irq_unmask     = exynos5440_gpio_irq_unmask,
+       .irq_mask       = exynos5440_gpio_irq_mask,
+};
+
+/* interrupt handler for GPIO interrupts 0..7 */
+static irqreturn_t exynos5440_gpio_irq(int irq, void *data)
+{
+       struct exynos5440_gpio_intr_data *intd = data;
+       struct exynos5440_pinctrl_priv_data *d = intd->priv;
+       int virq;
+
+       virq = irq_linear_revmap(d->irq_domain, intd->gpio_int);
+       if (!virq)
+               return IRQ_NONE;
+       generic_handle_irq(virq);
+       return IRQ_HANDLED;
+}
+
+static int exynos5440_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+                                       irq_hw_number_t hw)
+{
+       struct exynos5440_pinctrl_priv_data *d = h->host_data;
+
+       irq_set_chip_data(virq, d);
+       irq_set_chip_and_handler(virq, &exynos5440_gpio_irq_chip,
+                                       handle_level_irq);
+       set_irq_flags(virq, IRQF_VALID);
+       return 0;
+}
+
+/* irq domain callbacks for gpio interrupt controller */
+static const struct irq_domain_ops exynos5440_gpio_irqd_ops = {
+       .map    = exynos5440_gpio_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+/* setup handling of gpio interrupts */
+static int exynos5440_gpio_irq_init(struct platform_device *pdev,
+                               struct exynos5440_pinctrl_priv_data *priv)
+{
+       struct device *dev = &pdev->dev;
+       struct exynos5440_gpio_intr_data *intd;
+       int i, irq, ret;
+
+       intd = devm_kzalloc(dev, sizeof(*intd) * EXYNOS5440_MAX_GPIO_INT,
+                                       GFP_KERNEL);
+       if (!intd) {
+               dev_err(dev, "failed to allocate memory for gpio intr data\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < EXYNOS5440_MAX_GPIO_INT; i++) {
+               irq = irq_of_parse_and_map(dev->of_node, i);
+               if (irq <= 0) {
+                       dev_err(dev, "irq parsing failed\n");
+                       return -EINVAL;
+               }
+
+               intd->gpio_int = i;
+               intd->priv = priv;
+               ret = devm_request_irq(dev, irq, exynos5440_gpio_irq,
+                                       0, dev_name(dev), intd++);
+               if (ret) {
+                       dev_err(dev, "irq request failed\n");
+                       return -ENXIO;
+               }
+       }
+
+       priv->irq_domain = irq_domain_add_linear(dev->of_node,
+                               EXYNOS5440_MAX_GPIO_INT,
+                               &exynos5440_gpio_irqd_ops, priv);
+       if (!priv->irq_domain) {
+               dev_err(dev, "failed to create irq domain\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
 static int exynos5440_pinctrl_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -854,7 +993,7 @@ static int exynos5440_pinctrl_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       priv = devm_kzalloc(dev, sizeof(priv), GFP_KERNEL);
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv) {
                dev_err(dev, "could not allocate memory for private data\n");
                return -ENOMEM;
@@ -880,6 +1019,12 @@ static int exynos5440_pinctrl_probe(struct platform_device *pdev)
                return ret;
        }
 
+       ret = exynos5440_gpio_irq_init(pdev, priv);
+       if (ret) {
+               dev_err(dev, "failed to setup gpio interrupts\n");
+               return ret;
+       }
+
        platform_set_drvdata(pdev, priv);
        dev_info(dev, "EXYNOS5440 pinctrl driver registered\n");
        return 0;
index af97a1f..f9b2a1d 100644 (file)
@@ -353,7 +353,7 @@ static void falcon_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev,
 {
 }
 
-static struct pinconf_ops falcon_pinconf_ops = {
+static const struct pinconf_ops falcon_pinconf_ops = {
        .pin_config_get                 = falcon_pinconf_get,
        .pin_config_set                 = falcon_pinconf_set,
        .pin_config_group_get           = falcon_pinconf_group_get,
index 4cebb9c..0ef1904 100644 (file)
@@ -207,7 +207,7 @@ static void imx_dt_free_map(struct pinctrl_dev *pctldev,
        kfree(map);
 }
 
-static struct pinctrl_ops imx_pctrl_ops = {
+static const struct pinctrl_ops imx_pctrl_ops = {
        .get_groups_count = imx_get_groups_count,
        .get_group_name = imx_get_group_name,
        .get_group_pins = imx_get_group_pins,
@@ -299,7 +299,7 @@ static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
        return 0;
 }
 
-static struct pinmux_ops imx_pmx_ops = {
+static const struct pinmux_ops imx_pmx_ops = {
        .get_functions_count = imx_pmx_get_funcs_count,
        .get_function_name = imx_pmx_get_func_name,
        .get_function_groups = imx_pmx_get_groups,
@@ -397,7 +397,7 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
        }
 }
 
-static struct pinconf_ops imx_pinconf_ops = {
+static const struct pinconf_ops imx_pinconf_ops = {
        .pin_config_get = imx_pinconf_get,
        .pin_config_set = imx_pinconf_set,
        .pin_config_dbg_show = imx_pinconf_dbg_show,
index a703846..615c500 100644 (file)
@@ -169,7 +169,7 @@ static int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
        return 0;
 }
 
-static struct pinctrl_ops ltq_pctrl_ops = {
+static const struct pinctrl_ops ltq_pctrl_ops = {
        .get_groups_count       = ltq_get_group_count,
        .get_group_name         = ltq_get_group_name,
        .get_group_pins         = ltq_get_group_pins,
@@ -311,7 +311,7 @@ static int ltq_pmx_gpio_request_enable(struct pinctrl_dev *pctrldev,
        return info->apply_mux(pctrldev, mfp, pin_func);
 }
 
-static struct pinmux_ops ltq_pmx_ops = {
+static const struct pinmux_ops ltq_pmx_ops = {
        .get_functions_count    = ltq_pmx_func_count,
        .get_function_name      = ltq_pmx_func_name,
        .get_function_groups    = ltq_pmx_get_groups,
diff --git a/drivers/pinctrl/pinctrl-mmp2.c b/drivers/pinctrl/pinctrl-mmp2.c
deleted file mode 100644 (file)
index 4afa56a..0000000
+++ /dev/null
@@ -1,722 +0,0 @@
-/*
- *  linux/drivers/pinctrl/pinmux-mmp2.c
- *
- *  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
- *  publishhed by the Free Software Foundation.
- *
- *  Copyright (C) 2011, Marvell Technology Group Ltd.
- *
- *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include "pinctrl-pxa3xx.h"
-
-#define MMP2_DS_MASK           0x1800
-#define MMP2_DS_SHIFT          11
-#define MMP2_SLEEP_MASK                0x38
-#define MMP2_SLEEP_SELECT      (1 << 9)
-#define MMP2_SLEEP_DATA                (1 << 8)
-#define MMP2_SLEEP_DIR         (1 << 7)
-
-#define MFPR_MMP2(a, r, f0, f1, f2, f3, f4, f5, f6, f7)                \
-       {                                                       \
-               .name = #a,                                     \
-               .pin = a,                                       \
-               .mfpr = r,                                      \
-               .func = {                                       \
-                       MMP2_MUX_##f0,                          \
-                       MMP2_MUX_##f1,                          \
-                       MMP2_MUX_##f2,                          \
-                       MMP2_MUX_##f3,                          \
-                       MMP2_MUX_##f4,                          \
-                       MMP2_MUX_##f5,                          \
-                       MMP2_MUX_##f6,                          \
-                       MMP2_MUX_##f7,                          \
-               },                                              \
-       }
-
-#define GRP_MMP2(a, m, p)              \
-       { .name = a, .mux = MMP2_MUX_##m, .pins = p, .npins = ARRAY_SIZE(p), }
-
-/* 174 pins */
-enum mmp2_pin_list {
-       /* 0~168: GPIO0~GPIO168 */
-       TWSI4_SCL = 169,
-       TWSI4_SDA, /* 170 */
-       G_CLKREQ,
-       VCXO_REQ,
-       VCXO_OUT,
-};
-
-enum mmp2_mux {
-       /* PXA3xx_MUX_GPIO = 0 (predefined in pinctrl-pxa3xx.h) */
-       MMP2_MUX_GPIO = 0,
-       MMP2_MUX_G_CLKREQ,
-       MMP2_MUX_VCXO_REQ,
-       MMP2_MUX_VCXO_OUT,
-       MMP2_MUX_KP_MK,
-       MMP2_MUX_KP_DK,
-       MMP2_MUX_CCIC1,
-       MMP2_MUX_CCIC2,
-       MMP2_MUX_SPI,
-       MMP2_MUX_SSPA2,
-       MMP2_MUX_ROT,
-       MMP2_MUX_I2S,
-       MMP2_MUX_TB,
-       MMP2_MUX_CAM2,
-       MMP2_MUX_HDMI,
-       MMP2_MUX_TWSI2,
-       MMP2_MUX_TWSI3,
-       MMP2_MUX_TWSI4,
-       MMP2_MUX_TWSI5,
-       MMP2_MUX_TWSI6,
-       MMP2_MUX_UART1,
-       MMP2_MUX_UART2,
-       MMP2_MUX_UART3,
-       MMP2_MUX_UART4,
-       MMP2_MUX_SSP1_RX,
-       MMP2_MUX_SSP1_FRM,
-       MMP2_MUX_SSP1_TXRX,
-       MMP2_MUX_SSP2_RX,
-       MMP2_MUX_SSP2_FRM,
-       MMP2_MUX_SSP1,
-       MMP2_MUX_SSP2,
-       MMP2_MUX_SSP3,
-       MMP2_MUX_SSP4,
-       MMP2_MUX_MMC1,
-       MMP2_MUX_MMC2,
-       MMP2_MUX_MMC3,
-       MMP2_MUX_MMC4,
-       MMP2_MUX_ULPI,
-       MMP2_MUX_AC,
-       MMP2_MUX_CA,
-       MMP2_MUX_PWM,
-       MMP2_MUX_USIM,
-       MMP2_MUX_TIPU,
-       MMP2_MUX_PLL,
-       MMP2_MUX_NAND,
-       MMP2_MUX_FSIC,
-       MMP2_MUX_SLEEP_IND,
-       MMP2_MUX_EXT_DMA,
-       MMP2_MUX_ONE_WIRE,
-       MMP2_MUX_LCD,
-       MMP2_MUX_SMC,
-       MMP2_MUX_SMC_INT,
-       MMP2_MUX_MSP,
-       MMP2_MUX_G_CLKOUT,
-       MMP2_MUX_32K_CLKOUT,
-       MMP2_MUX_PRI_JTAG,
-       MMP2_MUX_AAS_JTAG,
-       MMP2_MUX_AAS_GPIO,
-       MMP2_MUX_AAS_SPI,
-       MMP2_MUX_AAS_TWSI,
-       MMP2_MUX_AAS_DEU_EX,
-       MMP2_MUX_NONE = 0xffff,
-};
-
-static struct pinctrl_pin_desc mmp2_pads[] = {
-       /*
-        * The name indicates function 0 of this pin.
-        * After reset, function 0 is the default function of pin.
-        */
-       PINCTRL_PIN(GPIO0, "GPIO0"),
-       PINCTRL_PIN(GPIO1, "GPIO1"),
-       PINCTRL_PIN(GPIO2, "GPIO2"),
-       PINCTRL_PIN(GPIO3, "GPIO3"),
-       PINCTRL_PIN(GPIO4, "GPIO4"),
-       PINCTRL_PIN(GPIO5, "GPIO5"),
-       PINCTRL_PIN(GPIO6, "GPIO6"),
-       PINCTRL_PIN(GPIO7, "GPIO7"),
-       PINCTRL_PIN(GPIO8, "GPIO8"),
-       PINCTRL_PIN(GPIO9, "GPIO9"),
-       PINCTRL_PIN(GPIO10, "GPIO10"),
-       PINCTRL_PIN(GPIO11, "GPIO11"),
-       PINCTRL_PIN(GPIO12, "GPIO12"),
-       PINCTRL_PIN(GPIO13, "GPIO13"),
-       PINCTRL_PIN(GPIO14, "GPIO14"),
-       PINCTRL_PIN(GPIO15, "GPIO15"),
-       PINCTRL_PIN(GPIO16, "GPIO16"),
-       PINCTRL_PIN(GPIO17, "GPIO17"),
-       PINCTRL_PIN(GPIO18, "GPIO18"),
-       PINCTRL_PIN(GPIO19, "GPIO19"),
-       PINCTRL_PIN(GPIO20, "GPIO20"),
-       PINCTRL_PIN(GPIO21, "GPIO21"),
-       PINCTRL_PIN(GPIO22, "GPIO22"),
-       PINCTRL_PIN(GPIO23, "GPIO23"),
-       PINCTRL_PIN(GPIO24, "GPIO24"),
-       PINCTRL_PIN(GPIO25, "GPIO25"),
-       PINCTRL_PIN(GPIO26, "GPIO26"),
-       PINCTRL_PIN(GPIO27, "GPIO27"),
-       PINCTRL_PIN(GPIO28, "GPIO28"),
-       PINCTRL_PIN(GPIO29, "GPIO29"),
-       PINCTRL_PIN(GPIO30, "GPIO30"),
-       PINCTRL_PIN(GPIO31, "GPIO31"),
-       PINCTRL_PIN(GPIO32, "GPIO32"),
-       PINCTRL_PIN(GPIO33, "GPIO33"),
-       PINCTRL_PIN(GPIO34, "GPIO34"),
-       PINCTRL_PIN(GPIO35, "GPIO35"),
-       PINCTRL_PIN(GPIO36, "GPIO36"),
-       PINCTRL_PIN(GPIO37, "GPIO37"),
-       PINCTRL_PIN(GPIO38, "GPIO38"),
-       PINCTRL_PIN(GPIO39, "GPIO39"),
-       PINCTRL_PIN(GPIO40, "GPIO40"),
-       PINCTRL_PIN(GPIO41, "GPIO41"),
-       PINCTRL_PIN(GPIO42, "GPIO42"),
-       PINCTRL_PIN(GPIO43, "GPIO43"),
-       PINCTRL_PIN(GPIO44, "GPIO44"),
-       PINCTRL_PIN(GPIO45, "GPIO45"),
-       PINCTRL_PIN(GPIO46, "GPIO46"),
-       PINCTRL_PIN(GPIO47, "GPIO47"),
-       PINCTRL_PIN(GPIO48, "GPIO48"),
-       PINCTRL_PIN(GPIO49, "GPIO49"),
-       PINCTRL_PIN(GPIO50, "GPIO50"),
-       PINCTRL_PIN(GPIO51, "GPIO51"),
-       PINCTRL_PIN(GPIO52, "GPIO52"),
-       PINCTRL_PIN(GPIO53, "GPIO53"),
-       PINCTRL_PIN(GPIO54, "GPIO54"),
-       PINCTRL_PIN(GPIO55, "GPIO55"),
-       PINCTRL_PIN(GPIO56, "GPIO56"),
-       PINCTRL_PIN(GPIO57, "GPIO57"),
-       PINCTRL_PIN(GPIO58, "GPIO58"),
-       PINCTRL_PIN(GPIO59, "GPIO59"),
-       PINCTRL_PIN(GPIO60, "GPIO60"),
-       PINCTRL_PIN(GPIO61, "GPIO61"),
-       PINCTRL_PIN(GPIO62, "GPIO62"),
-       PINCTRL_PIN(GPIO63, "GPIO63"),
-       PINCTRL_PIN(GPIO64, "GPIO64"),
-       PINCTRL_PIN(GPIO65, "GPIO65"),
-       PINCTRL_PIN(GPIO66, "GPIO66"),
-       PINCTRL_PIN(GPIO67, "GPIO67"),
-       PINCTRL_PIN(GPIO68, "GPIO68"),
-       PINCTRL_PIN(GPIO69, "GPIO69"),
-       PINCTRL_PIN(GPIO70, "GPIO70"),
-       PINCTRL_PIN(GPIO71, "GPIO71"),
-       PINCTRL_PIN(GPIO72, "GPIO72"),
-       PINCTRL_PIN(GPIO73, "GPIO73"),
-       PINCTRL_PIN(GPIO74, "GPIO74"),
-       PINCTRL_PIN(GPIO75, "GPIO75"),
-       PINCTRL_PIN(GPIO76, "GPIO76"),
-       PINCTRL_PIN(GPIO77, "GPIO77"),
-       PINCTRL_PIN(GPIO78, "GPIO78"),
-       PINCTRL_PIN(GPIO79, "GPIO79"),
-       PINCTRL_PIN(GPIO80, "GPIO80"),
-       PINCTRL_PIN(GPIO81, "GPIO81"),
-       PINCTRL_PIN(GPIO82, "GPIO82"),
-       PINCTRL_PIN(GPIO83, "GPIO83"),
-       PINCTRL_PIN(GPIO84, "GPIO84"),
-       PINCTRL_PIN(GPIO85, "GPIO85"),
-       PINCTRL_PIN(GPIO86, "GPIO86"),
-       PINCTRL_PIN(GPIO87, "GPIO87"),
-       PINCTRL_PIN(GPIO88, "GPIO88"),
-       PINCTRL_PIN(GPIO89, "GPIO89"),
-       PINCTRL_PIN(GPIO90, "GPIO90"),
-       PINCTRL_PIN(GPIO91, "GPIO91"),
-       PINCTRL_PIN(GPIO92, "GPIO92"),
-       PINCTRL_PIN(GPIO93, "GPIO93"),
-       PINCTRL_PIN(GPIO94, "GPIO94"),
-       PINCTRL_PIN(GPIO95, "GPIO95"),
-       PINCTRL_PIN(GPIO96, "GPIO96"),
-       PINCTRL_PIN(GPIO97, "GPIO97"),
-       PINCTRL_PIN(GPIO98, "GPIO98"),
-       PINCTRL_PIN(GPIO99, "GPIO99"),
-       PINCTRL_PIN(GPIO100, "GPIO100"),
-       PINCTRL_PIN(GPIO101, "GPIO101"),
-       PINCTRL_PIN(GPIO102, "GPIO102"),
-       PINCTRL_PIN(GPIO103, "GPIO103"),
-       PINCTRL_PIN(GPIO104, "GPIO104"),
-       PINCTRL_PIN(GPIO105, "GPIO105"),
-       PINCTRL_PIN(GPIO106, "GPIO106"),
-       PINCTRL_PIN(GPIO107, "GPIO107"),
-       PINCTRL_PIN(GPIO108, "GPIO108"),
-       PINCTRL_PIN(GPIO109, "GPIO109"),
-       PINCTRL_PIN(GPIO110, "GPIO110"),
-       PINCTRL_PIN(GPIO111, "GPIO111"),
-       PINCTRL_PIN(GPIO112, "GPIO112"),
-       PINCTRL_PIN(GPIO113, "GPIO113"),
-       PINCTRL_PIN(GPIO114, "GPIO114"),
-       PINCTRL_PIN(GPIO115, "GPIO115"),
-       PINCTRL_PIN(GPIO116, "GPIO116"),
-       PINCTRL_PIN(GPIO117, "GPIO117"),
-       PINCTRL_PIN(GPIO118, "GPIO118"),
-       PINCTRL_PIN(GPIO119, "GPIO119"),
-       PINCTRL_PIN(GPIO120, "GPIO120"),
-       PINCTRL_PIN(GPIO121, "GPIO121"),
-       PINCTRL_PIN(GPIO122, "GPIO122"),
-       PINCTRL_PIN(GPIO123, "GPIO123"),
-       PINCTRL_PIN(GPIO124, "GPIO124"),
-       PINCTRL_PIN(GPIO125, "GPIO125"),
-       PINCTRL_PIN(GPIO126, "GPIO126"),
-       PINCTRL_PIN(GPIO127, "GPIO127"),
-       PINCTRL_PIN(GPIO128, "GPIO128"),
-       PINCTRL_PIN(GPIO129, "GPIO129"),
-       PINCTRL_PIN(GPIO130, "GPIO130"),
-       PINCTRL_PIN(GPIO131, "GPIO131"),
-       PINCTRL_PIN(GPIO132, "GPIO132"),
-       PINCTRL_PIN(GPIO133, "GPIO133"),
-       PINCTRL_PIN(GPIO134, "GPIO134"),
-       PINCTRL_PIN(GPIO135, "GPIO135"),
-       PINCTRL_PIN(GPIO136, "GPIO136"),
-       PINCTRL_PIN(GPIO137, "GPIO137"),
-       PINCTRL_PIN(GPIO138, "GPIO138"),
-       PINCTRL_PIN(GPIO139, "GPIO139"),
-       PINCTRL_PIN(GPIO140, "GPIO140"),
-       PINCTRL_PIN(GPIO141, "GPIO141"),
-       PINCTRL_PIN(GPIO142, "GPIO142"),
-       PINCTRL_PIN(GPIO143, "GPIO143"),
-       PINCTRL_PIN(GPIO144, "GPIO144"),
-       PINCTRL_PIN(GPIO145, "GPIO145"),
-       PINCTRL_PIN(GPIO146, "GPIO146"),
-       PINCTRL_PIN(GPIO147, "GPIO147"),
-       PINCTRL_PIN(GPIO148, "GPIO148"),
-       PINCTRL_PIN(GPIO149, "GPIO149"),
-       PINCTRL_PIN(GPIO150, "GPIO150"),
-       PINCTRL_PIN(GPIO151, "GPIO151"),
-       PINCTRL_PIN(GPIO152, "GPIO152"),
-       PINCTRL_PIN(GPIO153, "GPIO153"),
-       PINCTRL_PIN(GPIO154, "GPIO154"),
-       PINCTRL_PIN(GPIO155, "GPIO155"),
-       PINCTRL_PIN(GPIO156, "GPIO156"),
-       PINCTRL_PIN(GPIO157, "GPIO157"),
-       PINCTRL_PIN(GPIO158, "GPIO158"),
-       PINCTRL_PIN(GPIO159, "GPIO159"),
-       PINCTRL_PIN(GPIO160, "GPIO160"),
-       PINCTRL_PIN(GPIO161, "GPIO161"),
-       PINCTRL_PIN(GPIO162, "GPIO162"),
-       PINCTRL_PIN(GPIO163, "GPIO163"),
-       PINCTRL_PIN(GPIO164, "GPIO164"),
-       PINCTRL_PIN(GPIO165, "GPIO165"),
-       PINCTRL_PIN(GPIO166, "GPIO166"),
-       PINCTRL_PIN(GPIO167, "GPIO167"),
-       PINCTRL_PIN(GPIO168, "GPIO168"),
-       PINCTRL_PIN(TWSI4_SCL, "TWSI4_SCL"),
-       PINCTRL_PIN(TWSI4_SDA, "TWSI4_SDA"),
-       PINCTRL_PIN(G_CLKREQ, "G_CLKREQ"),
-       PINCTRL_PIN(VCXO_REQ, "VCXO_REQ"),
-       PINCTRL_PIN(VCXO_OUT, "VCXO_OUT"),
-};
-
-struct pxa3xx_mfp_pin mmp2_mfp[] = {
-       /*       pin         offs   f0        f1          f2          f3          f4          f5        f6        f7  */
-       MFPR_MMP2(GPIO0,     0x054, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO1,     0x058, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO2,     0x05C, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO3,     0x060, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO4,     0x064, GPIO,     KP_MK,      NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO5,     0x068, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO6,     0x06C, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO7,     0x070, GPIO,     KP_MK,      NONE,       SPI,        NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO8,     0x074, GPIO,     KP_MK,      NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO9,     0x078, GPIO,     KP_MK,      NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO10,    0x07C, GPIO,     KP_MK,      NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO11,    0x080, GPIO,     KP_MK,      NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO12,    0x084, GPIO,     KP_MK,      NONE,       CCIC1,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO13,    0x088, GPIO,     KP_MK,      NONE,       CCIC1,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO14,    0x08C, GPIO,     KP_MK,      NONE,       CCIC1,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO15,    0x090, GPIO,     KP_MK,      KP_DK,      CCIC1,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO16,    0x094, GPIO,     KP_DK,      ROT,        CCIC1,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO17,    0x098, GPIO,     KP_DK,      ROT,        CCIC1,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO18,    0x09C, GPIO,     KP_DK,      ROT,        CCIC1,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO19,    0x0A0, GPIO,     KP_DK,      ROT,        CCIC1,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO20,    0x0A4, GPIO,     KP_DK,      TB,         CCIC1,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO21,    0x0A8, GPIO,     KP_DK,      TB,         CCIC1,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO22,    0x0AC, GPIO,     KP_DK,      TB,         CCIC1,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO23,    0x0B0, GPIO,     KP_DK,      TB,         CCIC1,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO24,    0x0B4, GPIO,     I2S,        VCXO_OUT,   NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO25,    0x0B8, GPIO,     I2S,        HDMI,       SSPA2,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO26,    0x0BC, GPIO,     I2S,        HDMI,       SSPA2,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO27,    0x0C0, GPIO,     I2S,        HDMI,       SSPA2,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO28,    0x0C4, GPIO,     I2S,        NONE,       SSPA2,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO29,    0x0C8, GPIO,     UART1,      KP_MK,      NONE,       NONE,       NONE,     AAS_SPI,  NONE),
-       MFPR_MMP2(GPIO30,    0x0CC, GPIO,     UART1,      KP_MK,      NONE,       NONE,       NONE,     AAS_SPI,  NONE),
-       MFPR_MMP2(GPIO31,    0x0D0, GPIO,     UART1,      KP_MK,      NONE,       NONE,       NONE,     AAS_SPI,  NONE),
-       MFPR_MMP2(GPIO32,    0x0D4, GPIO,     UART1,      KP_MK,      NONE,       NONE,       NONE,     AAS_SPI,  NONE),
-       MFPR_MMP2(GPIO33,    0x0D8, GPIO,     SSPA2,      I2S,        NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO34,    0x0DC, GPIO,     SSPA2,      I2S,        NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO35,    0x0E0, GPIO,     SSPA2,      I2S,        NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO36,    0x0E4, GPIO,     SSPA2,      I2S,        NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO37,    0x0E8, GPIO,     MMC2,       SSP1,       TWSI2,      UART2,      UART3,    AAS_SPI,  AAS_TWSI),
-       MFPR_MMP2(GPIO38,    0x0EC, GPIO,     MMC2,       SSP1,       TWSI2,      UART2,      UART3,    AAS_SPI,  AAS_TWSI),
-       MFPR_MMP2(GPIO39,    0x0F0, GPIO,     MMC2,       SSP1,       TWSI2,      UART2,      UART3,    AAS_SPI,  AAS_TWSI),
-       MFPR_MMP2(GPIO40,    0x0F4, GPIO,     MMC2,       SSP1,       TWSI2,      UART2,      UART3,    AAS_SPI,  AAS_TWSI),
-       MFPR_MMP2(GPIO41,    0x0F8, GPIO,     MMC2,       TWSI5,      NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO42,    0x0FC, GPIO,     MMC2,       TWSI5,      NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO43,    0x100, GPIO,     TWSI2,      UART4,      SSP1,       UART2,      UART3,    NONE,     AAS_TWSI),
-       MFPR_MMP2(GPIO44,    0x104, GPIO,     TWSI2,      UART4,      SSP1,       UART2,      UART3,    NONE,     AAS_TWSI),
-       MFPR_MMP2(GPIO45,    0x108, GPIO,     UART1,      UART4,      SSP1,       UART2,      UART3,    NONE,     NONE),
-       MFPR_MMP2(GPIO46,    0x10C, GPIO,     UART1,      UART4,      SSP1,       UART2,      UART3,    NONE,     NONE),
-       MFPR_MMP2(GPIO47,    0x110, GPIO,     UART2,      SSP2,       TWSI6,      CAM2,       AAS_SPI,  AAS_GPIO, NONE),
-       MFPR_MMP2(GPIO48,    0x114, GPIO,     UART2,      SSP2,       TWSI6,      CAM2,       AAS_SPI,  AAS_GPIO, NONE),
-       MFPR_MMP2(GPIO49,    0x118, GPIO,     UART2,      SSP2,       PWM,        CCIC2,      AAS_SPI,  NONE,     NONE),
-       MFPR_MMP2(GPIO50,    0x11C, GPIO,     UART2,      SSP2,       PWM,        CCIC2,      AAS_SPI,  NONE,     NONE),
-       MFPR_MMP2(GPIO51,    0x120, GPIO,     UART3,      ROT,        AAS_GPIO,   PWM,        NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO52,    0x124, GPIO,     UART3,      ROT,        AAS_GPIO,   PWM,        NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO53,    0x128, GPIO,     UART3,      TWSI2,      VCXO_REQ,   NONE,       PWM,      NONE,     AAS_TWSI),
-       MFPR_MMP2(GPIO54,    0x12C, GPIO,     UART3,      TWSI2,      VCXO_OUT,   HDMI,       PWM,      NONE,     AAS_TWSI),
-       MFPR_MMP2(GPIO55,    0x130, GPIO,     SSP2,       SSP1,       UART2,      ROT,        TWSI2,    SSP3,     AAS_TWSI),
-       MFPR_MMP2(GPIO56,    0x134, GPIO,     SSP2,       SSP1,       UART2,      ROT,        TWSI2,    KP_DK,    AAS_TWSI),
-       MFPR_MMP2(GPIO57,    0x138, GPIO,     SSP2_RX,    SSP1_TXRX,  SSP2_FRM,   SSP1_RX,    VCXO_REQ, KP_DK,    NONE),
-       MFPR_MMP2(GPIO58,    0x13C, GPIO,     SSP2,       SSP1_RX,    SSP1_FRM,   SSP1_TXRX,  VCXO_REQ, KP_DK,    NONE),
-       MFPR_MMP2(GPIO59,    0x280, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      UART3,    UART4,    NONE),
-       MFPR_MMP2(GPIO60,    0x284, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      UART3,    UART4,    NONE),
-       MFPR_MMP2(GPIO61,    0x288, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      UART3,    HDMI,     NONE),
-       MFPR_MMP2(GPIO62,    0x28C, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      UART3,    NONE,     NONE),
-       MFPR_MMP2(GPIO63,    0x290, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      UART4,    NONE),
-       MFPR_MMP2(GPIO64,    0x294, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      UART4,    NONE),
-       MFPR_MMP2(GPIO65,    0x298, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      UART4,    NONE),
-       MFPR_MMP2(GPIO66,    0x29C, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      UART4,    NONE),
-       MFPR_MMP2(GPIO67,    0x2A0, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      NONE,     NONE),
-       MFPR_MMP2(GPIO68,    0x2A4, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      LCD,      NONE),
-       MFPR_MMP2(GPIO69,    0x2A8, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      NONE,     LCD,      NONE),
-       MFPR_MMP2(GPIO70,    0x2AC, GPIO,     CCIC1,      ULPI,       MMC3,       CCIC2,      MSP,      LCD,      NONE),
-       MFPR_MMP2(GPIO71,    0x2B0, GPIO,     TWSI3,      NONE,       PWM,        NONE,       NONE,     LCD,      AAS_TWSI),
-       MFPR_MMP2(GPIO72,    0x2B4, GPIO,     TWSI3,      HDMI,       PWM,        NONE,       NONE,     LCD,      AAS_TWSI),
-       MFPR_MMP2(GPIO73,    0x2B8, GPIO,     VCXO_REQ,   32K_CLKOUT, PWM,        VCXO_OUT,   NONE,     LCD,      NONE),
-       MFPR_MMP2(GPIO74,    0x170, GPIO,     LCD,        SMC,        MMC4,       SSP3,       UART2,    UART4,    TIPU),
-       MFPR_MMP2(GPIO75,    0x174, GPIO,     LCD,        SMC,        MMC4,       SSP3,       UART2,    UART4,    TIPU),
-       MFPR_MMP2(GPIO76,    0x178, GPIO,     LCD,        SMC,        MMC4,       SSP3,       UART2,    UART4,    TIPU),
-       MFPR_MMP2(GPIO77,    0x17C, GPIO,     LCD,        SMC,        MMC4,       SSP3,       UART2,    UART4,    TIPU),
-       MFPR_MMP2(GPIO78,    0x180, GPIO,     LCD,        HDMI,       MMC4,       NONE,       SSP4,     AAS_SPI,  TIPU),
-       MFPR_MMP2(GPIO79,    0x184, GPIO,     LCD,        AAS_GPIO,   MMC4,       NONE,       SSP4,     AAS_SPI,  TIPU),
-       MFPR_MMP2(GPIO80,    0x188, GPIO,     LCD,        AAS_GPIO,   MMC4,       NONE,       SSP4,     AAS_SPI,  TIPU),
-       MFPR_MMP2(GPIO81,    0x18C, GPIO,     LCD,        AAS_GPIO,   MMC4,       NONE,       SSP4,     AAS_SPI,  TIPU),
-       MFPR_MMP2(GPIO82,    0x190, GPIO,     LCD,        NONE,       MMC4,       NONE,       NONE,     CCIC2,    TIPU),
-       MFPR_MMP2(GPIO83,    0x194, GPIO,     LCD,        NONE,       MMC4,       NONE,       NONE,     CCIC2,    TIPU),
-       MFPR_MMP2(GPIO84,    0x198, GPIO,     LCD,        SMC,        MMC2,       NONE,       TWSI5,    AAS_TWSI, TIPU),
-       MFPR_MMP2(GPIO85,    0x19C, GPIO,     LCD,        SMC,        MMC2,       NONE,       TWSI5,    AAS_TWSI, TIPU),
-       MFPR_MMP2(GPIO86,    0x1A0, GPIO,     LCD,        SMC,        MMC2,       NONE,       TWSI6,    CCIC2,    TIPU),
-       MFPR_MMP2(GPIO87,    0x1A4, GPIO,     LCD,        SMC,        MMC2,       NONE,       TWSI6,    CCIC2,    TIPU),
-       MFPR_MMP2(GPIO88,    0x1A8, GPIO,     LCD,        AAS_GPIO,   MMC2,       NONE,       NONE,     CCIC2,    TIPU),
-       MFPR_MMP2(GPIO89,    0x1AC, GPIO,     LCD,        AAS_GPIO,   MMC2,       NONE,       NONE,     CCIC2,    TIPU),
-       MFPR_MMP2(GPIO90,    0x1B0, GPIO,     LCD,        AAS_GPIO,   MMC2,       NONE,       NONE,     CCIC2,    TIPU),
-       MFPR_MMP2(GPIO91,    0x1B4, GPIO,     LCD,        AAS_GPIO,   MMC2,       NONE,       NONE,     CCIC2,    TIPU),
-       MFPR_MMP2(GPIO92,    0x1B8, GPIO,     LCD,        AAS_GPIO,   MMC2,       NONE,       NONE,     CCIC2,    TIPU),
-       MFPR_MMP2(GPIO93,    0x1BC, GPIO,     LCD,        AAS_GPIO,   MMC2,       NONE,       NONE,     CCIC2,    TIPU),
-       MFPR_MMP2(GPIO94,    0x1C0, GPIO,     LCD,        AAS_GPIO,   SPI,        NONE,       AAS_SPI,  CCIC2,    TIPU),
-       MFPR_MMP2(GPIO95,    0x1C4, GPIO,     LCD,        TWSI3,      SPI,        AAS_DEU_EX, AAS_SPI,  CCIC2,    TIPU),
-       MFPR_MMP2(GPIO96,    0x1C8, GPIO,     LCD,        TWSI3,      SPI,        AAS_DEU_EX, AAS_SPI,  NONE,     TIPU),
-       MFPR_MMP2(GPIO97,    0x1CC, GPIO,     LCD,        TWSI6,      SPI,        AAS_DEU_EX, AAS_SPI,  NONE,     TIPU),
-       MFPR_MMP2(GPIO98,    0x1D0, GPIO,     LCD,        TWSI6,      SPI,        ONE_WIRE,   NONE,     NONE,     TIPU),
-       MFPR_MMP2(GPIO99,    0x1D4, GPIO,     LCD,        SMC,        SPI,        TWSI5,      NONE,     NONE,     TIPU),
-       MFPR_MMP2(GPIO100,   0x1D8, GPIO,     LCD,        SMC,        SPI,        TWSI5,      NONE,     NONE,     TIPU),
-       MFPR_MMP2(GPIO101,   0x1DC, GPIO,     LCD,        SMC,        SPI,        NONE,       NONE,     NONE,     TIPU),
-       MFPR_MMP2(GPIO102,   0x000, USIM,     GPIO,       FSIC,       KP_DK,      LCD,        NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO103,   0x004, USIM,     GPIO,       FSIC,       KP_DK,      LCD,        NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO104,   0x1FC, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO105,   0x1F8, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO106,   0x1F4, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO107,   0x1F0, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO108,   0x21C, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO109,   0x218, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO110,   0x214, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO111,   0x200, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO112,   0x244, NAND,     GPIO,       MMC3,       SMC,        NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO113,   0x25C, SMC,      GPIO,       EXT_DMA,    MMC3,       SMC,        HDMI,     NONE,     NONE),
-       MFPR_MMP2(GPIO114,   0x164, G_CLKOUT, 32K_CLKOUT, HDMI,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO115,   0x260, GPIO,     NONE,       AC,         UART4,      UART3,      SSP1,     NONE,     NONE),
-       MFPR_MMP2(GPIO116,   0x264, GPIO,     NONE,       AC,         UART4,      UART3,      SSP1,     NONE,     NONE),
-       MFPR_MMP2(GPIO117,   0x268, GPIO,     NONE,       AC,         UART4,      UART3,      SSP1,     NONE,     NONE),
-       MFPR_MMP2(GPIO118,   0x26C, GPIO,     NONE,       AC,         UART4,      UART3,      SSP1,     NONE,     NONE),
-       MFPR_MMP2(GPIO119,   0x270, GPIO,     NONE,       CA,         SSP3,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO120,   0x274, GPIO,     NONE,       CA,         SSP3,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO121,   0x278, GPIO,     NONE,       CA,         SSP3,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO122,   0x27C, GPIO,     NONE,       CA,         SSP3,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO123,   0x148, GPIO,     SLEEP_IND,  ONE_WIRE,   32K_CLKOUT, NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO124,   0x00C, GPIO,     MMC1,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO125,   0x010, GPIO,     MMC1,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO126,   0x014, GPIO,     MMC1,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO127,   0x018, GPIO,     NONE,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO128,   0x01C, GPIO,     NONE,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO129,   0x020, GPIO,     MMC1,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO130,   0x024, GPIO,     MMC1,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO131,   0x028, GPIO,     MMC1,       NONE,       MSP,        NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO132,   0x02C, GPIO,     MMC1,       PRI_JTAG,   MSP,        SSP3,       AAS_JTAG, NONE,     NONE),
-       MFPR_MMP2(GPIO133,   0x030, GPIO,     MMC1,       PRI_JTAG,   MSP,        SSP3,       AAS_JTAG, NONE,     NONE),
-       MFPR_MMP2(GPIO134,   0x034, GPIO,     MMC1,       PRI_JTAG,   MSP,        SSP3,       AAS_JTAG, NONE,     NONE),
-       MFPR_MMP2(GPIO135,   0x038, GPIO,     NONE,       LCD,        MMC3,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO136,   0x03C, GPIO,     MMC1,       PRI_JTAG,   MSP,        SSP3,       AAS_JTAG, NONE,     NONE),
-       MFPR_MMP2(GPIO137,   0x040, GPIO,     HDMI,       LCD,        MSP,        NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO138,   0x044, GPIO,     NONE,       LCD,        MMC3,       SMC,        NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO139,   0x048, GPIO,     MMC1,       PRI_JTAG,   MSP,        NONE,       AAS_JTAG, NONE,     NONE),
-       MFPR_MMP2(GPIO140,   0x04C, GPIO,     MMC1,       LCD,        NONE,       NONE,       UART2,    UART1,    NONE),
-       MFPR_MMP2(GPIO141,   0x050, GPIO,     MMC1,       LCD,        NONE,       NONE,       UART2,    UART1,    NONE),
-       MFPR_MMP2(GPIO142,   0x008, USIM,     GPIO,       FSIC,       KP_DK,      NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO143,   0x220, NAND,     GPIO,       SMC,        NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO144,   0x224, NAND,     GPIO,       SMC_INT,    SMC,        NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO145,   0x228, SMC,      GPIO,       NONE,       NONE,       SMC,        NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO146,   0x22C, SMC,      GPIO,       NONE,       NONE,       SMC,        NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO147,   0x230, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO148,   0x234, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO149,   0x238, NAND,     GPIO,       NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO150,   0x23C, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO151,   0x240, SMC,      GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO152,   0x248, SMC,      GPIO,       NONE,       NONE,       SMC,        NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO153,   0x24C, SMC,      GPIO,       NONE,       NONE,       SMC,        NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO154,   0x254, SMC_INT,  GPIO,       SMC,        NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO155,   0x258, EXT_DMA,  GPIO,       SMC,        NONE,       EXT_DMA,    NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO156,   0x14C, PRI_JTAG, GPIO,       PWM,        NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO157,   0x150, PRI_JTAG, GPIO,       PWM,        NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO158,   0x154, PRI_JTAG, GPIO,       PWM,        NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO159,   0x158, PRI_JTAG, GPIO,       PWM,        NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO160,   0x250, NAND,     GPIO,       SMC,        NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO161,   0x210, NAND,     GPIO,       NONE,       NONE,       NAND,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO162,   0x20C, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO163,   0x208, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO164,   0x204, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO165,   0x1EC, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO166,   0x1E8, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO167,   0x1E4, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(GPIO168,   0x1E0, NAND,     GPIO,       MMC3,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(TWSI4_SCL, 0x2BC, TWSI4,    LCD,        NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(TWSI4_SDA, 0x2C0, TWSI4,    LCD,        NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(G_CLKREQ,  0x160, G_CLKREQ, ONE_WIRE,   NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(VCXO_REQ,  0x168, VCXO_REQ, ONE_WIRE,   PLL,        NONE,       NONE,       NONE,     NONE,     NONE),
-       MFPR_MMP2(VCXO_OUT,  0x16C, VCXO_OUT, 32K_CLKOUT, NONE,       NONE,       NONE,       NONE,     NONE,     NONE),
-};
-
-static const unsigned mmp2_uart1_pin1[] = {GPIO29, GPIO30, GPIO31, GPIO32};
-static const unsigned mmp2_uart1_pin2[] = {GPIO45, GPIO46};
-static const unsigned mmp2_uart1_pin3[] = {GPIO140, GPIO141};
-static const unsigned mmp2_uart2_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40};
-static const unsigned mmp2_uart2_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned mmp2_uart2_pin3[] = {GPIO47, GPIO48, GPIO49, GPIO50};
-static const unsigned mmp2_uart2_pin4[] = {GPIO74, GPIO75, GPIO76, GPIO77};
-static const unsigned mmp2_uart2_pin5[] = {GPIO55, GPIO56};
-static const unsigned mmp2_uart2_pin6[] = {GPIO140, GPIO141};
-static const unsigned mmp2_uart3_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40};
-static const unsigned mmp2_uart3_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned mmp2_uart3_pin3[] = {GPIO51, GPIO52, GPIO53, GPIO54};
-static const unsigned mmp2_uart3_pin4[] = {GPIO59, GPIO60, GPIO61, GPIO62};
-static const unsigned mmp2_uart3_pin5[] = {GPIO115, GPIO116, GPIO117, GPIO118};
-static const unsigned mmp2_uart3_pin6[] = {GPIO51, GPIO52};
-static const unsigned mmp2_uart4_pin1[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned mmp2_uart4_pin2[] = {GPIO63, GPIO64, GPIO65, GPIO66};
-static const unsigned mmp2_uart4_pin3[] = {GPIO74, GPIO75, GPIO76, GPIO77};
-static const unsigned mmp2_uart4_pin4[] = {GPIO115, GPIO116, GPIO117, GPIO118};
-static const unsigned mmp2_uart4_pin5[] = {GPIO59, GPIO60};
-static const unsigned mmp2_kpdk_pin1[] = {GPIO16, GPIO17, GPIO18, GPIO19};
-static const unsigned mmp2_kpdk_pin2[] = {GPIO16, GPIO17};
-static const unsigned mmp2_twsi2_pin1[] = {GPIO37, GPIO38};
-static const unsigned mmp2_twsi2_pin2[] = {GPIO39, GPIO40};
-static const unsigned mmp2_twsi2_pin3[] = {GPIO43, GPIO44};
-static const unsigned mmp2_twsi2_pin4[] = {GPIO53, GPIO54};
-static const unsigned mmp2_twsi2_pin5[] = {GPIO55, GPIO56};
-static const unsigned mmp2_twsi3_pin1[] = {GPIO71, GPIO72};
-static const unsigned mmp2_twsi3_pin2[] = {GPIO95, GPIO96};
-static const unsigned mmp2_twsi4_pin1[] = {TWSI4_SCL, TWSI4_SDA};
-static const unsigned mmp2_twsi5_pin1[] = {GPIO41, GPIO42};
-static const unsigned mmp2_twsi5_pin2[] = {GPIO84, GPIO85};
-static const unsigned mmp2_twsi5_pin3[] = {GPIO99, GPIO100};
-static const unsigned mmp2_twsi6_pin1[] = {GPIO47, GPIO48};
-static const unsigned mmp2_twsi6_pin2[] = {GPIO86, GPIO87};
-static const unsigned mmp2_twsi6_pin3[] = {GPIO97, GPIO98};
-static const unsigned mmp2_ccic1_pin1[] = {GPIO12, GPIO13, GPIO14, GPIO15,
-       GPIO16, GPIO17, GPIO18, GPIO19, GPIO20, GPIO21, GPIO22, GPIO23};
-static const unsigned mmp2_ccic1_pin2[] = {GPIO59, GPIO60, GPIO61, GPIO62,
-       GPIO63, GPIO64, GPIO65, GPIO66, GPIO67, GPIO68, GPIO69, GPIO70};
-static const unsigned mmp2_ccic2_pin1[] = {GPIO59, GPIO60, GPIO61, GPIO62,
-       GPIO63, GPIO64, GPIO65, GPIO66, GPIO67, GPIO68, GPIO69, GPIO70};
-static const unsigned mmp2_ccic2_pin2[] = {GPIO82, GPIO83, GPIO86, GPIO87,
-       GPIO88, GPIO89, GPIO90, GPIO91, GPIO92, GPIO93, GPIO94, GPIO95};
-static const unsigned mmp2_ulpi_pin1[] = {GPIO59, GPIO60, GPIO61, GPIO62,
-       GPIO63, GPIO64, GPIO65, GPIO66, GPIO67, GPIO68, GPIO69, GPIO70};
-static const unsigned mmp2_ro_pin1[] = {GPIO16, GPIO17};
-static const unsigned mmp2_ro_pin2[] = {GPIO18, GPIO19};
-static const unsigned mmp2_ro_pin3[] = {GPIO51, GPIO52};
-static const unsigned mmp2_ro_pin4[] = {GPIO55, GPIO56};
-static const unsigned mmp2_i2s_pin1[] = {GPIO24, GPIO25, GPIO26, GPIO27,
-       GPIO28};
-static const unsigned mmp2_i2s_pin2[] = {GPIO33, GPIO34, GPIO35, GPIO36};
-static const unsigned mmp2_ssp1_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40};
-static const unsigned mmp2_ssp1_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned mmp2_ssp1_pin3[] = {GPIO115, GPIO116, GPIO117, GPIO118};
-static const unsigned mmp2_ssp2_pin1[] = {GPIO47, GPIO48, GPIO49, GPIO50};
-static const unsigned mmp2_ssp3_pin1[] = {GPIO119, GPIO120, GPIO121, GPIO122};
-static const unsigned mmp2_ssp3_pin2[] = {GPIO132, GPIO133, GPIO133, GPIO136};
-static const unsigned mmp2_sspa2_pin1[] = {GPIO25, GPIO26, GPIO27, GPIO28};
-static const unsigned mmp2_sspa2_pin2[] = {GPIO33, GPIO34, GPIO35, GPIO36};
-static const unsigned mmp2_mmc1_pin1[] = {GPIO131, GPIO132, GPIO133, GPIO134,
-       GPIO136, GPIO139, GPIO140, GPIO141};
-static const unsigned mmp2_mmc2_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40,
-       GPIO41, GPIO42};
-static const unsigned mmp2_mmc3_pin1[] = {GPIO111, GPIO112, GPIO151, GPIO162,
-       GPIO163, GPIO164, GPIO165, GPIO166, GPIO167, GPIO168};
-
-static struct pxa3xx_pin_group mmp2_grps[] = {
-       GRP_MMP2("uart1 4p1", UART1, mmp2_uart1_pin1),
-       GRP_MMP2("uart1 2p2", UART1, mmp2_uart1_pin2),
-       GRP_MMP2("uart1 2p3", UART1, mmp2_uart1_pin3),
-       GRP_MMP2("uart2 4p1", UART2, mmp2_uart2_pin1),
-       GRP_MMP2("uart2 4p2", UART2, mmp2_uart2_pin2),
-       GRP_MMP2("uart2 4p3", UART2, mmp2_uart2_pin3),
-       GRP_MMP2("uart2 4p4", UART2, mmp2_uart2_pin4),
-       GRP_MMP2("uart2 2p5", UART2, mmp2_uart2_pin5),
-       GRP_MMP2("uart2 2p6", UART2, mmp2_uart2_pin6),
-       GRP_MMP2("uart3 4p1", UART3, mmp2_uart3_pin1),
-       GRP_MMP2("uart3 4p2", UART3, mmp2_uart3_pin2),
-       GRP_MMP2("uart3 4p3", UART3, mmp2_uart3_pin3),
-       GRP_MMP2("uart3 4p4", UART3, mmp2_uart3_pin4),
-       GRP_MMP2("uart3 4p5", UART3, mmp2_uart3_pin5),
-       GRP_MMP2("uart3 2p6", UART3, mmp2_uart3_pin6),
-       GRP_MMP2("uart4 4p1", UART4, mmp2_uart4_pin1),
-       GRP_MMP2("uart4 4p2", UART4, mmp2_uart4_pin2),
-       GRP_MMP2("uart4 4p3", UART4, mmp2_uart4_pin3),
-       GRP_MMP2("uart4 4p4", UART4, mmp2_uart4_pin4),
-       GRP_MMP2("uart4 2p5", UART4, mmp2_uart4_pin5),
-       GRP_MMP2("kpdk 4p1", KP_DK, mmp2_kpdk_pin1),
-       GRP_MMP2("kpdk 4p2", KP_DK, mmp2_kpdk_pin2),
-       GRP_MMP2("twsi2-1", TWSI2, mmp2_twsi2_pin1),
-       GRP_MMP2("twsi2-2", TWSI2, mmp2_twsi2_pin2),
-       GRP_MMP2("twsi2-3", TWSI2, mmp2_twsi2_pin3),
-       GRP_MMP2("twsi2-4", TWSI2, mmp2_twsi2_pin4),
-       GRP_MMP2("twsi2-5", TWSI2, mmp2_twsi2_pin5),
-       GRP_MMP2("twsi3-1", TWSI3, mmp2_twsi3_pin1),
-       GRP_MMP2("twsi3-2", TWSI3, mmp2_twsi3_pin2),
-       GRP_MMP2("twsi4", TWSI4, mmp2_twsi4_pin1),
-       GRP_MMP2("twsi5-1", TWSI5, mmp2_twsi5_pin1),
-       GRP_MMP2("twsi5-2", TWSI5, mmp2_twsi5_pin2),
-       GRP_MMP2("twsi5-3", TWSI5, mmp2_twsi5_pin3),
-       GRP_MMP2("twsi6-1", TWSI6, mmp2_twsi6_pin1),
-       GRP_MMP2("twsi6-2", TWSI6, mmp2_twsi6_pin2),
-       GRP_MMP2("twsi6-3", TWSI6, mmp2_twsi6_pin3),
-       GRP_MMP2("ccic1-1", CCIC1, mmp2_ccic1_pin1),
-       GRP_MMP2("ccic1-2", CCIC1, mmp2_ccic1_pin2),
-       GRP_MMP2("ccic2-1", CCIC2, mmp2_ccic2_pin1),
-       GRP_MMP2("ccic2-1", CCIC2, mmp2_ccic2_pin2),
-       GRP_MMP2("ulpi", ULPI, mmp2_ulpi_pin1),
-       GRP_MMP2("ro-1", ROT, mmp2_ro_pin1),
-       GRP_MMP2("ro-2", ROT, mmp2_ro_pin2),
-       GRP_MMP2("ro-3", ROT, mmp2_ro_pin3),
-       GRP_MMP2("ro-4", ROT, mmp2_ro_pin4),
-       GRP_MMP2("i2s 5p1", I2S, mmp2_i2s_pin1),
-       GRP_MMP2("i2s 4p2", I2S, mmp2_i2s_pin2),
-       GRP_MMP2("ssp1 4p1", SSP1, mmp2_ssp1_pin1),
-       GRP_MMP2("ssp1 4p2", SSP1, mmp2_ssp1_pin2),
-       GRP_MMP2("ssp1 4p3", SSP1, mmp2_ssp1_pin3),
-       GRP_MMP2("ssp2 4p1", SSP2, mmp2_ssp2_pin1),
-       GRP_MMP2("ssp3 4p1", SSP3, mmp2_ssp3_pin1),
-       GRP_MMP2("ssp3 4p2", SSP3, mmp2_ssp3_pin2),
-       GRP_MMP2("sspa2 4p1", SSPA2, mmp2_sspa2_pin1),
-       GRP_MMP2("sspa2 4p2", SSPA2, mmp2_sspa2_pin2),
-       GRP_MMP2("mmc1 8p1", MMC1, mmp2_mmc1_pin1),
-       GRP_MMP2("mmc2 6p1", MMC2, mmp2_mmc2_pin1),
-       GRP_MMP2("mmc3 10p1", MMC3, mmp2_mmc3_pin1),
-};
-
-static const char * const mmp2_uart1_grps[] = {"uart1 4p1", "uart1 2p2",
-       "uart1 2p3"};
-static const char * const mmp2_uart2_grps[] = {"uart2 4p1", "uart2 4p2",
-       "uart2 4p3", "uart2 4p4", "uart2 4p5", "uart2 4p6"};
-static const char * const mmp2_uart3_grps[] = {"uart3 4p1", "uart3 4p2",
-       "uart3 4p3", "uart3 4p4", "uart3 4p5", "uart3 2p6"};
-static const char * const mmp2_uart4_grps[] = {"uart4 4p1", "uart4 4p2",
-       "uart4 4p3", "uart4 4p4", "uart4 2p5"};
-static const char * const mmp2_kpdk_grps[] = {"kpdk 4p1", "kpdk 4p2"};
-static const char * const mmp2_twsi2_grps[] = {"twsi2-1", "twsi2-2",
-       "twsi2-3", "twsi2-4", "twsi2-5"};
-static const char * const mmp2_twsi3_grps[] = {"twsi3-1", "twsi3-2"};
-static const char * const mmp2_twsi4_grps[] = {"twsi4"};
-static const char * const mmp2_twsi5_grps[] = {"twsi5-1", "twsi5-2",
-       "twsi5-3"};
-static const char * const mmp2_twsi6_grps[] = {"twsi6-1", "twsi6-2",
-       "twsi6-3"};
-static const char * const mmp2_ccic1_grps[] = {"ccic1-1", "ccic1-2"};
-static const char * const mmp2_ccic2_grps[] = {"ccic2-1", "ccic2-2"};
-static const char * const mmp2_ulpi_grps[] = {"ulpi"};
-static const char * const mmp2_ro_grps[] = {"ro-1", "ro-2", "ro-3", "ro-4"};
-static const char * const mmp2_i2s_grps[] = {"i2s 5p1", "i2s 4p2"};
-static const char * const mmp2_ssp1_grps[] = {"ssp1 4p1", "ssp1 4p2",
-       "ssp1 4p3"};
-static const char * const mmp2_ssp2_grps[] = {"ssp2 4p1"};
-static const char * const mmp2_ssp3_grps[] = {"ssp3 4p1", "ssp3 4p2"};
-static const char * const mmp2_sspa2_grps[] = {"sspa2 4p1", "sspa2 4p2"};
-static const char * const mmp2_mmc1_grps[] = {"mmc1 8p1"};
-static const char * const mmp2_mmc2_grps[] = {"mmc2 6p1"};
-static const char * const mmp2_mmc3_grps[] = {"mmc3 10p1"};
-
-static struct pxa3xx_pmx_func mmp2_funcs[] = {
-       {"uart1",       ARRAY_AND_SIZE(mmp2_uart1_grps)},
-       {"uart2",       ARRAY_AND_SIZE(mmp2_uart2_grps)},
-       {"uart3",       ARRAY_AND_SIZE(mmp2_uart3_grps)},
-       {"uart4",       ARRAY_AND_SIZE(mmp2_uart4_grps)},
-       {"kpdk",        ARRAY_AND_SIZE(mmp2_kpdk_grps)},
-       {"twsi2",       ARRAY_AND_SIZE(mmp2_twsi2_grps)},
-       {"twsi3",       ARRAY_AND_SIZE(mmp2_twsi3_grps)},
-       {"twsi4",       ARRAY_AND_SIZE(mmp2_twsi4_grps)},
-       {"twsi5",       ARRAY_AND_SIZE(mmp2_twsi5_grps)},
-       {"twsi6",       ARRAY_AND_SIZE(mmp2_twsi6_grps)},
-       {"ccic1",       ARRAY_AND_SIZE(mmp2_ccic1_grps)},
-       {"ccic2",       ARRAY_AND_SIZE(mmp2_ccic2_grps)},
-       {"ulpi",        ARRAY_AND_SIZE(mmp2_ulpi_grps)},
-       {"ro",          ARRAY_AND_SIZE(mmp2_ro_grps)},
-       {"i2s",         ARRAY_AND_SIZE(mmp2_i2s_grps)},
-       {"ssp1",        ARRAY_AND_SIZE(mmp2_ssp1_grps)},
-       {"ssp2",        ARRAY_AND_SIZE(mmp2_ssp2_grps)},
-       {"ssp3",        ARRAY_AND_SIZE(mmp2_ssp3_grps)},
-       {"sspa2",       ARRAY_AND_SIZE(mmp2_sspa2_grps)},
-       {"mmc1",        ARRAY_AND_SIZE(mmp2_mmc1_grps)},
-       {"mmc2",        ARRAY_AND_SIZE(mmp2_mmc2_grps)},
-       {"mmc3",        ARRAY_AND_SIZE(mmp2_mmc3_grps)},
-};
-
-static struct pinctrl_desc mmp2_pctrl_desc = {
-       .name           = "mmp2-pinctrl",
-       .owner          = THIS_MODULE,
-};
-
-static struct pxa3xx_pinmux_info mmp2_info = {
-       .mfp            = mmp2_mfp,
-       .num_mfp        = ARRAY_SIZE(mmp2_mfp),
-       .grps           = mmp2_grps,
-       .num_grps       = ARRAY_SIZE(mmp2_grps),
-       .funcs          = mmp2_funcs,
-       .num_funcs      = ARRAY_SIZE(mmp2_funcs),
-       .num_gpio       = 169,
-       .desc           = &mmp2_pctrl_desc,
-       .pads           = mmp2_pads,
-       .num_pads       = ARRAY_SIZE(mmp2_pads),
-
-       .cputype        = PINCTRL_MMP2,
-       .ds_mask        = MMP2_DS_MASK,
-       .ds_shift       = MMP2_DS_SHIFT,
-};
-
-static int mmp2_pinmux_probe(struct platform_device *pdev)
-{
-       return pxa3xx_pinctrl_register(pdev, &mmp2_info);
-}
-
-static int mmp2_pinmux_remove(struct platform_device *pdev)
-{
-       return pxa3xx_pinctrl_unregister(pdev);
-}
-
-static struct platform_driver mmp2_pinmux_driver = {
-       .driver = {
-               .name   = "mmp2-pinmux",
-               .owner  = THIS_MODULE,
-       },
-       .probe  = mmp2_pinmux_probe,
-       .remove = mmp2_pinmux_remove,
-};
-
-static int __init mmp2_pinmux_init(void)
-{
-       return platform_driver_register(&mmp2_pinmux_driver);
-}
-core_initcall_sync(mmp2_pinmux_init);
-
-static void __exit mmp2_pinmux_exit(void)
-{
-       platform_driver_unregister(&mmp2_pinmux_driver);
-}
-module_exit(mmp2_pinmux_exit);
-
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_DESCRIPTION("PXA3xx pin control driver");
-MODULE_LICENSE("GPL v2");
index 23af9f1..b45c4eb 100644 (file)
@@ -158,7 +158,7 @@ static void mxs_dt_free_map(struct pinctrl_dev *pctldev,
        kfree(map);
 }
 
-static struct pinctrl_ops mxs_pinctrl_ops = {
+static const struct pinctrl_ops mxs_pinctrl_ops = {
        .get_groups_count = mxs_get_groups_count,
        .get_group_name = mxs_get_group_name,
        .get_group_pins = mxs_get_group_pins,
@@ -219,7 +219,7 @@ static int mxs_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned selector,
        return 0;
 }
 
-static struct pinmux_ops mxs_pinmux_ops = {
+static const struct pinmux_ops mxs_pinmux_ops = {
        .get_functions_count = mxs_pinctrl_get_funcs_count,
        .get_function_name = mxs_pinctrl_get_func_name,
        .get_function_groups = mxs_pinctrl_get_func_groups,
@@ -319,7 +319,7 @@ static void mxs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
                seq_printf(s, "0x%lx", config);
 }
 
-static struct pinconf_ops mxs_pinconf_ops = {
+static const struct pinconf_ops mxs_pinconf_ops = {
        .pin_config_get = mxs_pinconf_get,
        .pin_config_set = mxs_pinconf_set,
        .pin_config_group_get = mxs_pinconf_group_get,
index 30b4da9..c748407 100644 (file)
@@ -466,7 +466,7 @@ static const unsigned mc1_a_1_pins[] = { DB8500_PIN_AH16, DB8500_PIN_AG15,
        DB8500_PIN_AJ15, DB8500_PIN_AG14, DB8500_PIN_AF13, DB8500_PIN_AG13,
        DB8500_PIN_AH15 };
 static const unsigned mc1_a_2_pins[] = { DB8500_PIN_AH16, DB8500_PIN_AJ15,
-       DB8500_PIN_AG14, DB8500_PIN_AF13, DB8500_PIN_AG13,DB8500_PIN_AH15 };
+       DB8500_PIN_AG14, DB8500_PIN_AF13, DB8500_PIN_AG13, DB8500_PIN_AH15 };
 static const unsigned mc1dir_a_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
        DB8500_PIN_AH12, DB8500_PIN_AH11 };
 static const unsigned hsir_a_1_pins[] = { DB8500_PIN_AG10, DB8500_PIN_AH10,
@@ -663,7 +663,7 @@ static const unsigned hwobs_oc4_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16,
        DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
        DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
 
-#define DB8500_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins,          \
+#define DB8500_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins,         \
                        .npins = ARRAY_SIZE(a##_pins), .altsetting = b }
 
 static const struct nmk_pingroup nmk_db8500_groups[] = {
index 924a339..ed39dca 100644 (file)
@@ -299,7 +299,7 @@ static const unsigned i2c0_a_1_pins[] = { STN8815_PIN_D3, STN8815_PIN_D2 };
 static const unsigned u1_b_1_pins[] = { STN8815_PIN_B16, STN8815_PIN_A16 };
 static const unsigned i2cusb_b_1_pins[] = { STN8815_PIN_C21, STN8815_PIN_C20 };
 
-#define STN8815_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins,         \
+#define STN8815_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins,                \
                        .npins = ARRAY_SIZE(a##_pins), .altsetting = b }
 
 static const struct nmk_pingroup nmk_stn8815_groups[] = {
index 36d2029..435bf30 100644 (file)
@@ -1565,8 +1565,8 @@ static int nmk_dt_add_map_configs(struct pinctrl_map **map,
        return 0;
 }
 
-#define NMK_CONFIG_PIN(x,y) { .property = x, .config = y, }
-#define NMK_CONFIG_PIN_ARRAY(x,y) { .property = x, .choice = y, \
+#define NMK_CONFIG_PIN(x, y) { .property = x, .config = y, }
+#define NMK_CONFIG_PIN_ARRAY(x, y) { .property = x, .choice = y, \
        .size = ARRAY_SIZE(y), }
 
 static const unsigned long nmk_pin_input_modes[] = {
@@ -1764,7 +1764,7 @@ int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
        return 0;
 }
 
-static struct pinctrl_ops nmk_pinctrl_ops = {
+static const struct pinctrl_ops nmk_pinctrl_ops = {
        .get_groups_count = nmk_get_groups_cnt,
        .get_group_name = nmk_get_group_name,
        .get_group_pins = nmk_get_group_pins,
@@ -1975,7 +1975,7 @@ static void nmk_gpio_disable_free(struct pinctrl_dev *pctldev,
        /* Set the pin to some default state, GPIO is usually default */
 }
 
-static struct pinmux_ops nmk_pinmux_ops = {
+static const struct pinmux_ops nmk_pinmux_ops = {
        .get_functions_count = nmk_pmx_get_funcs_cnt,
        .get_function_name = nmk_pmx_get_func_name,
        .get_function_groups = nmk_pmx_get_func_groups,
@@ -2068,7 +2068,7 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
                pin, cfg, pullnames[pull], slpmnames[slpm],
                output ? "output " : "input",
                output ? (val ? "high" : "low") : "",
-               lowemi ? "on" : "off" );
+               lowemi ? "on" : "off");
 
        clk_enable(nmk_chip->clk);
        bit = pin % NMK_GPIO_PER_CHIP;
@@ -2089,7 +2089,7 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
        return 0;
 }
 
-static struct pinconf_ops nmk_pinconf_ops = {
+static const struct pinconf_ops nmk_pinconf_ops = {
        .pin_config_get = nmk_pin_config_get,
        .pin_config_set = nmk_pin_config_set,
 };
@@ -2111,6 +2111,10 @@ static const struct of_device_id nmk_pinctrl_match[] = {
                .compatible = "stericsson,nmk-pinctrl",
                .data = (void *)PINCTRL_NMK_DB8500,
        },
+       {
+               .compatible = "stericsson,nmk-pinctrl-db8540",
+               .data = (void *)PINCTRL_NMK_DB8540,
+       },
        {},
 };
 
diff --git a/drivers/pinctrl/pinctrl-pxa168.c b/drivers/pinctrl/pinctrl-pxa168.c
deleted file mode 100644 (file)
index d9cd2b4..0000000
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
- *  linux/drivers/pinctrl/pinmux-pxa168.c
- *
- *  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
- *  publishhed by the Free Software Foundation.
- *
- *  Copyright (C) 2011, Marvell Technology Group Ltd.
- *
- *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include "pinctrl-pxa3xx.h"
-
-#define PXA168_DS_MASK         0x1800
-#define PXA168_DS_SHIFT                11
-#define PXA168_SLEEP_MASK      0x38
-#define PXA168_SLEEP_SELECT    (1 << 9)
-#define PXA168_SLEEP_DATA      (1 << 8)
-#define PXA168_SLEEP_DIR       (1 << 7)
-
-#define MFPR_168(a, r, f0, f1, f2, f3, f4, f5, f6, f7)         \
-       {                                                       \
-               .name = #a,                                     \
-               .pin = a,                                       \
-               .mfpr = r,                                      \
-               .func = {                                       \
-                       PXA168_MUX_##f0,                        \
-                       PXA168_MUX_##f1,                        \
-                       PXA168_MUX_##f2,                        \
-                       PXA168_MUX_##f3,                        \
-                       PXA168_MUX_##f4,                        \
-                       PXA168_MUX_##f5,                        \
-                       PXA168_MUX_##f6,                        \
-                       PXA168_MUX_##f7,                        \
-               },                                              \
-       }
-
-#define GRP_168(a, m, p)               \
-       { .name = a, .mux = PXA168_MUX_##m, .pins = p, .npins = ARRAY_SIZE(p), }
-
-/* 131 pins */
-enum pxa168_pin_list {
-       /* 0~122: GPIO0~GPIO122 */
-       PWR_SCL = 123,
-       PWR_SDA,
-       TDI,
-       TMS,
-       TCK,
-       TDO,
-       TRST,
-       WAKEUP = 130,
-};
-
-enum pxa168_mux {
-       /* PXA3xx_MUX_GPIO = 0 (predefined in pinctrl-pxa3xx.h) */
-       PXA168_MUX_GPIO = 0,
-       PXA168_MUX_DFIO,
-       PXA168_MUX_NAND,
-       PXA168_MUX_SMC,
-       PXA168_MUX_SMC_CS0,
-       PXA168_MUX_SMC_CS1,
-       PXA168_MUX_SMC_INT,
-       PXA168_MUX_SMC_RDY,
-       PXA168_MUX_MMC1,
-       PXA168_MUX_MMC2,
-       PXA168_MUX_MMC2_CMD,
-       PXA168_MUX_MMC2_CLK,
-       PXA168_MUX_MMC3,
-       PXA168_MUX_MMC3_CMD,
-       PXA168_MUX_MMC3_CLK,
-       PXA168_MUX_MMC4,
-       PXA168_MUX_MSP,
-       PXA168_MUX_MSP_DAT3,
-       PXA168_MUX_MSP_INS,
-       PXA168_MUX_I2C,
-       PXA168_MUX_PWRI2C,
-       PXA168_MUX_AC97,
-       PXA168_MUX_AC97_SYSCLK,
-       PXA168_MUX_PWM,
-       PXA168_MUX_PWM1,
-       PXA168_MUX_XD,
-       PXA168_MUX_XP,
-       PXA168_MUX_LCD,
-       PXA168_MUX_CCIC,
-       PXA168_MUX_CF,
-       PXA168_MUX_CF_RDY,
-       PXA168_MUX_CF_nINPACK,
-       PXA168_MUX_CF_nWAIT,
-       PXA168_MUX_KP_MKOUT,
-       PXA168_MUX_KP_MKIN,
-       PXA168_MUX_KP_DK,
-       PXA168_MUX_ETH,
-       PXA168_MUX_ETH_TX,
-       PXA168_MUX_ETH_RX,
-       PXA168_MUX_ONE_WIRE,
-       PXA168_MUX_UART1,
-       PXA168_MUX_UART1_TX,
-       PXA168_MUX_UART1_CTS,
-       PXA168_MUX_UART1_nRI,
-       PXA168_MUX_UART1_DTR,
-       PXA168_MUX_UART2,
-       PXA168_MUX_UART2_TX,
-       PXA168_MUX_UART3,
-       PXA168_MUX_UART3_TX,
-       PXA168_MUX_UART3_CTS,
-       PXA168_MUX_SSP1,
-       PXA168_MUX_SSP1_TX,
-       PXA168_MUX_SSP2,
-       PXA168_MUX_SSP2_TX,
-       PXA168_MUX_SSP3,
-       PXA168_MUX_SSP3_TX,
-       PXA168_MUX_SSP4,
-       PXA168_MUX_SSP4_TX,
-       PXA168_MUX_SSP5,
-       PXA168_MUX_SSP5_TX,
-       PXA168_MUX_USB,
-       PXA168_MUX_JTAG,
-       PXA168_MUX_RESET,
-       PXA168_MUX_WAKEUP,
-       PXA168_MUX_EXT_32K_IN,
-       PXA168_MUX_NONE = 0xffff,
-};
-
-static struct pinctrl_pin_desc pxa168_pads[] = {
-       PINCTRL_PIN(GPIO0, "GPIO0"),
-       PINCTRL_PIN(GPIO1, "GPIO1"),
-       PINCTRL_PIN(GPIO2, "GPIO2"),
-       PINCTRL_PIN(GPIO3, "GPIO3"),
-       PINCTRL_PIN(GPIO4, "GPIO4"),
-       PINCTRL_PIN(GPIO5, "GPIO5"),
-       PINCTRL_PIN(GPIO6, "GPIO6"),
-       PINCTRL_PIN(GPIO7, "GPIO7"),
-       PINCTRL_PIN(GPIO8, "GPIO8"),
-       PINCTRL_PIN(GPIO9, "GPIO9"),
-       PINCTRL_PIN(GPIO10, "GPIO10"),
-       PINCTRL_PIN(GPIO11, "GPIO11"),
-       PINCTRL_PIN(GPIO12, "GPIO12"),
-       PINCTRL_PIN(GPIO13, "GPIO13"),
-       PINCTRL_PIN(GPIO14, "GPIO14"),
-       PINCTRL_PIN(GPIO15, "GPIO15"),
-       PINCTRL_PIN(GPIO16, "GPIO16"),
-       PINCTRL_PIN(GPIO17, "GPIO17"),
-       PINCTRL_PIN(GPIO18, "GPIO18"),
-       PINCTRL_PIN(GPIO19, "GPIO19"),
-       PINCTRL_PIN(GPIO20, "GPIO20"),
-       PINCTRL_PIN(GPIO21, "GPIO21"),
-       PINCTRL_PIN(GPIO22, "GPIO22"),
-       PINCTRL_PIN(GPIO23, "GPIO23"),
-       PINCTRL_PIN(GPIO24, "GPIO24"),
-       PINCTRL_PIN(GPIO25, "GPIO25"),
-       PINCTRL_PIN(GPIO26, "GPIO26"),
-       PINCTRL_PIN(GPIO27, "GPIO27"),
-       PINCTRL_PIN(GPIO28, "GPIO28"),
-       PINCTRL_PIN(GPIO29, "GPIO29"),
-       PINCTRL_PIN(GPIO30, "GPIO30"),
-       PINCTRL_PIN(GPIO31, "GPIO31"),
-       PINCTRL_PIN(GPIO32, "GPIO32"),
-       PINCTRL_PIN(GPIO33, "GPIO33"),
-       PINCTRL_PIN(GPIO34, "GPIO34"),
-       PINCTRL_PIN(GPIO35, "GPIO35"),
-       PINCTRL_PIN(GPIO36, "GPIO36"),
-       PINCTRL_PIN(GPIO37, "GPIO37"),
-       PINCTRL_PIN(GPIO38, "GPIO38"),
-       PINCTRL_PIN(GPIO39, "GPIO39"),
-       PINCTRL_PIN(GPIO40, "GPIO40"),
-       PINCTRL_PIN(GPIO41, "GPIO41"),
-       PINCTRL_PIN(GPIO42, "GPIO42"),
-       PINCTRL_PIN(GPIO43, "GPIO43"),
-       PINCTRL_PIN(GPIO44, "GPIO44"),
-       PINCTRL_PIN(GPIO45, "GPIO45"),
-       PINCTRL_PIN(GPIO46, "GPIO46"),
-       PINCTRL_PIN(GPIO47, "GPIO47"),
-       PINCTRL_PIN(GPIO48, "GPIO48"),
-       PINCTRL_PIN(GPIO49, "GPIO49"),
-       PINCTRL_PIN(GPIO50, "GPIO50"),
-       PINCTRL_PIN(GPIO51, "GPIO51"),
-       PINCTRL_PIN(GPIO52, "GPIO52"),
-       PINCTRL_PIN(GPIO53, "GPIO53"),
-       PINCTRL_PIN(GPIO54, "GPIO54"),
-       PINCTRL_PIN(GPIO55, "GPIO55"),
-       PINCTRL_PIN(GPIO56, "GPIO56"),
-       PINCTRL_PIN(GPIO57, "GPIO57"),
-       PINCTRL_PIN(GPIO58, "GPIO58"),
-       PINCTRL_PIN(GPIO59, "GPIO59"),
-       PINCTRL_PIN(GPIO60, "GPIO60"),
-       PINCTRL_PIN(GPIO61, "GPIO61"),
-       PINCTRL_PIN(GPIO62, "GPIO62"),
-       PINCTRL_PIN(GPIO63, "GPIO63"),
-       PINCTRL_PIN(GPIO64, "GPIO64"),
-       PINCTRL_PIN(GPIO65, "GPIO65"),
-       PINCTRL_PIN(GPIO66, "GPIO66"),
-       PINCTRL_PIN(GPIO67, "GPIO67"),
-       PINCTRL_PIN(GPIO68, "GPIO68"),
-       PINCTRL_PIN(GPIO69, "GPIO69"),
-       PINCTRL_PIN(GPIO70, "GPIO70"),
-       PINCTRL_PIN(GPIO71, "GPIO71"),
-       PINCTRL_PIN(GPIO72, "GPIO72"),
-       PINCTRL_PIN(GPIO73, "GPIO73"),
-       PINCTRL_PIN(GPIO74, "GPIO74"),
-       PINCTRL_PIN(GPIO75, "GPIO75"),
-       PINCTRL_PIN(GPIO76, "GPIO76"),
-       PINCTRL_PIN(GPIO77, "GPIO77"),
-       PINCTRL_PIN(GPIO78, "GPIO78"),
-       PINCTRL_PIN(GPIO79, "GPIO79"),
-       PINCTRL_PIN(GPIO80, "GPIO80"),
-       PINCTRL_PIN(GPIO81, "GPIO81"),
-       PINCTRL_PIN(GPIO82, "GPIO82"),
-       PINCTRL_PIN(GPIO83, "GPIO83"),
-       PINCTRL_PIN(GPIO84, "GPIO84"),
-       PINCTRL_PIN(GPIO85, "GPIO85"),
-       PINCTRL_PIN(GPIO86, "GPIO86"),
-       PINCTRL_PIN(GPIO87, "GPIO87"),
-       PINCTRL_PIN(GPIO88, "GPIO88"),
-       PINCTRL_PIN(GPIO89, "GPIO89"),
-       PINCTRL_PIN(GPIO90, "GPIO90"),
-       PINCTRL_PIN(GPIO91, "GPIO91"),
-       PINCTRL_PIN(GPIO92, "GPIO92"),
-       PINCTRL_PIN(GPIO93, "GPIO93"),
-       PINCTRL_PIN(GPIO94, "GPIO94"),
-       PINCTRL_PIN(GPIO95, "GPIO95"),
-       PINCTRL_PIN(GPIO96, "GPIO96"),
-       PINCTRL_PIN(GPIO97, "GPIO97"),
-       PINCTRL_PIN(GPIO98, "GPIO98"),
-       PINCTRL_PIN(GPIO99, "GPIO99"),
-       PINCTRL_PIN(GPIO100, "GPIO100"),
-       PINCTRL_PIN(GPIO101, "GPIO101"),
-       PINCTRL_PIN(GPIO102, "GPIO102"),
-       PINCTRL_PIN(GPIO103, "GPIO103"),
-       PINCTRL_PIN(GPIO104, "GPIO104"),
-       PINCTRL_PIN(GPIO105, "GPIO105"),
-       PINCTRL_PIN(GPIO106, "GPIO106"),
-       PINCTRL_PIN(GPIO107, "GPIO107"),
-       PINCTRL_PIN(GPIO108, "GPIO108"),
-       PINCTRL_PIN(GPIO109, "GPIO109"),
-       PINCTRL_PIN(GPIO110, "GPIO110"),
-       PINCTRL_PIN(GPIO111, "GPIO111"),
-       PINCTRL_PIN(GPIO112, "GPIO112"),
-       PINCTRL_PIN(GPIO113, "GPIO113"),
-       PINCTRL_PIN(GPIO114, "GPIO114"),
-       PINCTRL_PIN(GPIO115, "GPIO115"),
-       PINCTRL_PIN(GPIO116, "GPIO116"),
-       PINCTRL_PIN(GPIO117, "GPIO117"),
-       PINCTRL_PIN(GPIO118, "GPIO118"),
-       PINCTRL_PIN(GPIO119, "GPIO119"),
-       PINCTRL_PIN(GPIO120, "GPIO120"),
-       PINCTRL_PIN(GPIO121, "GPIO121"),
-       PINCTRL_PIN(GPIO122, "GPIO122"),
-       PINCTRL_PIN(PWR_SCL, "PWR_SCL"),
-       PINCTRL_PIN(PWR_SDA, "PWR_SDA"),
-       PINCTRL_PIN(TDI, "TDI"),
-       PINCTRL_PIN(TMS, "TMS"),
-       PINCTRL_PIN(TCK, "TCK"),
-       PINCTRL_PIN(TDO, "TDO"),
-       PINCTRL_PIN(TRST, "TRST"),
-       PINCTRL_PIN(WAKEUP, "WAKEUP"),
-};
-
-struct pxa3xx_mfp_pin pxa168_mfp[] = {
-       /*       pin      offs   f0       f1           f2         f3           f4           f5        f6           f7  */
-       MFPR_168(GPIO0,   0x04C, DFIO,    NONE,        NONE,      MSP,         MMC3_CMD,    GPIO,     MMC3,        NONE),
-       MFPR_168(GPIO1,   0x050, DFIO,    NONE,        NONE,      MSP,         MMC3_CLK,    GPIO,     MMC3,        NONE),
-       MFPR_168(GPIO2,   0x054, DFIO,    NONE,        NONE,      MSP,         NONE,        GPIO,     MMC3,        NONE),
-       MFPR_168(GPIO3,   0x058, DFIO,    NONE,        NONE,      NONE,        NONE,        GPIO,     MMC3,        NONE),
-       MFPR_168(GPIO4,   0x05C, DFIO,    NONE,        NONE,      MSP_DAT3,    NONE,        GPIO,     MMC3,        NONE),
-       MFPR_168(GPIO5,   0x060, DFIO,    NONE,        NONE,      MSP,         NONE,        GPIO,     MMC3,        NONE),
-       MFPR_168(GPIO6,   0x064, DFIO,    NONE,        NONE,      MSP,         NONE,        GPIO,     MMC3,        NONE),
-       MFPR_168(GPIO7,   0x068, DFIO,    NONE,        NONE,      MSP,         NONE,        GPIO,     MMC3,        NONE),
-       MFPR_168(GPIO8,   0x06C, DFIO,    MMC2,        UART3_TX,  NONE,        MMC2_CMD,    GPIO,     MMC3_CLK,    NONE),
-       MFPR_168(GPIO9,   0x070, DFIO,    MMC2,        UART3,     NONE,        MMC2_CLK,    GPIO,     MMC3_CMD,    NONE),
-       MFPR_168(GPIO10,  0x074, DFIO,    MMC2,        UART3,     NONE,        NONE,        GPIO,     MSP_DAT3,    NONE),
-       MFPR_168(GPIO11,  0x078, DFIO,    MMC2,        UART3,     NONE,        NONE,        GPIO,     MSP,         NONE),
-       MFPR_168(GPIO12,  0x07C, DFIO,    MMC2,        UART3,     NONE,        NONE,        GPIO,     MSP,         NONE),
-       MFPR_168(GPIO13,  0x080, DFIO,    MMC2,        UART3,     NONE,        NONE,        GPIO,     MSP,         NONE),
-       MFPR_168(GPIO14,  0x084, DFIO,    MMC2,        NONE,      NONE,        NONE,        GPIO,     MSP,         NONE),
-       MFPR_168(GPIO15,  0x088, DFIO,    MMC2,        NONE,      NONE,        NONE,        GPIO,     MSP,         NONE),
-       MFPR_168(GPIO16,  0x08C, GPIO,    NAND,        SMC_CS0,   SMC_CS1,     NONE,        NONE,     MMC3,        NONE),
-       MFPR_168(GPIO17,  0x090, NAND,    NONE,        NONE,      NONE,        NONE,        GPIO,     MSP,         NONE),
-       MFPR_168(GPIO18,  0x094, GPIO,    NAND,        SMC_CS1,   SMC_CS0,     NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO19,  0x098, SMC_CS0, NONE,        NONE,      CF,          NONE,        GPIO,     NONE,        NONE),
-       MFPR_168(GPIO20,  0x09C, GPIO,    NONE,        SMC_CS1,   CF,          CF_RDY,      NONE,     NONE,        NONE),
-       MFPR_168(GPIO21,  0x0A0, NAND,    MMC2_CLK,    NONE,      NONE,        NONE,        GPIO,     NONE,        NONE),
-       MFPR_168(GPIO22,  0x0A4, NAND,    MMC2_CMD,    NONE,      NONE,        NONE,        GPIO,     NONE,        NONE),
-       MFPR_168(GPIO23,  0x0A8, SMC,     NAND,        NONE,      CF,          NONE,        GPIO,     NONE,        NONE),
-       MFPR_168(GPIO24,  0x0AC, NAND,    NONE,        NONE,      NONE,        NONE,        GPIO,     NONE,        NONE),
-       MFPR_168(GPIO25,  0x0B0, SMC,     NAND,        NONE,      CF,          NONE,        GPIO,     NONE,        NONE),
-       MFPR_168(GPIO26,  0x0B4, GPIO,    NAND,        NONE,      NONE,        CF,          NONE,     NONE,        NONE),
-       MFPR_168(GPIO27,  0x0B8, SMC_INT, NAND,        SMC,       NONE,        SMC_RDY,     GPIO,     NONE,        NONE),
-       MFPR_168(GPIO28,  0x0BC, SMC_RDY, MMC4,        SMC,       CF_RDY,      NONE,        GPIO,     MMC2_CMD,    NONE),
-       MFPR_168(GPIO29,  0x0C0, SMC,     MMC4,        NONE,      CF,          NONE,        GPIO,     MMC2_CLK,    KP_DK),
-       MFPR_168(GPIO30,  0x0C4, SMC,     MMC4,        UART3_TX,  CF,          NONE,        GPIO,     MMC2,        KP_DK),
-       MFPR_168(GPIO31,  0x0C8, SMC,     MMC4,        UART3,     CF,          NONE,        GPIO,     MMC2,        KP_DK),
-       MFPR_168(GPIO32,  0x0CC, SMC,     MMC4,        UART3,     CF,          NONE,        GPIO,     MMC2,        KP_DK),
-       MFPR_168(GPIO33,  0x0D0, SMC,     MMC4,        UART3,     CF,          CF_nINPACK,  GPIO,     MMC2,        KP_DK),
-       MFPR_168(GPIO34,  0x0D4, GPIO,    NONE,        SMC_CS1,   CF,          CF_nWAIT,    NONE,     MMC3,        KP_DK),
-       MFPR_168(GPIO35,  0x0D8, GPIO,    NONE,        SMC,       CF_nINPACK,  NONE,        NONE,     MMC3_CMD,    KP_DK),
-       MFPR_168(GPIO36,  0x0DC, GPIO,    NONE,        SMC,       CF_nWAIT,    NONE,        NONE,     MMC3_CLK,    KP_DK),
-       MFPR_168(GPIO37,  0x000, GPIO,    MMC1,        NONE,      KP_MKOUT,    CCIC,        XP,       KP_MKIN,     KP_DK),
-       MFPR_168(GPIO38,  0x004, GPIO,    MMC1,        NONE,      KP_MKOUT,    CCIC,        XP,       KP_MKIN,     KP_DK),
-       MFPR_168(GPIO39,  0x008, GPIO,    NONE,        NONE,      KP_MKOUT,    CCIC,        XP,       KP_MKIN,     KP_DK),
-       MFPR_168(GPIO40,  0x00C, GPIO,    MMC1,        MSP,       KP_MKOUT,    CCIC,        XP,       KP_MKIN,     KP_DK),
-       MFPR_168(GPIO41,  0x010, GPIO,    MMC1,        MSP,       NONE,        CCIC,        XP,       KP_MKIN,     KP_DK),
-       MFPR_168(GPIO42,  0x014, GPIO,    I2C,         NONE,      MSP,         CCIC,        XP,       KP_MKIN,     KP_DK),
-       MFPR_168(GPIO43,  0x018, GPIO,    MMC1,        MSP,       MSP_INS,     NONE,        NONE,     KP_MKIN,     KP_DK),
-       MFPR_168(GPIO44,  0x01C, GPIO,    MMC1,        MSP_DAT3,  MSP,         CCIC,        XP,       KP_MKIN,     KP_DK),
-       MFPR_168(GPIO45,  0x020, GPIO,    NONE,        NONE,      MSP,         CCIC,        XP,       NONE,        KP_DK),
-       MFPR_168(GPIO46,  0x024, GPIO,    MMC1,        MSP_INS,   MSP,         CCIC,        NONE,     KP_MKOUT,    KP_DK),
-       MFPR_168(GPIO47,  0x028, GPIO,    NONE,        NONE,      MSP_INS,     NONE,        XP,       NONE,        KP_DK),
-       MFPR_168(GPIO48,  0x02C, GPIO,    MMC1,        NONE,      MSP_DAT3,    CCIC,        NONE,     NONE,        KP_DK),
-       MFPR_168(GPIO49,  0x030, GPIO,    MMC1,        NONE,      MSP,         NONE,        XD,       KP_MKOUT,    NONE),
-       MFPR_168(GPIO50,  0x034, GPIO,    I2C,         NONE,      MSP,         CCIC,        XD,       KP_MKOUT,    NONE),
-       MFPR_168(GPIO51,  0x038, GPIO,    MMC1,        NONE,      MSP,         NONE,        XD,       KP_MKOUT,    NONE),
-       MFPR_168(GPIO52,  0x03C, GPIO,    MMC1,        NONE,      MSP,         NONE,        XD,       KP_MKOUT,    NONE),
-       MFPR_168(GPIO53,  0x040, GPIO,    MMC1,        NONE,      NONE,        NONE,        XD,       KP_MKOUT,    NONE),
-       MFPR_168(GPIO54,  0x044, GPIO,    MMC1,        NONE,      NONE,        CCIC,        XD,       KP_MKOUT,    NONE),
-       MFPR_168(GPIO55,  0x048, GPIO,    NONE,        NONE,      MSP,         CCIC,        XD,       KP_MKOUT,    NONE),
-       MFPR_168(GPIO56,  0x0E0, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO57,  0x0E4, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO58,  0x0E8, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO59,  0x0EC, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO60,  0x0F0, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO61,  0x0F4, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO62,  0x0F8, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO63,  0x0FC, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO64,  0x100, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO65,  0x104, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO66,  0x108, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO67,  0x10C, GPIO,    LCD,         NONE,      NONE,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO68,  0x110, GPIO,    LCD,         NONE,      XD,          NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO69,  0x114, GPIO,    LCD,         NONE,      XD,          NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO70,  0x118, GPIO,    LCD,         NONE,      XD,          NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO71,  0x11C, GPIO,    LCD,         NONE,      XD,          NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO72,  0x120, GPIO,    LCD,         NONE,      XD,          NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO73,  0x124, GPIO,    LCD,         NONE,      XD,          NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO74,  0x128, GPIO,    LCD,         PWM,       XD,          NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO75,  0x12C, GPIO,    LCD,         PWM,       XD,          ONE_WIRE,    NONE,     NONE,        NONE),
-       MFPR_168(GPIO76,  0x130, GPIO,    LCD,         PWM,       I2C,         NONE,        NONE,     MSP_INS,     NONE),
-       MFPR_168(GPIO77,  0x134, GPIO,    LCD,         PWM1,      I2C,         ONE_WIRE,    NONE,     XD,          NONE),
-       MFPR_168(GPIO78,  0x138, GPIO,    LCD,         NONE,      NONE,        NONE,        MMC4,     NONE,        NONE),
-       MFPR_168(GPIO79,  0x13C, GPIO,    LCD,         NONE,      NONE,        ONE_WIRE,    MMC4,     NONE,        NONE),
-       MFPR_168(GPIO80,  0x140, GPIO,    LCD,         NONE,      I2C,         NONE,        MMC4,     NONE,        NONE),
-       MFPR_168(GPIO81,  0x144, GPIO,    LCD,         NONE,      I2C,         ONE_WIRE,    MMC4,     NONE,        NONE),
-       MFPR_168(GPIO82,  0x148, GPIO,    LCD,         PWM,       NONE,        NONE,        MMC4,     NONE,        NONE),
-       MFPR_168(GPIO83,  0x14C, GPIO,    LCD,         PWM,       NONE,        RESET,       MMC4,     NONE,        NONE),
-       MFPR_168(GPIO84,  0x150, GPIO,    NONE,        PWM,       ONE_WIRE,    PWM1,        NONE,     NONE,        EXT_32K_IN),
-       MFPR_168(GPIO85,  0x154, GPIO,    NONE,        PWM1,      NONE,        NONE,        NONE,     NONE,        USB),
-       MFPR_168(GPIO86,  0x158, GPIO,    MMC2,        UART2,     NONE,        JTAG,        ETH_TX,   SSP5_TX,     SSP5),
-       MFPR_168(GPIO87,  0x15C, GPIO,    MMC2,        UART2,     NONE,        JTAG,        ETH_TX,   SSP5,        SSP5_TX),
-       MFPR_168(GPIO88,  0x160, GPIO,    MMC2,        UART2,     UART2_TX,    JTAG,        ETH_TX,   ETH_RX,      SSP5),
-       MFPR_168(GPIO89,  0x164, GPIO,    MMC2,        UART2_TX,  UART2,       JTAG,        ETH_TX,   ETH_RX,      SSP5),
-       MFPR_168(GPIO90,  0x168, GPIO,    MMC2,        NONE,      SSP3,        JTAG,        ETH_TX,   ETH_RX,      NONE),
-       MFPR_168(GPIO91,  0x16C, GPIO,    MMC2,        NONE,      SSP3,        SSP4,        ETH_TX,   ETH_RX,      NONE),
-       MFPR_168(GPIO92,  0x170, GPIO,    MMC2,        NONE,      SSP3,        SSP3_TX,     ETH,      NONE,        NONE),
-       MFPR_168(GPIO93,  0x174, GPIO,    MMC2,        NONE,      SSP3_TX,     SSP3,        ETH,      NONE,        NONE),
-       MFPR_168(GPIO94,  0x178, GPIO,    MMC2_CMD,    SSP3,      AC97_SYSCLK, AC97,        ETH,      NONE,        NONE),
-       MFPR_168(GPIO95,  0x17C, GPIO,    MMC2_CLK,    NONE,      NONE,        AC97,        ETH,      NONE,        NONE),
-       MFPR_168(GPIO96,  0x180, GPIO,    PWM,         NONE,      MMC2,        NONE,        ETH_RX,   ETH_TX,      NONE),
-       MFPR_168(GPIO97,  0x184, GPIO,    PWM,         ONE_WIRE,  NONE,        NONE,        ETH_RX,   ETH_TX,      NONE),
-       MFPR_168(GPIO98,  0x188, GPIO,    PWM1,        UART3_TX,  UART3,       NONE,        ETH_RX,   ETH_TX,      NONE),
-       MFPR_168(GPIO99,  0x18C, GPIO,    ONE_WIRE,    UART3,     UART3_TX,    NONE,        ETH_RX,   ETH_TX,      NONE),
-       MFPR_168(GPIO100, 0x190, GPIO,    NONE,        UART3_CTS, UART3,       NONE,        ETH,      NONE,        NONE),
-       MFPR_168(GPIO101, 0x194, GPIO,    NONE,        UART3,     UART3_CTS,   NONE,        ETH,      NONE,        NONE),
-       MFPR_168(GPIO102, 0x198, GPIO,    I2C,         UART3,     SSP4,        NONE,        NONE,     NONE,        NONE),
-       MFPR_168(GPIO103, 0x19C, GPIO,    I2C,         UART3,     SSP4,        SSP2,        ETH,      NONE,        NONE),
-       MFPR_168(GPIO104, 0x1A0, GPIO,    PWM,         UART1,     SSP4,        SSP4_TX,     AC97,     KP_MKOUT,    NONE),
-       MFPR_168(GPIO105, 0x1A4, GPIO,    I2C,         UART1,     SSP4_TX,     SSP4,        AC97,     KP_MKOUT,    NONE),
-       MFPR_168(GPIO106, 0x1A8, GPIO,    I2C,         PWM1,      AC97_SYSCLK, MMC2,        NONE,     KP_MKOUT,    NONE),
-       MFPR_168(GPIO107, 0x1AC, GPIO,    UART1_TX,    UART1,     NONE,        SSP2,        MSP_DAT3, NONE,        KP_MKIN),
-       MFPR_168(GPIO108, 0x1B0, GPIO,    UART1,       UART1_TX,  NONE,        SSP2_TX,     MSP,      NONE,        KP_MKIN),
-       MFPR_168(GPIO109, 0x1B4, GPIO,    UART1_CTS,   UART1,     NONE,        AC97_SYSCLK, MSP,      NONE,        KP_MKIN),
-       MFPR_168(GPIO110, 0x1B8, GPIO,    UART1,       UART1_CTS, NONE,        SMC_RDY,     MSP,      NONE,        KP_MKIN),
-       MFPR_168(GPIO111, 0x1BC, GPIO,    UART1_nRI,   UART1,     SSP3,        SSP2,        MSP,      XD,          KP_MKOUT),
-       MFPR_168(GPIO112, 0x1C0, GPIO,    UART1_DTR,   UART1,     ONE_WIRE,    SSP2,        MSP,      XD,          KP_MKOUT),
-       MFPR_168(GPIO113, 0x1C4, GPIO,    NONE,        NONE,      NONE,        NONE,        NONE,     AC97_SYSCLK, NONE),
-       MFPR_168(GPIO114, 0x1C8, GPIO,    SSP1,        NONE,      NONE,        NONE,        NONE,     AC97,        NONE),
-       MFPR_168(GPIO115, 0x1CC, GPIO,    SSP1,        NONE,      NONE,        NONE,        NONE,     AC97,        NONE),
-       MFPR_168(GPIO116, 0x1D0, GPIO,    SSP1_TX,     SSP1,      NONE,        NONE,        NONE,     AC97,        NONE),
-       MFPR_168(GPIO117, 0x1D4, GPIO,    SSP1,        SSP1_TX,   NONE,        MMC2_CMD,    NONE,     AC97,        NONE),
-       MFPR_168(GPIO118, 0x1D8, GPIO,    SSP2,        NONE,      NONE,        MMC2_CLK,    NONE,     AC97,        KP_MKIN),
-       MFPR_168(GPIO119, 0x1DC, GPIO,    SSP2,        NONE,      NONE,        MMC2,        NONE,     AC97,        KP_MKIN),
-       MFPR_168(GPIO120, 0x1E0, GPIO,    SSP2,        SSP2_TX,   NONE,        MMC2,        NONE,     NONE,        KP_MKIN),
-       MFPR_168(GPIO121, 0x1E4, GPIO,    SSP2_TX,     SSP2,      NONE,        MMC2,        NONE,     NONE,        KP_MKIN),
-       MFPR_168(GPIO122, 0x1E8, GPIO,    AC97_SYSCLK, SSP2,      PWM,         MMC2,        NONE,     NONE,        NONE),
-       MFPR_168(PWR_SCL, 0x1EC, PWRI2C,  NONE,        NONE,      NONE,        NONE,        NONE,     GPIO,        MMC4),
-       MFPR_168(PWR_SDA, 0x1F0, PWRI2C,  NONE,        NONE,      NONE,        NONE,        NONE,     GPIO,        NONE),
-       MFPR_168(TDI,     0x1F4, JTAG,    PWM1,        UART2,     MMC4,        SSP5,        NONE,     XD,          MMC4),
-       MFPR_168(TMS,     0x1F8, JTAG,    PWM,         UART2,     NONE,        SSP5,        NONE,     XD,          MMC4),
-       MFPR_168(TCK,     0x1FC, JTAG,    PWM,         UART2,     UART2_TX,    SSP5,        NONE,     XD,          MMC4),
-       MFPR_168(TDO,     0x200, JTAG,    PWM,         UART2_TX,  UART2,       SSP5_TX,     NONE,     XD,          MMC4),
-       MFPR_168(TRST,    0x204, JTAG,    ONE_WIRE,    SSP2,      SSP3,        AC97_SYSCLK, NONE,     XD,          MMC4),
-       MFPR_168(WAKEUP,  0x208, WAKEUP,  ONE_WIRE,    PWM1,      PWM,         SSP2,        NONE,     GPIO,        MMC4),
-};
-
-static const unsigned p168_jtag_pin1[] = {TDI, TMS, TCK, TDO, TRST};
-static const unsigned p168_wakeup_pin1[] = {WAKEUP};
-static const unsigned p168_ssp1rx_pin1[] = {GPIO114, GPIO115, GPIO116};
-static const unsigned p168_ssp1tx_pin1[] = {GPIO117};
-static const unsigned p168_ssp4rx_pin1[] = {GPIO102, GPIO103, GPIO104};
-static const unsigned p168_ssp4tx_pin1[] = {GPIO105};
-static const unsigned p168_ssp5rx_pin1[] = {GPIO86, GPIO88, GPIO89};
-static const unsigned p168_ssp5tx_pin1[] = {GPIO87};
-static const unsigned p168_i2c_pin1[] = {GPIO105, GPIO106};
-static const unsigned p168_pwri2c_pin1[] = {PWR_SCL, PWR_SDA};
-static const unsigned p168_mmc1_pin1[] = {GPIO40, GPIO41, GPIO43, GPIO46,
-       GPIO49, GPIO51, GPIO52, GPIO53};
-static const unsigned p168_mmc2_data_pin1[] = {GPIO90, GPIO91, GPIO92, GPIO93};
-static const unsigned p168_mmc2_cmd_pin1[] = {GPIO94};
-static const unsigned p168_mmc2_clk_pin1[] = {GPIO95};
-static const unsigned p168_mmc3_data_pin1[] = {GPIO0, GPIO1, GPIO2, GPIO3,
-       GPIO4, GPIO5, GPIO6, GPIO7};
-static const unsigned p168_mmc3_cmd_pin1[] = {GPIO9};
-static const unsigned p168_mmc3_clk_pin1[] = {GPIO8};
-static const unsigned p168_eth_pin1[] = {GPIO92, GPIO93, GPIO100, GPIO101,
-       GPIO103};
-static const unsigned p168_ethtx_pin1[] = {GPIO86, GPIO87, GPIO88, GPIO89,
-       GPIO90, GPIO91};
-static const unsigned p168_ethrx_pin1[] = {GPIO94, GPIO95, GPIO96, GPIO97,
-       GPIO98, GPIO99};
-static const unsigned p168_uart1rx_pin1[] = {GPIO107};
-static const unsigned p168_uart1tx_pin1[] = {GPIO108};
-static const unsigned p168_uart3rx_pin1[] = {GPIO98, GPIO100, GPIO101};
-static const unsigned p168_uart3tx_pin1[] = {GPIO99};
-static const unsigned p168_msp_pin1[] = {GPIO40, GPIO41, GPIO42, GPIO43,
-       GPIO44, GPIO50};
-static const unsigned p168_ccic_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40,
-       GPIO41, GPIO42, GPIO44, GPIO45, GPIO46, GPIO48, GPIO54, GPIO55};
-static const unsigned p168_xd_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40,
-       GPIO41, GPIO42, GPIO44, GPIO45, GPIO47, GPIO48, GPIO49, GPIO50,
-       GPIO51, GPIO52};
-static const unsigned p168_lcd_pin1[] = {GPIO56, GPIO57, GPIO58, GPIO59,
-       GPIO60, GPIO61, GPIO62, GPIO63, GPIO64, GPIO65, GPIO66, GPIO67,
-       GPIO68, GPIO69, GPIO70, GPIO71, GPIO72, GPIO73, GPIO74, GPIO75,
-       GPIO76, GPIO77, GPIO78, GPIO79, GPIO80, GPIO81, GPIO82, GPIO83};
-static const unsigned p168_dfio_pin1[] = {GPIO0, GPIO1, GPIO2, GPIO3,
-       GPIO4, GPIO5, GPIO6, GPIO7, GPIO8, GPIO9, GPIO10, GPIO11, GPIO12,
-       GPIO13, GPIO14, GPIO15};
-static const unsigned p168_nand_pin1[] = {GPIO16, GPIO17, GPIO21, GPIO22,
-       GPIO24, GPIO26};
-static const unsigned p168_smc_pin1[] = {GPIO23, GPIO25, GPIO29, GPIO35,
-       GPIO36};
-static const unsigned p168_smccs0_pin1[] = {GPIO18};
-static const unsigned p168_smccs1_pin1[] = {GPIO34};
-static const unsigned p168_smcrdy_pin1[] = {GPIO28};
-static const unsigned p168_ac97sysclk_pin1[] = {GPIO113};
-static const unsigned p168_ac97_pin1[] = {GPIO114, GPIO115, GPIO117, GPIO118,
-       GPIO119};
-static const unsigned p168_cf_pin1[] = {GPIO19, GPIO20, GPIO23, GPIO25,
-       GPIO28, GPIO29, GPIO30, GPIO31, GPIO32, GPIO33, GPIO34, GPIO35,
-       GPIO36};
-static const unsigned p168_kpmkin_pin1[] = {GPIO109, GPIO110, GPIO121};
-static const unsigned p168_kpmkout_pin1[] = {GPIO111, GPIO112};
-static const unsigned p168_gpio86_pin1[] = {WAKEUP};
-static const unsigned p168_gpio86_pin2[] = {GPIO86};
-static const unsigned p168_gpio87_pin1[] = {GPIO87};
-static const unsigned p168_gpio87_pin2[] = {PWR_SDA};
-static const unsigned p168_gpio88_pin1[] = {GPIO88};
-static const unsigned p168_gpio88_pin2[] = {PWR_SCL};
-
-static struct pxa3xx_pin_group pxa168_grps[] = {
-       GRP_168("uart1rx-1", UART1, p168_uart1rx_pin1),
-       GRP_168("uart1tx-1", UART1_TX, p168_uart1tx_pin1),
-       GRP_168("uart3rx-1", UART3, p168_uart3rx_pin1),
-       GRP_168("uart3tx-1", UART3_TX, p168_uart3tx_pin1),
-       GRP_168("ssp1rx-1", SSP1, p168_ssp1rx_pin1),
-       GRP_168("ssp1tx-1", SSP1_TX, p168_ssp1tx_pin1),
-       GRP_168("ssp4rx-1", SSP4, p168_ssp4rx_pin1),
-       GRP_168("ssp4tx-1", SSP4_TX, p168_ssp4tx_pin1),
-       GRP_168("ssp5rx-1", SSP5, p168_ssp5rx_pin1),
-       GRP_168("ssp5tx-1", SSP5_TX, p168_ssp5tx_pin1),
-       GRP_168("jtag", JTAG, p168_jtag_pin1),
-       GRP_168("wakeup", WAKEUP, p168_wakeup_pin1),
-       GRP_168("i2c", I2C, p168_i2c_pin1),
-       GRP_168("pwri2c", PWRI2C, p168_pwri2c_pin1),
-       GRP_168("mmc1 8p1", MMC1, p168_mmc1_pin1),
-       GRP_168("mmc2 4p1", MMC2, p168_mmc2_data_pin1),
-       GRP_168("mmc2 cmd1", MMC2_CMD, p168_mmc2_cmd_pin1),
-       GRP_168("mmc2 clk1", MMC2_CLK, p168_mmc2_clk_pin1),
-       GRP_168("mmc3 8p1", MMC3, p168_mmc3_data_pin1),
-       GRP_168("mmc3 cmd1", MMC3_CMD, p168_mmc3_cmd_pin1),
-       GRP_168("mmc3 clk1", MMC3_CLK, p168_mmc3_clk_pin1),
-       GRP_168("eth", ETH, p168_eth_pin1),
-       GRP_168("eth rx", ETH_RX, p168_ethrx_pin1),
-       GRP_168("eth tx", ETH_TX, p168_ethtx_pin1),
-       GRP_168("msp", MSP, p168_msp_pin1),
-       GRP_168("ccic", CCIC, p168_ccic_pin1),
-       GRP_168("xd", XD, p168_xd_pin1),
-       GRP_168("lcd", LCD, p168_lcd_pin1),
-       GRP_168("dfio", DFIO, p168_dfio_pin1),
-       GRP_168("nand", NAND, p168_nand_pin1),
-       GRP_168("smc", SMC, p168_smc_pin1),
-       GRP_168("smc cs0", SMC_CS0, p168_smccs0_pin1),
-       GRP_168("smc cs1", SMC_CS1, p168_smccs1_pin1),
-       GRP_168("smc rdy", SMC_RDY, p168_smcrdy_pin1),
-       GRP_168("ac97 sysclk", AC97_SYSCLK, p168_ac97sysclk_pin1),
-       GRP_168("ac97", AC97, p168_ac97_pin1),
-       GRP_168("cf", CF, p168_cf_pin1),
-       GRP_168("kp mkin 3p1", KP_MKIN, p168_kpmkin_pin1),
-       GRP_168("kp mkout 2p1", KP_MKOUT, p168_kpmkout_pin1),
-       GRP_168("gpio86-1", GPIO, p168_gpio86_pin1),
-       GRP_168("gpio86-2", GPIO, p168_gpio86_pin2),
-       GRP_168("gpio87-1", GPIO, p168_gpio87_pin1),
-       GRP_168("gpio87-2", GPIO, p168_gpio87_pin2),
-       GRP_168("gpio88-1", GPIO, p168_gpio88_pin1),
-       GRP_168("gpio88-2", GPIO, p168_gpio88_pin2),
-};
-
-static const char * const p168_uart1rx_grps[] = {"uart1rx-1"};
-static const char * const p168_uart1tx_grps[] = {"uart1tx-1"};
-static const char * const p168_uart3rx_grps[] = {"uart3rx-1"};
-static const char * const p168_uart3tx_grps[] = {"uart3tx-1"};
-static const char * const p168_ssp1rx_grps[] = {"ssp1rx-1"};
-static const char * const p168_ssp1tx_grps[] = {"ssp1tx-1"};
-static const char * const p168_ssp4rx_grps[] = {"ssp4rx-1"};
-static const char * const p168_ssp4tx_grps[] = {"ssp4tx-1"};
-static const char * const p168_ssp5rx_grps[] = {"ssp5rx-1"};
-static const char * const p168_ssp5tx_grps[] = {"ssp5tx-1"};
-static const char * const p168_i2c_grps[] = {"i2c"};
-static const char * const p168_pwri2c_grps[] = {"pwri2c"};
-static const char * const p168_mmc1_grps[] = {"mmc1 8p1"};
-static const char * const p168_mmc2_data_grps[] = {"mmc2 4p1"};
-static const char * const p168_mmc2_cmd_grps[] = {"mmc2 cmd1"};
-static const char * const p168_mmc2_clk_grps[] = {"mmc2 clk1"};
-static const char * const p168_mmc3_data_grps[] = {"mmc3 8p1"};
-static const char * const p168_mmc3_cmd_grps[] = {"mmc3 cmd1"};
-static const char * const p168_mmc3_clk_grps[] = {"mmc3 clk1"};
-static const char * const p168_eth_grps[] = {"eth"};
-static const char * const p168_ethrx_grps[] = {"eth rx"};
-static const char * const p168_ethtx_grps[] = {"eth tx"};
-static const char * const p168_msp_grps[] = {"msp"};
-static const char * const p168_ccic_grps[] = {"ccic"};
-static const char * const p168_xd_grps[] = {"xd"};
-static const char * const p168_lcd_grps[] = {"lcd"};
-static const char * const p168_dfio_grps[] = {"dfio"};
-static const char * const p168_nand_grps[] = {"nand"};
-static const char * const p168_smc_grps[] = {"smc"};
-static const char * const p168_smccs0_grps[] = {"smc cs0"};
-static const char * const p168_smccs1_grps[] = {"smc cs1"};
-static const char * const p168_smcrdy_grps[] = {"smc rdy"};
-static const char * const p168_ac97sysclk_grps[] = {"ac97 sysclk"};
-static const char * const p168_ac97_grps[] = {"ac97"};
-static const char * const p168_cf_grps[] = {"cf"};
-static const char * const p168_kpmkin_grps[] = {"kp mkin 3p1"};
-static const char * const p168_kpmkout_grps[] = {"kp mkout 2p1"};
-static const char * const p168_gpio86_grps[] = {"gpio86-1", "gpio86-2"};
-static const char * const p168_gpio87_grps[] = {"gpio87-1", "gpio87-2"};
-static const char * const p168_gpio88_grps[] = {"gpio88-1", "gpio88-2"};
-
-static struct pxa3xx_pmx_func pxa168_funcs[] = {
-       {"uart1 rx",    ARRAY_AND_SIZE(p168_uart1rx_grps)},
-       {"uart1 tx",    ARRAY_AND_SIZE(p168_uart1tx_grps)},
-       {"uart3 rx",    ARRAY_AND_SIZE(p168_uart3rx_grps)},
-       {"uart3 tx",    ARRAY_AND_SIZE(p168_uart3tx_grps)},
-       {"ssp1 rx",     ARRAY_AND_SIZE(p168_ssp1rx_grps)},
-       {"ssp1 tx",     ARRAY_AND_SIZE(p168_ssp1tx_grps)},
-       {"ssp4 rx",     ARRAY_AND_SIZE(p168_ssp4rx_grps)},
-       {"ssp4 tx",     ARRAY_AND_SIZE(p168_ssp4tx_grps)},
-       {"ssp5 rx",     ARRAY_AND_SIZE(p168_ssp5rx_grps)},
-       {"ssp5 tx",     ARRAY_AND_SIZE(p168_ssp5tx_grps)},
-       {"i2c",         ARRAY_AND_SIZE(p168_i2c_grps)},
-       {"pwri2c",      ARRAY_AND_SIZE(p168_pwri2c_grps)},
-       {"mmc1",        ARRAY_AND_SIZE(p168_mmc1_grps)},
-       {"mmc2",        ARRAY_AND_SIZE(p168_mmc2_data_grps)},
-       {"mmc2 cmd",    ARRAY_AND_SIZE(p168_mmc2_cmd_grps)},
-       {"mmc2 clk",    ARRAY_AND_SIZE(p168_mmc2_clk_grps)},
-       {"mmc3",        ARRAY_AND_SIZE(p168_mmc3_data_grps)},
-       {"mmc3 cmd",    ARRAY_AND_SIZE(p168_mmc3_cmd_grps)},
-       {"mmc3 clk",    ARRAY_AND_SIZE(p168_mmc3_clk_grps)},
-       {"eth",         ARRAY_AND_SIZE(p168_eth_grps)},
-       {"eth rx",      ARRAY_AND_SIZE(p168_ethrx_grps)},
-       {"eth tx",      ARRAY_AND_SIZE(p168_ethtx_grps)},
-       {"msp",         ARRAY_AND_SIZE(p168_msp_grps)},
-       {"ccic",        ARRAY_AND_SIZE(p168_ccic_grps)},
-       {"xd",          ARRAY_AND_SIZE(p168_xd_grps)},
-       {"lcd",         ARRAY_AND_SIZE(p168_lcd_grps)},
-       {"dfio",        ARRAY_AND_SIZE(p168_dfio_grps)},
-       {"nand",        ARRAY_AND_SIZE(p168_nand_grps)},
-       {"smc",         ARRAY_AND_SIZE(p168_smc_grps)},
-       {"smc cs0",     ARRAY_AND_SIZE(p168_smccs0_grps)},
-       {"smc cs1",     ARRAY_AND_SIZE(p168_smccs1_grps)},
-       {"smc rdy",     ARRAY_AND_SIZE(p168_smcrdy_grps)},
-       {"ac97",        ARRAY_AND_SIZE(p168_ac97_grps)},
-       {"ac97 sysclk", ARRAY_AND_SIZE(p168_ac97sysclk_grps)},
-       {"cf",          ARRAY_AND_SIZE(p168_cf_grps)},
-       {"kpmkin",      ARRAY_AND_SIZE(p168_kpmkin_grps)},
-       {"kpmkout",     ARRAY_AND_SIZE(p168_kpmkout_grps)},
-       {"gpio86",      ARRAY_AND_SIZE(p168_gpio86_grps)},
-       {"gpio87",      ARRAY_AND_SIZE(p168_gpio87_grps)},
-       {"gpio88",      ARRAY_AND_SIZE(p168_gpio88_grps)},
-};
-
-static struct pinctrl_desc pxa168_pctrl_desc = {
-       .name           = "pxa168-pinctrl",
-       .owner          = THIS_MODULE,
-};
-
-static struct pxa3xx_pinmux_info pxa168_info = {
-       .mfp            = pxa168_mfp,
-       .num_mfp        = ARRAY_SIZE(pxa168_mfp),
-       .grps           = pxa168_grps,
-       .num_grps       = ARRAY_SIZE(pxa168_grps),
-       .funcs          = pxa168_funcs,
-       .num_funcs      = ARRAY_SIZE(pxa168_funcs),
-       .num_gpio       = 128,
-       .desc           = &pxa168_pctrl_desc,
-       .pads           = pxa168_pads,
-       .num_pads       = ARRAY_SIZE(pxa168_pads),
-
-       .cputype        = PINCTRL_PXA168,
-       .ds_mask        = PXA168_DS_MASK,
-       .ds_shift       = PXA168_DS_SHIFT,
-};
-
-static int pxa168_pinmux_probe(struct platform_device *pdev)
-{
-       return pxa3xx_pinctrl_register(pdev, &pxa168_info);
-}
-
-static int pxa168_pinmux_remove(struct platform_device *pdev)
-{
-       return pxa3xx_pinctrl_unregister(pdev);
-}
-
-static struct platform_driver pxa168_pinmux_driver = {
-       .driver = {
-               .name   = "pxa168-pinmux",
-               .owner  = THIS_MODULE,
-       },
-       .probe  = pxa168_pinmux_probe,
-       .remove = pxa168_pinmux_remove,
-};
-
-static int __init pxa168_pinmux_init(void)
-{
-       return platform_driver_register(&pxa168_pinmux_driver);
-}
-core_initcall_sync(pxa168_pinmux_init);
-
-static void __exit pxa168_pinmux_exit(void)
-{
-       platform_driver_unregister(&pxa168_pinmux_driver);
-}
-module_exit(pxa168_pinmux_exit);
-
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_DESCRIPTION("PXA3xx pin control driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c
deleted file mode 100644 (file)
index 1f49bb0..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- *  linux/drivers/pinctrl/pinctrl-pxa3xx.c
- *
- *  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
- *  publishhed by the Free Software Foundation.
- *
- *  Copyright (C) 2011, Marvell Technology Group Ltd.
- *
- *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- */
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include "pinctrl-pxa3xx.h"
-
-static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = {
-       .name           = "PXA3xx GPIO",
-       .id             = 0,
-       .base           = 0,
-       .pin_base       = 0,
-};
-
-static int pxa3xx_get_groups_count(struct pinctrl_dev *pctrldev)
-{
-       struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-
-       return info->num_grps;
-}
-
-static const char *pxa3xx_get_group_name(struct pinctrl_dev *pctrldev,
-                                        unsigned selector)
-{
-       struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-
-       return info->grps[selector].name;
-}
-
-static int pxa3xx_get_group_pins(struct pinctrl_dev *pctrldev,
-                                unsigned selector,
-                                const unsigned **pins,
-                                unsigned *num_pins)
-{
-       struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-
-       *pins = info->grps[selector].pins;
-       *num_pins = info->grps[selector].npins;
-       return 0;
-}
-
-static struct pinctrl_ops pxa3xx_pctrl_ops = {
-       .get_groups_count = pxa3xx_get_groups_count,
-       .get_group_name = pxa3xx_get_group_name,
-       .get_group_pins = pxa3xx_get_group_pins,
-};
-
-static int pxa3xx_pmx_get_funcs_count(struct pinctrl_dev *pctrldev)
-{
-       struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-
-       return info->num_funcs;
-}
-
-static const char *pxa3xx_pmx_get_func_name(struct pinctrl_dev *pctrldev,
-                                           unsigned func)
-{
-       struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-       return info->funcs[func].name;
-}
-
-static int pxa3xx_pmx_get_groups(struct pinctrl_dev *pctrldev, unsigned func,
-                                const char * const **groups,
-                                unsigned * const num_groups)
-{
-       struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-       *groups = info->funcs[func].groups;
-       *num_groups = info->funcs[func].num_groups;
-       return 0;
-}
-
-/* Return function number. If failure, return negative value. */
-static int match_mux(struct pxa3xx_mfp_pin *mfp, unsigned mux)
-{
-       int i;
-       for (i = 0; i < PXA3xx_MAX_MUX; i++) {
-               if (mfp->func[i] == mux)
-                       break;
-       }
-       if (i >= PXA3xx_MAX_MUX)
-               return -EINVAL;
-       return i;
-}
-
-/* check whether current pin configuration is valid. Negative for failure */
-static int match_group_mux(struct pxa3xx_pin_group *grp,
-                          struct pxa3xx_pinmux_info *info,
-                          unsigned mux)
-{
-       int i, pin, ret = 0;
-       for (i = 0; i < grp->npins; i++) {
-               pin = grp->pins[i];
-               ret = match_mux(&info->mfp[pin], mux);
-               if (ret < 0) {
-                       dev_err(info->dev, "Can't find mux %d on pin%d\n",
-                               mux, pin);
-                       break;
-               }
-       }
-       return ret;
-}
-
-static int pxa3xx_pmx_enable(struct pinctrl_dev *pctrldev, unsigned func,
-                            unsigned group)
-{
-       struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-       struct pxa3xx_pin_group *pin_grp = &info->grps[group];
-       unsigned int data;
-       int i, mfpr, pin, pin_func;
-
-       if (!pin_grp->npins ||
-               (match_group_mux(pin_grp, info, pin_grp->mux) < 0)) {
-               dev_err(info->dev, "Failed to set the pin group: %d\n", group);
-               return -EINVAL;
-       }
-       for (i = 0; i < pin_grp->npins; i++) {
-               pin = pin_grp->pins[i];
-               pin_func = match_mux(&info->mfp[pin], pin_grp->mux);
-               mfpr = info->mfp[pin].mfpr;
-               data = readl_relaxed(info->virt_base + mfpr);
-               data &= ~MFPR_FUNC_MASK;
-               data |= pin_func;
-               writel_relaxed(data, info->virt_base + mfpr);
-       }
-       return 0;
-}
-
-static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev,
-                                  struct pinctrl_gpio_range *range,
-                                  unsigned pin)
-{
-       struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-       unsigned int data;
-       int pin_func, mfpr;
-
-       pin_func = match_mux(&info->mfp[pin], PXA3xx_MUX_GPIO);
-       if (pin_func < 0) {
-               dev_err(info->dev, "No GPIO function on pin%d (%s)\n",
-                       pin, info->pads[pin].name);
-               return -EINVAL;
-       }
-       mfpr = info->mfp[pin].mfpr;
-       /* write gpio function into mfpr register */
-       data = readl_relaxed(info->virt_base + mfpr) & ~MFPR_FUNC_MASK;
-       data |= pin_func;
-       writel_relaxed(data, info->virt_base + mfpr);
-       return 0;
-}
-
-static struct pinmux_ops pxa3xx_pmx_ops = {
-       .get_functions_count    = pxa3xx_pmx_get_funcs_count,
-       .get_function_name      = pxa3xx_pmx_get_func_name,
-       .get_function_groups    = pxa3xx_pmx_get_groups,
-       .enable                 = pxa3xx_pmx_enable,
-       .gpio_request_enable    = pxa3xx_pmx_request_gpio,
-};
-
-int pxa3xx_pinctrl_register(struct platform_device *pdev,
-                           struct pxa3xx_pinmux_info *info)
-{
-       struct pinctrl_desc *desc;
-       struct resource *res;
-
-       if (!info || !info->cputype)
-               return -EINVAL;
-       desc = info->desc;
-       desc->pins = info->pads;
-       desc->npins = info->num_pads;
-       desc->pctlops = &pxa3xx_pctrl_ops;
-       desc->pmxops = &pxa3xx_pmx_ops;
-       info->dev = &pdev->dev;
-       pxa3xx_pinctrl_gpio_range.npins = info->num_gpio;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENOENT;
-       info->virt_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(info->virt_base))
-               return PTR_ERR(info->virt_base);
-       info->pctrl = pinctrl_register(desc, &pdev->dev, info);
-       if (!info->pctrl) {
-               dev_err(&pdev->dev, "failed to register PXA pinmux driver\n");
-               return -EINVAL;
-       }
-       pinctrl_add_gpio_range(info->pctrl, &pxa3xx_pinctrl_gpio_range);
-       platform_set_drvdata(pdev, info);
-       return 0;
-}
-
-int pxa3xx_pinctrl_unregister(struct platform_device *pdev)
-{
-       struct pxa3xx_pinmux_info *info = platform_get_drvdata(pdev);
-
-       pinctrl_unregister(info->pctrl);
-       platform_set_drvdata(pdev, NULL);
-       return 0;
-}
-
-static int __init pxa3xx_pinctrl_init(void)
-{
-       pr_info("pxa3xx-pinctrl: PXA3xx pinctrl driver initializing\n");
-       return 0;
-}
-core_initcall_sync(pxa3xx_pinctrl_init);
-
-static void __exit pxa3xx_pinctrl_exit(void)
-{
-}
-module_exit(pxa3xx_pinctrl_exit);
-
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_DESCRIPTION("PXA3xx pin control driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-pxa3xx.h b/drivers/pinctrl/pinctrl-pxa3xx.h
deleted file mode 100644 (file)
index 92fad08..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- *  linux/drivers/pinctrl/pinctrl-pxa3xx.h
- *
- *  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
- *  publishhed by the Free Software Foundation.
- *
- *  Copyright (C) 2011, Marvell Technology Group Ltd.
- *
- *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- */
-
-#ifndef __PINCTRL_PXA3XX_H
-
-#include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinmux.h>
-
-#define ARRAY_AND_SIZE(x)      (x), ARRAY_SIZE(x)
-
-#define PXA3xx_MUX_GPIO                0
-
-#define PXA3xx_MAX_MUX         8
-#define MFPR_FUNC_MASK         0x7
-
-enum pxa_cpu_type {
-       PINCTRL_INVALID = 0,
-       PINCTRL_PXA300,
-       PINCTRL_PXA310,
-       PINCTRL_PXA320,
-       PINCTRL_PXA168,
-       PINCTRL_PXA910,
-       PINCTRL_PXA930,
-       PINCTRL_PXA955,
-       PINCTRL_MMP2,
-       PINCTRL_MAX,
-};
-
-struct pxa3xx_mfp_pin {
-       const char *name;
-       const unsigned int pin;
-       const unsigned int mfpr;        /* register offset */
-       const unsigned short func[8];
-};
-
-struct pxa3xx_pin_group {
-       const char *name;
-       const unsigned mux;
-       const unsigned *pins;
-       const unsigned npins;
-};
-
-struct pxa3xx_pmx_func {
-       const char *name;
-       const char * const * groups;
-       const unsigned num_groups;
-};
-
-struct pxa3xx_pinmux_info {
-       struct device *dev;
-       struct pinctrl_dev *pctrl;
-       enum pxa_cpu_type cputype;
-       void __iomem *virt_base;
-
-       struct pxa3xx_mfp_pin *mfp;
-       unsigned int num_mfp;
-       struct pxa3xx_pin_group *grps;
-       unsigned int num_grps;
-       struct pxa3xx_pmx_func *funcs;
-       unsigned int num_funcs;
-       unsigned int num_gpio;
-       struct pinctrl_desc *desc;
-       struct pinctrl_pin_desc *pads;
-       unsigned int num_pads;
-
-       unsigned ds_mask;       /* drive strength mask */
-       unsigned ds_shift;      /* drive strength shift */
-       unsigned slp_mask;      /* sleep mask */
-       unsigned slp_input_low;
-       unsigned slp_input_high;
-       unsigned slp_output_low;
-       unsigned slp_output_high;
-       unsigned slp_float;
-};
-
-enum pxa3xx_pin_list {
-       GPIO0 = 0,
-       GPIO1,
-       GPIO2,
-       GPIO3,
-       GPIO4,
-       GPIO5,
-       GPIO6,
-       GPIO7,
-       GPIO8,
-       GPIO9,
-       GPIO10, /* 10 */
-       GPIO11,
-       GPIO12,
-       GPIO13,
-       GPIO14,
-       GPIO15,
-       GPIO16,
-       GPIO17,
-       GPIO18,
-       GPIO19,
-       GPIO20, /* 20 */
-       GPIO21,
-       GPIO22,
-       GPIO23,
-       GPIO24,
-       GPIO25,
-       GPIO26,
-       GPIO27,
-       GPIO28,
-       GPIO29,
-       GPIO30, /* 30 */
-       GPIO31,
-       GPIO32,
-       GPIO33,
-       GPIO34,
-       GPIO35,
-       GPIO36,
-       GPIO37,
-       GPIO38,
-       GPIO39,
-       GPIO40, /* 40 */
-       GPIO41,
-       GPIO42,
-       GPIO43,
-       GPIO44,
-       GPIO45,
-       GPIO46,
-       GPIO47,
-       GPIO48,
-       GPIO49,
-       GPIO50, /* 50 */
-       GPIO51,
-       GPIO52,
-       GPIO53,
-       GPIO54,
-       GPIO55,
-       GPIO56,
-       GPIO57,
-       GPIO58,
-       GPIO59,
-       GPIO60, /* 60 */
-       GPIO61,
-       GPIO62,
-       GPIO63,
-       GPIO64,
-       GPIO65,
-       GPIO66,
-       GPIO67,
-       GPIO68,
-       GPIO69,
-       GPIO70, /* 70 */
-       GPIO71,
-       GPIO72,
-       GPIO73,
-       GPIO74,
-       GPIO75,
-       GPIO76,
-       GPIO77,
-       GPIO78,
-       GPIO79,
-       GPIO80, /* 80 */
-       GPIO81,
-       GPIO82,
-       GPIO83,
-       GPIO84,
-       GPIO85,
-       GPIO86,
-       GPIO87,
-       GPIO88,
-       GPIO89,
-       GPIO90, /* 90 */
-       GPIO91,
-       GPIO92,
-       GPIO93,
-       GPIO94,
-       GPIO95,
-       GPIO96,
-       GPIO97,
-       GPIO98,
-       GPIO99,
-       GPIO100, /* 100 */
-       GPIO101,
-       GPIO102,
-       GPIO103,
-       GPIO104,
-       GPIO105,
-       GPIO106,
-       GPIO107,
-       GPIO108,
-       GPIO109,
-       GPIO110, /* 110 */
-       GPIO111,
-       GPIO112,
-       GPIO113,
-       GPIO114,
-       GPIO115,
-       GPIO116,
-       GPIO117,
-       GPIO118,
-       GPIO119,
-       GPIO120, /* 120 */
-       GPIO121,
-       GPIO122,
-       GPIO123,
-       GPIO124,
-       GPIO125,
-       GPIO126,
-       GPIO127,
-       GPIO128,
-       GPIO129,
-       GPIO130, /* 130 */
-       GPIO131,
-       GPIO132,
-       GPIO133,
-       GPIO134,
-       GPIO135,
-       GPIO136,
-       GPIO137,
-       GPIO138,
-       GPIO139,
-       GPIO140, /* 140 */
-       GPIO141,
-       GPIO142,
-       GPIO143,
-       GPIO144,
-       GPIO145,
-       GPIO146,
-       GPIO147,
-       GPIO148,
-       GPIO149,
-       GPIO150, /* 150 */
-       GPIO151,
-       GPIO152,
-       GPIO153,
-       GPIO154,
-       GPIO155,
-       GPIO156,
-       GPIO157,
-       GPIO158,
-       GPIO159,
-       GPIO160, /* 160 */
-       GPIO161,
-       GPIO162,
-       GPIO163,
-       GPIO164,
-       GPIO165,
-       GPIO166,
-       GPIO167,
-       GPIO168,
-       GPIO169,
-};
-
-extern int pxa3xx_pinctrl_register(struct platform_device *pdev,
-                                  struct pxa3xx_pinmux_info *info);
-extern int pxa3xx_pinctrl_unregister(struct platform_device *pdev);
-#endif /* __PINCTRL_PXA3XX_H */
diff --git a/drivers/pinctrl/pinctrl-pxa910.c b/drivers/pinctrl/pinctrl-pxa910.c
deleted file mode 100644 (file)
index a2f917b..0000000
+++ /dev/null
@@ -1,1007 +0,0 @@
-/*
- *  linux/drivers/pinctrl/pinmux-pxa910.c
- *
- *  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
- *  publishhed by the Free Software Foundation.
- *
- *  Copyright (C) 2011, Marvell Technology Group Ltd.
- *
- *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include "pinctrl-pxa3xx.h"
-
-#define PXA910_DS_MASK         0x1800
-#define PXA910_DS_SHIFT                11
-#define PXA910_SLEEP_MASK      0x38
-#define PXA910_SLEEP_SELECT    (1 << 9)
-#define PXA910_SLEEP_DATA      (1 << 8)
-#define PXA910_SLEEP_DIR       (1 << 7)
-
-#define MFPR_910(a, r, f0, f1, f2, f3, f4, f5, f6, f7)         \
-       {                                                       \
-               .name = #a,                                     \
-               .pin = a,                                       \
-               .mfpr = r,                                      \
-               .func = {                                       \
-                       PXA910_MUX_##f0,                        \
-                       PXA910_MUX_##f1,                        \
-                       PXA910_MUX_##f2,                        \
-                       PXA910_MUX_##f3,                        \
-                       PXA910_MUX_##f4,                        \
-                       PXA910_MUX_##f5,                        \
-                       PXA910_MUX_##f6,                        \
-                       PXA910_MUX_##f7,                        \
-               },                                              \
-       }
-
-#define GRP_910(a, m, p)               \
-       { .name = a, .mux = PXA910_MUX_##m, .pins = p, .npins = ARRAY_SIZE(p), }
-
-/* 170 pins */
-enum pxa910_pin_list {
-       /* 0~127: GPIO0~GPIO127 */
-       ND_IO15 = 128,
-       ND_IO14,
-       ND_IO13, /* 130 */
-       ND_IO12,
-       ND_IO11,
-       ND_IO10,
-       ND_IO9,
-       ND_IO8,
-       ND_IO7,
-       ND_IO6,
-       ND_IO5,
-       ND_IO4,
-       ND_IO3, /* 140 */
-       ND_IO2,
-       ND_IO1,
-       ND_IO0,
-       ND_NCS0,
-       ND_NCS1,
-       SM_NCS0,
-       SM_NCS1,
-       ND_NWE,
-       ND_NRE,
-       ND_CLE, /* 150 */
-       ND_ALE,
-       SM_SCLK,
-       ND_RDY0,
-       SM_ADV,
-       ND_RDY1,
-       SM_ADVMUX,
-       SM_RDY,
-       MMC1_DAT7,
-       MMC1_DAT6,
-       MMC1_DAT5, /* 160 */
-       MMC1_DAT4,
-       MMC1_DAT3,
-       MMC1_DAT2,
-       MMC1_DAT1,
-       MMC1_DAT0,
-       MMC1_CMD,
-       MMC1_CLK,
-       MMC1_CD,
-       VCXO_OUT,
-};
-
-enum pxa910_mux {
-       /* PXA3xx_MUX_GPIO = 0 (predefined in pinctrl-pxa3xx.h) */
-       PXA910_MUX_GPIO = 0,
-       PXA910_MUX_NAND,
-       PXA910_MUX_USIM2,
-       PXA910_MUX_EXT_DMA,
-       PXA910_MUX_EXT_INT,
-       PXA910_MUX_MMC1,
-       PXA910_MUX_MMC2,
-       PXA910_MUX_MMC3,
-       PXA910_MUX_SM_INT,
-       PXA910_MUX_PRI_JTAG,
-       PXA910_MUX_SEC1_JTAG,
-       PXA910_MUX_SEC2_JTAG,
-       PXA910_MUX_RESET,       /* SLAVE RESET OUT */
-       PXA910_MUX_CLK_REQ,
-       PXA910_MUX_VCXO_REQ,
-       PXA910_MUX_VCXO_OUT,
-       PXA910_MUX_VCXO_REQ2,
-       PXA910_MUX_VCXO_OUT2,
-       PXA910_MUX_SPI,
-       PXA910_MUX_SPI2,
-       PXA910_MUX_GSSP,
-       PXA910_MUX_SSP0,
-       PXA910_MUX_SSP1,
-       PXA910_MUX_SSP2,
-       PXA910_MUX_DSSP2,
-       PXA910_MUX_DSSP3,
-       PXA910_MUX_UART0,
-       PXA910_MUX_UART1,
-       PXA910_MUX_UART2,
-       PXA910_MUX_TWSI,
-       PXA910_MUX_CCIC,
-       PXA910_MUX_PWM0,
-       PXA910_MUX_PWM1,
-       PXA910_MUX_PWM2,
-       PXA910_MUX_PWM3,
-       PXA910_MUX_HSL,
-       PXA910_MUX_ONE_WIRE,
-       PXA910_MUX_LCD,
-       PXA910_MUX_DAC_ST23,
-       PXA910_MUX_ULPI,
-       PXA910_MUX_TB,
-       PXA910_MUX_KP_MK,
-       PXA910_MUX_KP_DK,
-       PXA910_MUX_TCU_GPOA,
-       PXA910_MUX_TCU_GPOB,
-       PXA910_MUX_ROT,
-       PXA910_MUX_TDS,
-       PXA910_MUX_32K_CLK, /* 32KHz CLK OUT */
-       PXA910_MUX_MN_CLK, /* MN CLK OUT */
-       PXA910_MUX_SMC,
-       PXA910_MUX_SM_ADDR18,
-       PXA910_MUX_SM_ADDR19,
-       PXA910_MUX_SM_ADDR20,
-       PXA910_MUX_NONE = 0xffff,
-};
-
-
-static struct pinctrl_pin_desc pxa910_pads[] = {
-       PINCTRL_PIN(GPIO0, "GPIO0"),
-       PINCTRL_PIN(GPIO1, "GPIO1"),
-       PINCTRL_PIN(GPIO2, "GPIO2"),
-       PINCTRL_PIN(GPIO3, "GPIO3"),
-       PINCTRL_PIN(GPIO4, "GPIO4"),
-       PINCTRL_PIN(GPIO5, "GPIO5"),
-       PINCTRL_PIN(GPIO6, "GPIO6"),
-       PINCTRL_PIN(GPIO7, "GPIO7"),
-       PINCTRL_PIN(GPIO8, "GPIO8"),
-       PINCTRL_PIN(GPIO9, "GPIO9"),
-       PINCTRL_PIN(GPIO10, "GPIO10"),
-       PINCTRL_PIN(GPIO11, "GPIO11"),
-       PINCTRL_PIN(GPIO12, "GPIO12"),
-       PINCTRL_PIN(GPIO13, "GPIO13"),
-       PINCTRL_PIN(GPIO14, "GPIO14"),
-       PINCTRL_PIN(GPIO15, "GPIO15"),
-       PINCTRL_PIN(GPIO16, "GPIO16"),
-       PINCTRL_PIN(GPIO17, "GPIO17"),
-       PINCTRL_PIN(GPIO18, "GPIO18"),
-       PINCTRL_PIN(GPIO19, "GPIO19"),
-       PINCTRL_PIN(GPIO20, "GPIO20"),
-       PINCTRL_PIN(GPIO21, "GPIO21"),
-       PINCTRL_PIN(GPIO22, "GPIO22"),
-       PINCTRL_PIN(GPIO23, "GPIO23"),
-       PINCTRL_PIN(GPIO24, "GPIO24"),
-       PINCTRL_PIN(GPIO25, "GPIO25"),
-       PINCTRL_PIN(GPIO26, "GPIO26"),
-       PINCTRL_PIN(GPIO27, "GPIO27"),
-       PINCTRL_PIN(GPIO28, "GPIO28"),
-       PINCTRL_PIN(GPIO29, "GPIO29"),
-       PINCTRL_PIN(GPIO30, "GPIO30"),
-       PINCTRL_PIN(GPIO31, "GPIO31"),
-       PINCTRL_PIN(GPIO32, "GPIO32"),
-       PINCTRL_PIN(GPIO33, "GPIO33"),
-       PINCTRL_PIN(GPIO34, "GPIO34"),
-       PINCTRL_PIN(GPIO35, "GPIO35"),
-       PINCTRL_PIN(GPIO36, "GPIO36"),
-       PINCTRL_PIN(GPIO37, "GPIO37"),
-       PINCTRL_PIN(GPIO38, "GPIO38"),
-       PINCTRL_PIN(GPIO39, "GPIO39"),
-       PINCTRL_PIN(GPIO40, "GPIO40"),
-       PINCTRL_PIN(GPIO41, "GPIO41"),
-       PINCTRL_PIN(GPIO42, "GPIO42"),
-       PINCTRL_PIN(GPIO43, "GPIO43"),
-       PINCTRL_PIN(GPIO44, "GPIO44"),
-       PINCTRL_PIN(GPIO45, "GPIO45"),
-       PINCTRL_PIN(GPIO46, "GPIO46"),
-       PINCTRL_PIN(GPIO47, "GPIO47"),
-       PINCTRL_PIN(GPIO48, "GPIO48"),
-       PINCTRL_PIN(GPIO49, "GPIO49"),
-       PINCTRL_PIN(GPIO50, "GPIO50"),
-       PINCTRL_PIN(GPIO51, "GPIO51"),
-       PINCTRL_PIN(GPIO52, "GPIO52"),
-       PINCTRL_PIN(GPIO53, "GPIO53"),
-       PINCTRL_PIN(GPIO54, "GPIO54"),
-       PINCTRL_PIN(GPIO55, "GPIO55"),
-       PINCTRL_PIN(GPIO56, "GPIO56"),
-       PINCTRL_PIN(GPIO57, "GPIO57"),
-       PINCTRL_PIN(GPIO58, "GPIO58"),
-       PINCTRL_PIN(GPIO59, "GPIO59"),
-       PINCTRL_PIN(GPIO60, "GPIO60"),
-       PINCTRL_PIN(GPIO61, "GPIO61"),
-       PINCTRL_PIN(GPIO62, "GPIO62"),
-       PINCTRL_PIN(GPIO63, "GPIO63"),
-       PINCTRL_PIN(GPIO64, "GPIO64"),
-       PINCTRL_PIN(GPIO65, "GPIO65"),
-       PINCTRL_PIN(GPIO66, "GPIO66"),
-       PINCTRL_PIN(GPIO67, "GPIO67"),
-       PINCTRL_PIN(GPIO68, "GPIO68"),
-       PINCTRL_PIN(GPIO69, "GPIO69"),
-       PINCTRL_PIN(GPIO70, "GPIO70"),
-       PINCTRL_PIN(GPIO71, "GPIO71"),
-       PINCTRL_PIN(GPIO72, "GPIO72"),
-       PINCTRL_PIN(GPIO73, "GPIO73"),
-       PINCTRL_PIN(GPIO74, "GPIO74"),
-       PINCTRL_PIN(GPIO75, "GPIO75"),
-       PINCTRL_PIN(GPIO76, "GPIO76"),
-       PINCTRL_PIN(GPIO77, "GPIO77"),
-       PINCTRL_PIN(GPIO78, "GPIO78"),
-       PINCTRL_PIN(GPIO79, "GPIO79"),
-       PINCTRL_PIN(GPIO80, "GPIO80"),
-       PINCTRL_PIN(GPIO81, "GPIO81"),
-       PINCTRL_PIN(GPIO82, "GPIO82"),
-       PINCTRL_PIN(GPIO83, "GPIO83"),
-       PINCTRL_PIN(GPIO84, "GPIO84"),
-       PINCTRL_PIN(GPIO85, "GPIO85"),
-       PINCTRL_PIN(GPIO86, "GPIO86"),
-       PINCTRL_PIN(GPIO87, "GPIO87"),
-       PINCTRL_PIN(GPIO88, "GPIO88"),
-       PINCTRL_PIN(GPIO89, "GPIO89"),
-       PINCTRL_PIN(GPIO90, "GPIO90"),
-       PINCTRL_PIN(GPIO91, "GPIO91"),
-       PINCTRL_PIN(GPIO92, "GPIO92"),
-       PINCTRL_PIN(GPIO93, "GPIO93"),
-       PINCTRL_PIN(GPIO94, "GPIO94"),
-       PINCTRL_PIN(GPIO95, "GPIO95"),
-       PINCTRL_PIN(GPIO96, "GPIO96"),
-       PINCTRL_PIN(GPIO97, "GPIO97"),
-       PINCTRL_PIN(GPIO98, "GPIO98"),
-       PINCTRL_PIN(GPIO99, "GPIO99"),
-       PINCTRL_PIN(GPIO100, "GPIO100"),
-       PINCTRL_PIN(GPIO101, "GPIO101"),
-       PINCTRL_PIN(GPIO102, "GPIO102"),
-       PINCTRL_PIN(GPIO103, "GPIO103"),
-       PINCTRL_PIN(GPIO104, "GPIO104"),
-       PINCTRL_PIN(GPIO105, "GPIO105"),
-       PINCTRL_PIN(GPIO106, "GPIO106"),
-       PINCTRL_PIN(GPIO107, "GPIO107"),
-       PINCTRL_PIN(GPIO108, "GPIO108"),
-       PINCTRL_PIN(GPIO109, "GPIO109"),
-       PINCTRL_PIN(GPIO110, "GPIO110"),
-       PINCTRL_PIN(GPIO111, "GPIO111"),
-       PINCTRL_PIN(GPIO112, "GPIO112"),
-       PINCTRL_PIN(GPIO113, "GPIO113"),
-       PINCTRL_PIN(GPIO114, "GPIO114"),
-       PINCTRL_PIN(GPIO115, "GPIO115"),
-       PINCTRL_PIN(GPIO116, "GPIO116"),
-       PINCTRL_PIN(GPIO117, "GPIO117"),
-       PINCTRL_PIN(GPIO118, "GPIO118"),
-       PINCTRL_PIN(GPIO119, "GPIO119"),
-       PINCTRL_PIN(GPIO120, "GPIO120"),
-       PINCTRL_PIN(GPIO121, "GPIO121"),
-       PINCTRL_PIN(GPIO122, "GPIO122"),
-       PINCTRL_PIN(GPIO123, "GPIO123"),
-       PINCTRL_PIN(GPIO124, "GPIO124"),
-       PINCTRL_PIN(GPIO125, "GPIO125"),
-       PINCTRL_PIN(GPIO126, "GPIO126"),
-       PINCTRL_PIN(GPIO127, "GPIO127"),
-       PINCTRL_PIN(ND_IO15, "ND_IO15"),
-       PINCTRL_PIN(ND_IO14, "ND_IO14"),
-       PINCTRL_PIN(ND_IO13, "ND_IO13"),
-       PINCTRL_PIN(ND_IO12, "ND_IO12"),
-       PINCTRL_PIN(ND_IO11, "ND_IO11"),
-       PINCTRL_PIN(ND_IO10, "ND_IO10"),
-       PINCTRL_PIN(ND_IO9, "ND_IO9"),
-       PINCTRL_PIN(ND_IO8, "ND_IO8"),
-       PINCTRL_PIN(ND_IO7, "ND_IO7"),
-       PINCTRL_PIN(ND_IO6, "ND_IO6"),
-       PINCTRL_PIN(ND_IO5, "ND_IO5"),
-       PINCTRL_PIN(ND_IO4, "ND_IO4"),
-       PINCTRL_PIN(ND_IO3, "ND_IO3"),
-       PINCTRL_PIN(ND_IO2, "ND_IO2"),
-       PINCTRL_PIN(ND_IO1, "ND_IO1"),
-       PINCTRL_PIN(ND_IO0, "ND_IO0"),
-       PINCTRL_PIN(ND_NCS0, "ND_NCS0_SM_NCS2"),
-       PINCTRL_PIN(ND_NCS1, "ND_NCS1_SM_NCS3"),
-       PINCTRL_PIN(SM_NCS0, "SM_NCS0"),
-       PINCTRL_PIN(SM_NCS1, "SM_NCS1"),
-       PINCTRL_PIN(ND_NWE, "ND_NWE"),
-       PINCTRL_PIN(ND_NRE, "ND_NRE"),
-       PINCTRL_PIN(ND_CLE, "ND_CLE_SM_NOE"),
-       PINCTRL_PIN(ND_ALE, "ND_ALE_SM_NWE"),
-       PINCTRL_PIN(SM_SCLK, "SM_SCLK"),
-       PINCTRL_PIN(ND_RDY0, "ND_RDY0"),
-       PINCTRL_PIN(SM_ADV, "SM_ADV"),
-       PINCTRL_PIN(ND_RDY1, "ND_RDY1"),
-       PINCTRL_PIN(SM_RDY, "SM_RDY"),
-       PINCTRL_PIN(MMC1_DAT7, "MMC1_DAT7"),
-       PINCTRL_PIN(MMC1_DAT6, "MMC1_DAT6"),
-       PINCTRL_PIN(MMC1_DAT5, "MMC1_DAT5"),
-       PINCTRL_PIN(MMC1_DAT4, "MMC1_DAT4"),
-       PINCTRL_PIN(MMC1_DAT3, "MMC1_DAT3"),
-       PINCTRL_PIN(MMC1_DAT2, "MMC1_DAT2"),
-       PINCTRL_PIN(MMC1_DAT1, "MMC1_DAT1"),
-       PINCTRL_PIN(MMC1_DAT0, "MMC1_DAT0"),
-       PINCTRL_PIN(MMC1_CMD, "MMC1 CMD"),
-       PINCTRL_PIN(MMC1_CLK, "MMC1 CLK"),
-       PINCTRL_PIN(MMC1_CD, "MMC1 CD"),
-       PINCTRL_PIN(VCXO_OUT, "VCXO_OUT"),
-};
-
-struct pxa3xx_mfp_pin pxa910_mfp[] = {
-       /*       pin        offs   f0        f1      f2         f3         f4         f5        f6        f7  */
-       MFPR_910(GPIO0,     0x0DC, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO1,     0x0E0, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO2,     0x0E4, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO3,     0x0E8, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO4,     0x0EC, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO5,     0x0F0, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO6,     0x0F4, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO7,     0x0F8, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO8,     0x0FC, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO9,     0x100, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO10,    0x104, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO11,    0x108, GPIO,     KP_MK,  NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO12,    0x10C, GPIO,     KP_MK,  NONE,      NONE,      KP_DK,     NONE,     NONE,     NONE),
-       MFPR_910(GPIO13,    0x110, GPIO,     KP_MK,  NONE,      NONE,      KP_DK,     NONE,     NONE,     NONE),
-       MFPR_910(GPIO14,    0x114, GPIO,     KP_MK,  NONE,      NONE,      KP_DK,     TB,       NONE,     NONE),
-       MFPR_910(GPIO15,    0x118, GPIO,     KP_MK,  NONE,      NONE,      KP_DK,     TB,       NONE,     NONE),
-       MFPR_910(GPIO16,    0x11C, GPIO,     KP_DK,  NONE,      NONE,      NONE,      TB,       NONE,     NONE),
-       MFPR_910(GPIO17,    0x120, GPIO,     KP_DK,  NONE,      NONE,      NONE,      TB,       NONE,     NONE),
-       MFPR_910(GPIO18,    0x124, GPIO,     KP_DK,  NONE,      NONE,      ROT,       NONE,     NONE,     NONE),
-       MFPR_910(GPIO19,    0x128, GPIO,     KP_DK,  NONE,      NONE,      ROT,       NONE,     NONE,     NONE),
-       MFPR_910(GPIO20,    0x12C, GPIO,     SSP1,   NONE,      NONE,      VCXO_OUT,  NONE,     NONE,     NONE),
-       MFPR_910(GPIO21,    0x130, GPIO,     SSP1,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO22,    0x134, GPIO,     SSP1,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO23,    0x138, GPIO,     SSP1,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO24,    0x13C, GPIO,     SSP1,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO25,    0x140, GPIO,     GSSP,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO26,    0x144, GPIO,     GSSP,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO27,    0x148, GPIO,     GSSP,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO28,    0x14C, GPIO,     GSSP,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO29,    0x150, GPIO,     UART0,  NONE,      NONE,      UART1,     NONE,     NONE,     NONE),
-       MFPR_910(GPIO30,    0x154, GPIO,     UART0,  NONE,      NONE,      UART1,     NONE,     NONE,     NONE),
-       MFPR_910(GPIO31,    0x158, GPIO,     UART0,  NONE,      NONE,      UART1,     NONE,     NONE,     NONE),
-       MFPR_910(GPIO32,    0x15C, GPIO,     UART0,  DAC_ST23,  NONE,      UART1,     NONE,     NONE,     NONE),
-       MFPR_910(GPIO33,    0x160, GPIO,     MMC2,   SSP0,      SSP2,      NONE,      SPI,      NONE,     MMC3),
-       MFPR_910(GPIO34,    0x164, GPIO,     MMC2,   SSP0,      SSP2,      NONE,      SPI,      NONE,     MMC3),
-       MFPR_910(GPIO35,    0x168, GPIO,     MMC2,   SSP0,      SSP2,      NONE,      SPI,      NONE,     MMC3),
-       MFPR_910(GPIO36,    0x16C, GPIO,     MMC2,   SSP0,      SSP2,      NONE,      SPI,      NONE,     MMC3),
-       MFPR_910(GPIO37,    0x170, GPIO,     MMC2,   NONE,      NONE,      NONE,      SPI,      HSL,      NONE),
-       MFPR_910(GPIO38,    0x174, GPIO,     MMC2,   NONE,      NONE,      NONE,      NONE,     HSL,      NONE),
-       MFPR_910(GPIO39,    0x178, GPIO,     MMC2,   NONE,      NONE,      NONE,      NONE,     HSL,      NONE),
-       MFPR_910(GPIO40,    0x17C, GPIO,     MMC2,   NONE,      NONE,      NONE,      NONE,     HSL,      NONE),
-       MFPR_910(GPIO41,    0x180, GPIO,     MMC2,   NONE,      NONE,      NONE,      NONE,     HSL,      NONE),
-       MFPR_910(GPIO42,    0x184, GPIO,     MMC2,   NONE,      NONE,      NONE,      NONE,     HSL,      NONE),
-       MFPR_910(GPIO43,    0x188, GPIO,     UART1,  NONE,      DAC_ST23,  NONE,      DSSP2,    SPI,      UART2),
-       MFPR_910(GPIO44,    0x18C, GPIO,     UART1,  NONE,      EXT_INT,   NONE,      DSSP2,    SPI,      UART2),
-       MFPR_910(GPIO45,    0x190, GPIO,     UART1,  NONE,      EXT_INT,   NONE,      DSSP2,    SPI,      UART2),
-       MFPR_910(GPIO46,    0x194, GPIO,     UART1,  NONE,      EXT_INT,   NONE,      DSSP2,    SPI,      UART2),
-       MFPR_910(GPIO47,    0x198, GPIO,     SSP0,   NONE,      NONE,      NONE,      SSP2,     UART1,    NONE),
-       MFPR_910(GPIO48,    0x19C, GPIO,     SSP0,   NONE,      NONE,      NONE,      SSP2,     UART1,    NONE),
-       MFPR_910(GPIO49,    0x1A0, GPIO,     SSP0,   UART0,     VCXO_REQ,  NONE,      SSP2,     NONE,     MMC3),
-       MFPR_910(GPIO50,    0x1A4, GPIO,     SSP0,   UART0,     VCXO_OUT,  NONE,      SSP2,     NONE,     MMC3),
-       MFPR_910(GPIO51,    0x1A8, GPIO,     UART2,  PWM1,      TWSI,      SSP0,      NONE,     DSSP3,    NONE),
-       MFPR_910(GPIO52,    0x1AC, GPIO,     UART2,  DAC_ST23,  TWSI,      SSP0,      NONE,     DSSP3,    NONE),
-       MFPR_910(GPIO53,    0x1B0, GPIO,     UART2,  TWSI,      NONE,      SSP0,      NONE,     DSSP3,    NONE),
-       MFPR_910(GPIO54,    0x1B4, GPIO,     UART2,  TWSI,      SSP0,      NONE,      NONE,     DSSP3,    NONE),
-       MFPR_910(GPIO55,    0x2F0, TDS,      GPIO,   TB,        NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO56,    0x2F4, TDS,      GPIO,   TB,        NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO57,    0x2F8, TDS,      GPIO,   TB,        NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO58,    0x2FC, TDS,      GPIO,   TB,        NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO59,    0x300, TDS,      GPIO,   TCU_GPOA,  TCU_GPOB,  ONE_WIRE,  NONE,     NONE,     NONE),
-       MFPR_910(GPIO60,    0x304, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO61,    0x308, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     HSL),
-       MFPR_910(GPIO62,    0x30C, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     HSL),
-       MFPR_910(GPIO63,    0x310, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     HSL),
-       MFPR_910(GPIO64,    0x314, GPIO,     SPI2,   NONE,      NONE,      NONE,      NONE,     NONE,     HSL),
-       MFPR_910(GPIO65,    0x318, GPIO,     SPI2,   NONE,      NONE,      NONE,      NONE,     ONE_WIRE, HSL),
-       MFPR_910(GPIO66,    0x31C, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     HSL),
-       MFPR_910(GPIO67,    0x1B8, GPIO,     CCIC,   SPI,       NONE,      NONE,      ULPI,     NONE,     USIM2),
-       MFPR_910(GPIO68,    0x1BC, GPIO,     CCIC,   SPI,       NONE,      NONE,      ULPI,     NONE,     USIM2),
-       MFPR_910(GPIO69,    0x1C0, GPIO,     CCIC,   SPI,       NONE,      NONE,      ULPI,     NONE,     USIM2),
-       MFPR_910(GPIO70,    0x1C4, GPIO,     CCIC,   SPI,       NONE,      NONE,      ULPI,     NONE,     NONE),
-       MFPR_910(GPIO71,    0x1C8, GPIO,     CCIC,   SPI,       NONE,      NONE,      ULPI,     NONE,     NONE),
-       MFPR_910(GPIO72,    0x1CC, GPIO,     CCIC,   EXT_DMA,   NONE,      NONE,      ULPI,     NONE,     NONE),
-       MFPR_910(GPIO73,    0x1D0, GPIO,     CCIC,   EXT_DMA,   NONE,      NONE,      ULPI,     NONE,     NONE),
-       MFPR_910(GPIO74,    0x1D4, GPIO,     CCIC,   EXT_DMA,   NONE,      NONE,      ULPI,     NONE,     NONE),
-       MFPR_910(GPIO75,    0x1D8, GPIO,     CCIC,   NONE,      NONE,      NONE,      ULPI,     NONE,     NONE),
-       MFPR_910(GPIO76,    0x1DC, GPIO,     CCIC,   NONE,      NONE,      NONE,      ULPI,     NONE,     NONE),
-       MFPR_910(GPIO77,    0x1E0, GPIO,     CCIC,   NONE,      NONE,      NONE,      ULPI,     NONE,     NONE),
-       MFPR_910(GPIO78,    0x1E4, GPIO,     CCIC,   NONE,      NONE,      NONE,      ULPI,     NONE,     NONE),
-       MFPR_910(GPIO79,    0x1E8, GPIO,     TWSI,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO80,    0x1EC, GPIO,     TWSI,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO81,    0x1F0, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO82,    0x1F4, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO83,    0x1F8, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO84,    0x1FC, GPIO,     LCD,    VCXO_REQ2, NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO85,    0x200, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO86,    0x204, GPIO,     LCD,    VCXO_OUT2, NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO87,    0x208, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO88,    0x20C, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO89,    0x210, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO90,    0x214, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO91,    0x218, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO92,    0x21C, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO93,    0x220, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO94,    0x224, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO95,    0x228, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO96,    0x22C, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO97,    0x230, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO98,    0x234, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO99,    0x0B0, MMC1,     GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO100,   0x238, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO101,   0x23C, GPIO,     LCD,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO102,   0x240, GPIO,     LCD,    DSSP2,     SPI,       NONE,      NONE,     NONE,     SPI2),
-       MFPR_910(GPIO103,   0x244, GPIO,     LCD,    DSSP2,     SPI,       NONE,      NONE,     NONE,     SPI2),
-       MFPR_910(GPIO104,   0x248, GPIO,     LCD,    DSSP2,     SPI,       NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO105,   0x24C, GPIO,     LCD,    DSSP2,     SPI,       NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO106,   0x250, GPIO,     LCD,    DSSP3,     ONE_WIRE,  NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO107,   0x254, GPIO,     LCD,    DSSP3,     SPI,       NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO108,   0x258, GPIO,     LCD,    DSSP3,     SPI,       NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO109,   0x25C, GPIO,     LCD,    DSSP3,     SPI,       NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO110,   0x298, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO111,   0x29C, GPIO,     NONE,   DSSP2,     NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO112,   0x2A0, GPIO,     NONE,   DSSP2,     NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO113,   0x2A4, GPIO,     NONE,   DSSP2,     NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO114,   0x2A8, GPIO,     NONE,   DSSP3,     NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO115,   0x2AC, GPIO,     NONE,   DSSP3,     NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO116,   0x2B0, GPIO,     NONE,   DSSP3,     NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO117,   0x0B4, PRI_JTAG, GPIO,   PWM0,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO118,   0x0B8, PRI_JTAG, GPIO,   PWM1,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO119,   0x0BC, PRI_JTAG, GPIO,   PWM2,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO120,   0x0C0, PRI_JTAG, GPIO,   PWM3,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO121,   0x32C, GPIO,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO122,   0x0C8, RESET,    GPIO,   32K_CLK,   NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO123,   0x0CC, CLK_REQ,  GPIO,   ONE_WIRE,  EXT_DMA,   NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO124,   0x0D0, GPIO,     MN_CLK, DAC_ST23,  NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO125,   0x0D4, VCXO_REQ, GPIO,   NONE,      EXT_INT,   NONE,      NONE,     NONE,     NONE),
-       MFPR_910(GPIO126,   0x06C, GPIO,     SMC,    NONE,      SM_ADDR18, NONE,      EXT_DMA,  NONE,     NONE),
-       MFPR_910(GPIO127,   0x070, GPIO,     SMC,    NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO15,   0x004, NAND,     GPIO,   USIM2,     EXT_DMA,   NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO14,   0x008, NAND,     GPIO,   USIM2,     NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO13,   0x00C, NAND,     GPIO,   USIM2,     EXT_INT,   NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO12,   0x010, NAND,     GPIO,   SSP2,      EXT_INT,   NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO11,   0x014, NAND,     GPIO,   SSP2,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO10,   0x018, NAND,     GPIO,   SSP2,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO9,    0x01C, NAND,     GPIO,   SSP2,      NONE,      VCXO_OUT2, NONE,     NONE,     NONE),
-       MFPR_910(ND_IO8,    0x020, NAND,     GPIO,   NONE,      NONE,      PWM3,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO7,    0x024, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO6,    0x028, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO5,    0x02C, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO4,    0x030, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO3,    0x034, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO2,    0x038, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO1,    0x03C, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_IO0,    0x040, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_NCS0,   0x044, NAND,     GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_NCS1,   0x048, NAND,     GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(SM_NCS0,   0x04C, SMC,      GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(SM_NCS1,   0x050, SMC,      GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_NWE,    0x054, GPIO,     NAND,   NONE,      SM_ADDR20, NONE,      SMC,      NONE,     NONE),
-       MFPR_910(ND_NRE,    0x058, GPIO,     NAND,   NONE,      SMC,       NONE,      EXT_DMA,  NONE,     NONE),
-       MFPR_910(ND_CLE,    0x05C, NAND,     MMC3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_ALE,    0x060, GPIO,     NAND,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(SM_SCLK,   0x064, MMC3,     NONE,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_RDY0,   0x068, NAND,     GPIO,   NONE,      SMC,       NONE,      NONE,     NONE,     NONE),
-       MFPR_910(SM_ADV,    0x074, SMC,      GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(ND_RDY1,   0x078, NAND,     GPIO,   NONE,      SMC,       NONE,      NONE,     NONE,     NONE),
-       MFPR_910(SM_ADVMUX, 0x07C, SMC,      GPIO,   NONE,      SM_ADDR19, NONE,      NONE,     NONE,     NONE),
-       MFPR_910(SM_RDY,    0x080, SMC,      GPIO,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(MMC1_DAT7, 0x084, MMC1,     GPIO,   SEC1_JTAG, TB,        NONE,      NONE,     NONE,     NONE),
-       MFPR_910(MMC1_DAT6, 0x088, MMC1,     GPIO,   SEC1_JTAG, TB,        NONE,      NONE,     NONE,     NONE),
-       MFPR_910(MMC1_DAT5, 0x08C, MMC1,     GPIO,   SEC1_JTAG, TB,        NONE,      NONE,     NONE,     NONE),
-       MFPR_910(MMC1_DAT4, 0x090, MMC1,     GPIO,   NONE,      TB,        NONE,      NONE,     NONE,     NONE),
-       MFPR_910(MMC1_DAT3, 0x094, MMC1,     HSL,    SEC2_JTAG, SSP0,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(MMC1_DAT2, 0x098, MMC1,     HSL,    SEC2_JTAG, SSP2,      SSP0,      NONE,     NONE,     NONE),
-       MFPR_910(MMC1_DAT1, 0x09C, MMC1,     HSL,    SEC2_JTAG, SSP2,      SSP0,      NONE,     NONE,     NONE),
-       MFPR_910(MMC1_DAT0, 0x0A0, MMC1,     HSL,    SEC2_JTAG, SSP2,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(MMC1_CMD,  0x0A4, MMC1,     HSL,    SEC1_JTAG, SSP2,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(MMC1_CLK,  0x0A8, MMC1,     HSL,    SEC2_JTAG, SSP0,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(MMC1_CD,   0x0AC, MMC1,     GPIO,   SEC1_JTAG, NONE,      NONE,      NONE,     NONE,     NONE),
-       MFPR_910(VCXO_OUT,  0x0D8, VCXO_OUT, PWM3,   NONE,      NONE,      NONE,      NONE,     NONE,     NONE),
-};
-
-
-static const unsigned p910_usim2_pin1[] = {GPIO67, GPIO68, GPIO69};
-static const unsigned p910_usim2_pin2[] = {ND_IO15, ND_IO14, ND_IO13};
-static const unsigned p910_mmc1_pin1[] = {MMC1_DAT7, MMC1_DAT6, MMC1_DAT5,
-       MMC1_DAT4, MMC1_DAT3, MMC1_DAT2, MMC1_DAT1, MMC1_DAT0, MMC1_CMD,
-       MMC1_CLK, MMC1_CD, GPIO99};
-static const unsigned p910_mmc2_pin1[] = {GPIO33, GPIO34, GPIO35, GPIO36,
-       GPIO37, GPIO38, GPIO39, GPIO40, GPIO41, GPIO42};
-static const unsigned p910_mmc3_pin1[] = {GPIO33, GPIO34, GPIO35, GPIO36,
-       GPIO49, GPIO50};
-static const unsigned p910_mmc3_pin2[] = {ND_IO7, ND_IO6, ND_IO5, ND_IO4,
-       ND_IO3, ND_IO2, ND_IO1, ND_IO0, ND_CLE, SM_SCLK};
-static const unsigned p910_uart0_pin1[] = {GPIO29, GPIO30, GPIO31, GPIO32};
-static const unsigned p910_uart1_pin1[] = {GPIO47, GPIO48};
-static const unsigned p910_uart1_pin2[] = {GPIO31, GPIO32};
-static const unsigned p910_uart1_pin3[] = {GPIO45, GPIO46};
-static const unsigned p910_uart1_pin4[] = {GPIO29, GPIO30, GPIO31, GPIO32};
-static const unsigned p910_uart1_pin5[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned p910_uart2_pin1[] = {GPIO43, GPIO44};
-static const unsigned p910_uart2_pin2[] = {GPIO51, GPIO52};
-static const unsigned p910_uart2_pin3[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned p910_uart2_pin4[] = {GPIO51, GPIO52, GPIO53, GPIO54};
-static const unsigned p910_twsi_pin1[] = {GPIO51, GPIO52};
-static const unsigned p910_twsi_pin2[] = {GPIO53, GPIO54};
-static const unsigned p910_twsi_pin3[] = {GPIO79, GPIO80};
-static const unsigned p910_ccic_pin1[] = {GPIO67, GPIO68, GPIO69, GPIO70,
-       GPIO71, GPIO72, GPIO73, GPIO74, GPIO75, GPIO76, GPIO77, GPIO78};
-static const unsigned p910_lcd_pin1[] = {GPIO81, GPIO82, GPIO83, GPIO84,
-       GPIO85, GPIO86, GPIO87, GPIO88, GPIO89, GPIO90, GPIO91, GPIO92,
-       GPIO93, GPIO94, GPIO95, GPIO96, GPIO97, GPIO98, GPIO100, GPIO101,
-       GPIO102, GPIO103};
-static const unsigned p910_spi_pin1[] = {GPIO104, GPIO105, GPIO107, GPIO108};
-static const unsigned p910_spi_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned p910_spi_pin3[] = {GPIO33, GPIO34, GPIO35, GPIO36,
-       GPIO37};
-static const unsigned p910_spi_pin4[] = {GPIO67, GPIO68, GPIO69, GPIO70,
-       GPIO71};
-static const unsigned p910_spi2_pin1[] = {GPIO64, GPIO65};
-static const unsigned p910_spi2_pin2[] = {GPIO102, GPIO103};
-static const unsigned p910_dssp2_pin1[] = {GPIO102, GPIO103, GPIO104, GPIO105};
-static const unsigned p910_dssp2_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned p910_dssp2_pin3[] = {GPIO111, GPIO112, GPIO113};
-static const unsigned p910_dssp3_pin1[] = {GPIO106, GPIO107, GPIO108, GPIO109};
-static const unsigned p910_dssp3_pin2[] = {GPIO51, GPIO52, GPIO53, GPIO54};
-static const unsigned p910_dssp3_pin3[] = {GPIO114, GPIO115, GPIO116};
-static const unsigned p910_ssp0_pin1[] = {MMC1_DAT3, MMC1_DAT2, MMC1_DAT1,
-       MMC1_CLK};
-static const unsigned p910_ssp0_pin2[] = {GPIO33, GPIO34, GPIO35, GPIO36};
-static const unsigned p910_ssp0_pin3[] = {GPIO47, GPIO48, GPIO49, GPIO50};
-static const unsigned p910_ssp0_pin4[] = {GPIO51, GPIO52, GPIO53, GPIO54};
-static const unsigned p910_ssp1_pin1[] = {GPIO21, GPIO22, GPIO23, GPIO24};
-static const unsigned p910_ssp1_pin2[] = {GPIO20, GPIO21, GPIO22, GPIO23,
-       GPIO24};
-static const unsigned p910_ssp2_pin1[] = {MMC1_DAT2, MMC1_DAT1, MMC1_DAT0,
-       MMC1_CMD};
-static const unsigned p910_ssp2_pin2[] = {GPIO33, GPIO34, GPIO35, GPIO36};
-static const unsigned p910_ssp2_pin3[] = {GPIO47, GPIO48, GPIO49, GPIO50};
-static const unsigned p910_ssp2_pin4[] = {ND_IO12, ND_IO11, ND_IO10, ND_IO9};
-static const unsigned p910_gssp_pin1[] = {GPIO25, GPIO26, GPIO27, GPIO28};
-static const unsigned p910_pwm0_pin1[] = {GPIO117};
-static const unsigned p910_pwm1_pin1[] = {GPIO118};
-static const unsigned p910_pwm1_pin2[] = {GPIO51};
-static const unsigned p910_pwm2_pin1[] = {GPIO119};
-static const unsigned p910_pwm3_pin1[] = {GPIO120};
-static const unsigned p910_pwm3_pin2[] = {ND_IO8};
-static const unsigned p910_pwm3_pin3[] = {VCXO_OUT};
-static const unsigned p910_pri_jtag_pin1[] = {GPIO117, GPIO118, GPIO119,
-       GPIO120};
-static const unsigned p910_sec1_jtag_pin1[] = {MMC1_DAT7, MMC1_DAT6, MMC1_DAT5,
-       MMC1_CMD, MMC1_CD};
-static const unsigned p910_sec2_jtag_pin1[] = {MMC1_DAT3, MMC1_DAT2, MMC1_DAT1,
-       MMC1_DAT0, MMC1_CLK};
-static const unsigned p910_hsl_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40,
-       GPIO41, GPIO42};
-static const unsigned p910_hsl_pin2[] = {GPIO61, GPIO62, GPIO63, GPIO64,
-       GPIO65, GPIO66};
-static const unsigned p910_hsl_pin3[] = {MMC1_DAT3, MMC1_DAT2, MMC1_DAT1,
-       MMC1_DAT0, MMC1_CMD, MMC1_CLK};
-static const unsigned p910_w1_pin1[] = {GPIO59};
-static const unsigned p910_w1_pin2[] = {GPIO65};
-static const unsigned p910_w1_pin3[] = {GPIO106};
-static const unsigned p910_w1_pin4[] = {GPIO123};
-static const unsigned p910_kpmk_pin1[] = {GPIO0, GPIO1, GPIO2, GPIO3, GPIO4,
-       GPIO5, GPIO6, GPIO7, GPIO8, GPIO9, GPIO10, GPIO11, GPIO12, GPIO13,
-       GPIO14, GPIO15};
-static const unsigned p910_kpmk_pin2[] = {GPIO0, GPIO1, GPIO2, GPIO3, GPIO4,
-       GPIO5, GPIO6, GPIO7, GPIO8, GPIO9, GPIO12};
-static const unsigned p910_kpdk_pin1[] = {GPIO12, GPIO13, GPIO14, GPIO15,
-       GPIO16, GPIO17, GPIO18, GPIO19};
-static const unsigned p910_tds_pin1[] = {GPIO55, GPIO56, GPIO57, GPIO58,
-       GPIO59};
-static const unsigned p910_tds_pin2[] = {GPIO55, GPIO57, GPIO58, GPIO59};
-static const unsigned p910_tb_pin1[] = {GPIO14, GPIO15, GPIO16, GPIO17};
-static const unsigned p910_tb_pin2[] = {GPIO55, GPIO56, GPIO57, GPIO58};
-static const unsigned p910_tb_pin3[] = {MMC1_DAT7, MMC1_DAT6, MMC1_DAT5,
-       MMC1_DAT4};
-static const unsigned p910_ext_dma0_pin1[] = {GPIO72};
-static const unsigned p910_ext_dma0_pin2[] = {ND_IO15};
-static const unsigned p910_ext_dma0_pin3[] = {ND_NRE};
-static const unsigned p910_ext_dma1_pin1[] = {GPIO73};
-static const unsigned p910_ext_dma1_pin2[] = {GPIO123};
-static const unsigned p910_ext_dma1_pin3[] = {GPIO126};
-static const unsigned p910_ext_dma2_pin1[] = {GPIO74};
-static const unsigned p910_ext0_int_pin1[] = {GPIO44};
-static const unsigned p910_ext0_int_pin2[] = {ND_IO13};
-static const unsigned p910_ext1_int_pin1[] = {GPIO45};
-static const unsigned p910_ext1_int_pin2[] = {ND_IO12};
-static const unsigned p910_ext2_int_pin1[] = {GPIO46};
-static const unsigned p910_ext2_int_pin2[] = {GPIO125};
-static const unsigned p910_dac_st23_pin1[] = {GPIO32};
-static const unsigned p910_dac_st23_pin2[] = {GPIO43};
-static const unsigned p910_dac_st23_pin3[] = {GPIO52};
-static const unsigned p910_dac_st23_pin4[] = {GPIO124};
-static const unsigned p910_vcxo_out_pin1[] = {GPIO50};
-static const unsigned p910_vcxo_out_pin2[] = {VCXO_OUT};
-static const unsigned p910_vcxo_out_pin3[] = {GPIO20};
-static const unsigned p910_vcxo_req_pin1[] = {GPIO49};
-static const unsigned p910_vcxo_req_pin2[] = {GPIO125};
-static const unsigned p910_vcxo_out2_pin1[] = {GPIO86};
-static const unsigned p910_vcxo_out2_pin2[] = {ND_IO9};
-static const unsigned p910_vcxo_req2_pin1[] = {GPIO84};
-static const unsigned p910_ulpi_pin1[] = {GPIO67, GPIO68, GPIO69, GPIO70,
-       GPIO71, GPIO72, GPIO73, GPIO74, GPIO75, GPIO76, GPIO77, GPIO78};
-static const unsigned p910_nand_pin1[] = {ND_IO15, ND_IO14, ND_IO13, ND_IO12,
-       ND_IO11, ND_IO10, ND_IO9, ND_IO8, ND_IO7, ND_IO6, ND_IO5, ND_IO4,
-       ND_IO3, ND_IO2, ND_IO1, ND_IO0, ND_NCS0, ND_NWE, ND_NRE, ND_CLE,
-       ND_ALE, ND_RDY0};
-static const unsigned p910_gpio0_pin1[] = {GPIO0};
-static const unsigned p910_gpio0_pin2[] = {SM_ADV};
-static const unsigned p910_gpio1_pin1[] = {GPIO1};
-static const unsigned p910_gpio1_pin2[] = {ND_RDY1};
-static const unsigned p910_gpio2_pin1[] = {GPIO2};
-static const unsigned p910_gpio2_pin2[] = {SM_ADVMUX};
-static const unsigned p910_gpio3_pin1[] = {GPIO3};
-static const unsigned p910_gpio3_pin2[] = {SM_RDY};
-static const unsigned p910_gpio20_pin1[] = {GPIO20};
-static const unsigned p910_gpio20_pin2[] = {ND_IO15};
-static const unsigned p910_gpio20_pin3[] = {MMC1_DAT6};
-static const unsigned p910_gpio21_pin1[] = {GPIO21};
-static const unsigned p910_gpio21_pin2[] = {ND_IO14};
-static const unsigned p910_gpio21_pin3[] = {MMC1_DAT5};
-static const unsigned p910_gpio22_pin1[] = {GPIO22};
-static const unsigned p910_gpio22_pin2[] = {ND_IO13};
-static const unsigned p910_gpio22_pin3[] = {MMC1_DAT4};
-static const unsigned p910_gpio23_pin1[] = {GPIO23};
-static const unsigned p910_gpio23_pin2[] = {ND_IO12};
-static const unsigned p910_gpio23_pin3[] = {MMC1_CD};
-static const unsigned p910_gpio24_pin1[] = {GPIO24};
-static const unsigned p910_gpio24_pin2[] = {ND_IO11};
-static const unsigned p910_gpio24_pin3[] = {MMC1_DAT7};
-static const unsigned p910_gpio25_pin1[] = {GPIO25};
-static const unsigned p910_gpio25_pin2[] = {ND_IO10};
-static const unsigned p910_gpio26_pin1[] = {GPIO26};
-static const unsigned p910_gpio26_pin2[] = {ND_IO9};
-static const unsigned p910_gpio27_pin1[] = {GPIO27};
-static const unsigned p910_gpio27_pin2[] = {ND_IO8};
-static const unsigned p910_gpio85_pin1[] = {GPIO85};
-static const unsigned p910_gpio85_pin2[] = {ND_NCS0};
-static const unsigned p910_gpio86_pin1[] = {GPIO86};
-static const unsigned p910_gpio86_pin2[] = {ND_NCS1};
-static const unsigned p910_gpio87_pin1[] = {GPIO87};
-static const unsigned p910_gpio87_pin2[] = {SM_NCS0};
-static const unsigned p910_gpio88_pin1[] = {GPIO88};
-static const unsigned p910_gpio88_pin2[] = {SM_NCS1};
-static const unsigned p910_gpio89_pin1[] = {GPIO89};
-static const unsigned p910_gpio89_pin2[] = {ND_NWE};
-static const unsigned p910_gpio90_pin1[] = {GPIO90};
-static const unsigned p910_gpio90_pin2[] = {ND_NRE};
-static const unsigned p910_gpio91_pin1[] = {GPIO91};
-static const unsigned p910_gpio91_pin2[] = {ND_ALE};
-static const unsigned p910_gpio92_pin1[] = {GPIO92};
-static const unsigned p910_gpio92_pin2[] = {ND_RDY0};
-
-static struct pxa3xx_pin_group pxa910_grps[] = {
-       GRP_910("usim2 3p1", USIM2, p910_usim2_pin1),
-       GRP_910("usim2 3p2", USIM2, p910_usim2_pin2),
-       GRP_910("mmc1 12p", MMC1, p910_mmc1_pin1),
-       GRP_910("mmc2 10p", MMC2, p910_mmc2_pin1),
-       GRP_910("mmc3 6p", MMC3, p910_mmc3_pin1),
-       GRP_910("mmc3 10p", MMC3, p910_mmc3_pin2),
-       GRP_910("uart0 4p", UART0, p910_uart0_pin1),
-       GRP_910("uart1 2p1", UART1, p910_uart1_pin1),
-       GRP_910("uart1 2p2", UART1, p910_uart1_pin2),
-       GRP_910("uart1 2p3", UART1, p910_uart1_pin3),
-       GRP_910("uart1 4p4", UART1, p910_uart1_pin4),
-       GRP_910("uart1 4p5", UART1, p910_uart1_pin5),
-       GRP_910("uart2 2p1", UART2, p910_uart2_pin1),
-       GRP_910("uart2 2p2", UART2, p910_uart2_pin2),
-       GRP_910("uart2 4p3", UART2, p910_uart2_pin3),
-       GRP_910("uart2 4p4", UART2, p910_uart2_pin4),
-       GRP_910("twsi 2p1", TWSI, p910_twsi_pin1),
-       GRP_910("twsi 2p2", TWSI, p910_twsi_pin2),
-       GRP_910("twsi 2p3", TWSI, p910_twsi_pin3),
-       GRP_910("ccic", CCIC, p910_ccic_pin1),
-       GRP_910("lcd", LCD, p910_lcd_pin1),
-       GRP_910("spi 4p1", SPI, p910_spi_pin1),
-       GRP_910("spi 4p2", SPI, p910_spi_pin2),
-       GRP_910("spi 5p3", SPI, p910_spi_pin3),
-       GRP_910("spi 5p4", SPI, p910_spi_pin4),
-       GRP_910("dssp2 4p1", DSSP2, p910_dssp2_pin1),
-       GRP_910("dssp2 4p2", DSSP2, p910_dssp2_pin2),
-       GRP_910("dssp2 3p3", DSSP2, p910_dssp2_pin3),
-       GRP_910("dssp3 4p1", DSSP3, p910_dssp3_pin1),
-       GRP_910("dssp3 4p2", DSSP3, p910_dssp3_pin2),
-       GRP_910("dssp3 3p3", DSSP3, p910_dssp3_pin3),
-       GRP_910("ssp0 4p1", SSP0, p910_ssp0_pin1),
-       GRP_910("ssp0 4p2", SSP0, p910_ssp0_pin2),
-       GRP_910("ssp0 4p3", SSP0, p910_ssp0_pin3),
-       GRP_910("ssp0 4p4", SSP0, p910_ssp0_pin4),
-       GRP_910("ssp1 4p1", SSP1, p910_ssp1_pin1),
-       GRP_910("ssp1 5p2", SSP1, p910_ssp1_pin2),
-       GRP_910("ssp2 4p1", SSP2, p910_ssp2_pin1),
-       GRP_910("ssp2 4p2", SSP2, p910_ssp2_pin2),
-       GRP_910("ssp2 4p3", SSP2, p910_ssp2_pin3),
-       GRP_910("ssp2 4p4", SSP2, p910_ssp2_pin4),
-       GRP_910("gssp", GSSP, p910_gssp_pin1),
-       GRP_910("pwm0", PWM0, p910_pwm0_pin1),
-       GRP_910("pwm1-1", PWM1, p910_pwm1_pin1),
-       GRP_910("pwm1-2", PWM1, p910_pwm1_pin2),
-       GRP_910("pwm2", PWM2, p910_pwm2_pin1),
-       GRP_910("pwm3-1", PWM3, p910_pwm3_pin1),
-       GRP_910("pwm3-2", PWM3, p910_pwm3_pin2),
-       GRP_910("pwm3-3", PWM3, p910_pwm3_pin3),
-       GRP_910("pri jtag", PRI_JTAG, p910_pri_jtag_pin1),
-       GRP_910("sec1 jtag", SEC1_JTAG, p910_sec1_jtag_pin1),
-       GRP_910("sec2 jtag", SEC2_JTAG, p910_sec2_jtag_pin1),
-       GRP_910("hsl 6p1", HSL, p910_hsl_pin1),
-       GRP_910("hsl 6p2", HSL, p910_hsl_pin2),
-       GRP_910("hsl 6p3", HSL, p910_hsl_pin3),
-       GRP_910("w1-1", ONE_WIRE, p910_w1_pin1),
-       GRP_910("w1-2", ONE_WIRE, p910_w1_pin2),
-       GRP_910("w1-3", ONE_WIRE, p910_w1_pin3),
-       GRP_910("w1-4", ONE_WIRE, p910_w1_pin4),
-       GRP_910("kpmk 16p1", KP_MK, p910_kpmk_pin1),
-       GRP_910("kpmk 11p2", KP_MK, p910_kpmk_pin2),
-       GRP_910("kpdk 8p1", KP_DK, p910_kpdk_pin1),
-       GRP_910("tds 5p1", TDS, p910_tds_pin1),
-       GRP_910("tds 4p2", TDS, p910_tds_pin2),
-       GRP_910("tb 4p1", TB, p910_tb_pin1),
-       GRP_910("tb 4p2", TB, p910_tb_pin2),
-       GRP_910("tb 4p3", TB, p910_tb_pin3),
-       GRP_910("ext dma0-1", EXT_DMA, p910_ext_dma0_pin1),
-       GRP_910("ext dma0-2", EXT_DMA, p910_ext_dma0_pin2),
-       GRP_910("ext dma0-3", EXT_DMA, p910_ext_dma0_pin3),
-       GRP_910("ext dma1-1", EXT_DMA, p910_ext_dma1_pin1),
-       GRP_910("ext dma1-2", EXT_DMA, p910_ext_dma1_pin2),
-       GRP_910("ext dma1-3", EXT_DMA, p910_ext_dma1_pin3),
-       GRP_910("ext dma2", EXT_DMA, p910_ext_dma2_pin1),
-       GRP_910("ext0 int-1", EXT_INT, p910_ext0_int_pin1),
-       GRP_910("ext0 int-2", EXT_INT, p910_ext0_int_pin2),
-       GRP_910("ext1 int-1", EXT_INT, p910_ext1_int_pin1),
-       GRP_910("ext1 int-2", EXT_INT, p910_ext1_int_pin2),
-       GRP_910("ext2 int-1", EXT_INT, p910_ext2_int_pin1),
-       GRP_910("ext2 int-2", EXT_INT, p910_ext2_int_pin2),
-       GRP_910("dac st23-1", DAC_ST23, p910_dac_st23_pin1),
-       GRP_910("dac st23-2", DAC_ST23, p910_dac_st23_pin2),
-       GRP_910("dac st23-3", DAC_ST23, p910_dac_st23_pin3),
-       GRP_910("dac st23-4", DAC_ST23, p910_dac_st23_pin4),
-       GRP_910("vcxo out-1", VCXO_OUT, p910_vcxo_out_pin1),
-       GRP_910("vcxo out-2", VCXO_OUT, p910_vcxo_out_pin2),
-       GRP_910("vcxo out-3", VCXO_OUT, p910_vcxo_out_pin3),
-       GRP_910("vcxo req-1", VCXO_REQ, p910_vcxo_req_pin1),
-       GRP_910("vcxo req-2", VCXO_REQ, p910_vcxo_req_pin2),
-       GRP_910("vcxo out2-1", VCXO_OUT2, p910_vcxo_out2_pin1),
-       GRP_910("vcxo out2-2", VCXO_OUT2, p910_vcxo_out2_pin2),
-       GRP_910("vcxo req2", VCXO_REQ2, p910_vcxo_req2_pin1),
-       GRP_910("ulpi", ULPI, p910_ulpi_pin1),
-       GRP_910("nand", NAND, p910_nand_pin1),
-       GRP_910("gpio0-1", GPIO, p910_gpio0_pin1),
-       GRP_910("gpio0-2", GPIO, p910_gpio0_pin2),
-       GRP_910("gpio1-1", GPIO, p910_gpio1_pin1),
-       GRP_910("gpio1-2", GPIO, p910_gpio1_pin2),
-       GRP_910("gpio2-1", GPIO, p910_gpio2_pin1),
-       GRP_910("gpio2-2", GPIO, p910_gpio2_pin2),
-       GRP_910("gpio3-1", GPIO, p910_gpio3_pin1),
-       GRP_910("gpio3-2", GPIO, p910_gpio3_pin2),
-       GRP_910("gpio20-1", GPIO, p910_gpio20_pin1),
-       GRP_910("gpio20-2", GPIO, p910_gpio20_pin2),
-       GRP_910("gpio21-1", GPIO, p910_gpio21_pin1),
-       GRP_910("gpio21-2", GPIO, p910_gpio21_pin2),
-       GRP_910("gpio22-1", GPIO, p910_gpio22_pin1),
-       GRP_910("gpio22-2", GPIO, p910_gpio22_pin2),
-       GRP_910("gpio23-1", GPIO, p910_gpio23_pin1),
-       GRP_910("gpio23-2", GPIO, p910_gpio23_pin2),
-       GRP_910("gpio24-1", GPIO, p910_gpio24_pin1),
-       GRP_910("gpio24-2", GPIO, p910_gpio24_pin2),
-       GRP_910("gpio25-1", GPIO, p910_gpio25_pin1),
-       GRP_910("gpio25-2", GPIO, p910_gpio25_pin2),
-       GRP_910("gpio26-1", GPIO, p910_gpio26_pin1),
-       GRP_910("gpio26-2", GPIO, p910_gpio26_pin2),
-       GRP_910("gpio27-1", GPIO, p910_gpio27_pin1),
-       GRP_910("gpio27-2", GPIO, p910_gpio27_pin2),
-       GRP_910("gpio85-1", GPIO, p910_gpio85_pin1),
-       GRP_910("gpio85-2", GPIO, p910_gpio85_pin2),
-       GRP_910("gpio86-1", GPIO, p910_gpio86_pin1),
-       GRP_910("gpio86-2", GPIO, p910_gpio86_pin2),
-       GRP_910("gpio87-1", GPIO, p910_gpio87_pin1),
-       GRP_910("gpio87-2", GPIO, p910_gpio87_pin2),
-       GRP_910("gpio88-1", GPIO, p910_gpio88_pin1),
-       GRP_910("gpio88-2", GPIO, p910_gpio88_pin2),
-       GRP_910("gpio89-1", GPIO, p910_gpio89_pin1),
-       GRP_910("gpio89-2", GPIO, p910_gpio89_pin2),
-       GRP_910("gpio90-1", GPIO, p910_gpio90_pin1),
-       GRP_910("gpio90-2", GPIO, p910_gpio90_pin2),
-       GRP_910("gpio91-1", GPIO, p910_gpio91_pin1),
-       GRP_910("gpio91-2", GPIO, p910_gpio91_pin2),
-       GRP_910("gpio92-1", GPIO, p910_gpio92_pin1),
-       GRP_910("gpio92-2", GPIO, p910_gpio92_pin2),
-};
-
-static const char * const p910_usim2_grps[] = {"usim2 3p1", "usim2 3p2"};
-static const char * const p910_mmc1_grps[] = {"mmc1 12p"};
-static const char * const p910_mmc2_grps[] = {"mmc2 10p"};
-static const char * const p910_mmc3_grps[] = {"mmc3 6p", "mmc3 10p"};
-static const char * const p910_uart0_grps[] = {"uart0 4p"};
-static const char * const p910_uart1_grps[] = {"uart1 2p1", "uart1 2p2",
-       "uart1 2p3", "uart1 4p4", "uart1 4p5"};
-static const char * const p910_uart2_grps[] = {"uart2 2p1", "uart2 2p2",
-       "uart2 4p3", "uart2 4p4"};
-static const char * const p910_twsi_grps[] = {"twsi 2p1", "twsi 2p2",
-       "twsi 2p3"};
-static const char * const p910_ccic_grps[] = {"ccic"};
-static const char * const p910_lcd_grps[] = {"lcd"};
-static const char * const p910_spi_grps[] = {"spi 4p1", "spi 4p2", "spi 5p3",
-       "spi 5p4"};
-static const char * const p910_dssp2_grps[] = {"dssp2 4p1", "dssp2 4p2",
-       "dssp2 3p3"};
-static const char * const p910_dssp3_grps[] = {"dssp3 4p1", "dssp3 4p2",
-       "dssp3 3p3"};
-static const char * const p910_ssp0_grps[] = {"ssp0 4p1", "ssp0 4p2",
-       "ssp0 4p3", "ssp0 4p4"};
-static const char * const p910_ssp1_grps[] = {"ssp1 4p1", "ssp1 5p2"};
-static const char * const p910_ssp2_grps[] = {"ssp2 4p1", "ssp2 4p2",
-       "ssp2 4p3", "ssp2 4p4"};
-static const char * const p910_gssp_grps[] = {"gssp"};
-static const char * const p910_pwm0_grps[] = {"pwm0"};
-static const char * const p910_pwm1_grps[] = {"pwm1-1", "pwm1-2"};
-static const char * const p910_pwm2_grps[] = {"pwm2"};
-static const char * const p910_pwm3_grps[] = {"pwm3-1", "pwm3-2", "pwm3-3"};
-static const char * const p910_pri_jtag_grps[] = {"pri jtag"};
-static const char * const p910_sec1_jtag_grps[] = {"sec1 jtag"};
-static const char * const p910_sec2_jtag_grps[] = {"sec2 jtag"};
-static const char * const p910_hsl_grps[] = {"hsl 6p1", "hsl 6p2", "hsl 6p3"};
-static const char * const p910_w1_grps[] = {"w1-1", "w1-2", "w1-3", "w1-4"};
-static const char * const p910_kpmk_grps[] = {"kpmk 16p1", "kpmk 11p2"};
-static const char * const p910_kpdk_grps[] = {"kpdk 8p1"};
-static const char * const p910_tds_grps[] = {"tds 5p1", "tds 4p2"};
-static const char * const p910_tb_grps[] = {"tb 4p1", "tb 4p2", "tb 4p3"};
-static const char * const p910_dma0_grps[] = {"ext dma0-1", "ext dma0-2",
-       "ext dma0-3"};
-static const char * const p910_dma1_grps[] = {"ext dma1-1", "ext dma1-2",
-       "ext dma1-3"};
-static const char * const p910_dma2_grps[] = {"ext dma2"};
-static const char * const p910_int0_grps[] = {"ext0 int-1", "ext0 int-2"};
-static const char * const p910_int1_grps[] = {"ext1 int-1", "ext1 int-2"};
-static const char * const p910_int2_grps[] = {"ext2 int-1", "ext2 int-2"};
-static const char * const p910_dac_st23_grps[] = {"dac st23-1", "dac st23-2",
-       "dac st23-3", "dac st23-4"};
-static const char * const p910_vcxo_out_grps[] = {"vcxo out-1", "vcxo out-2",
-       "vcxo out-3"};
-static const char * const p910_vcxo_req_grps[] = {"vcxo req-1", "vcxo req-2"};
-static const char * const p910_vcxo_out2_grps[] = {"vcxo out2-1",
-       "vcxo out2-2"};
-static const char * const p910_vcxo_req2_grps[] = {"vcxo req2"};
-static const char * const p910_ulpi_grps[] = {"ulpi"};
-static const char * const p910_nand_grps[] = {"nand"};
-static const char * const p910_gpio0_grps[] = {"gpio0-1", "gpio0-2"};
-static const char * const p910_gpio1_grps[] = {"gpio1-1", "gpio1-2"};
-static const char * const p910_gpio2_grps[] = {"gpio2-1", "gpio2-2"};
-static const char * const p910_gpio3_grps[] = {"gpio3-1", "gpio3-2"};
-static const char * const p910_gpio20_grps[] = {"gpio20-1", "gpio20-2"};
-static const char * const p910_gpio21_grps[] = {"gpio21-1", "gpio21-2"};
-static const char * const p910_gpio22_grps[] = {"gpio22-1", "gpio22-2"};
-static const char * const p910_gpio23_grps[] = {"gpio23-1", "gpio23-2"};
-static const char * const p910_gpio24_grps[] = {"gpio24-1", "gpio24-2"};
-static const char * const p910_gpio25_grps[] = {"gpio25-1", "gpio25-2"};
-static const char * const p910_gpio26_grps[] = {"gpio26-1", "gpio26-2"};
-static const char * const p910_gpio27_grps[] = {"gpio27-1", "gpio27-2"};
-static const char * const p910_gpio85_grps[] = {"gpio85-1", "gpio85-2"};
-static const char * const p910_gpio86_grps[] = {"gpio86-1", "gpio86-2"};
-static const char * const p910_gpio87_grps[] = {"gpio87-1", "gpio87-2"};
-static const char * const p910_gpio88_grps[] = {"gpio88-1", "gpio88-2"};
-static const char * const p910_gpio89_grps[] = {"gpio89-1", "gpio89-2"};
-static const char * const p910_gpio90_grps[] = {"gpio90-1", "gpio90-2"};
-static const char * const p910_gpio91_grps[] = {"gpio91-1", "gpio91-2"};
-static const char * const p910_gpio92_grps[] = {"gpio92-1", "gpio92-2"};
-
-static struct pxa3xx_pmx_func pxa910_funcs[] = {
-       {"usim2",       ARRAY_AND_SIZE(p910_usim2_grps)},
-       {"mmc1",        ARRAY_AND_SIZE(p910_mmc1_grps)},
-       {"mmc2",        ARRAY_AND_SIZE(p910_mmc2_grps)},
-       {"mmc3",        ARRAY_AND_SIZE(p910_mmc3_grps)},
-       {"uart0",       ARRAY_AND_SIZE(p910_uart0_grps)},
-       {"uart1",       ARRAY_AND_SIZE(p910_uart1_grps)},
-       {"uart2",       ARRAY_AND_SIZE(p910_uart2_grps)},
-       {"twsi",        ARRAY_AND_SIZE(p910_twsi_grps)},
-       {"ccic",        ARRAY_AND_SIZE(p910_ccic_grps)},
-       {"lcd",         ARRAY_AND_SIZE(p910_lcd_grps)},
-       {"spi",         ARRAY_AND_SIZE(p910_spi_grps)},
-       {"dssp2",       ARRAY_AND_SIZE(p910_dssp2_grps)},
-       {"dssp3",       ARRAY_AND_SIZE(p910_dssp3_grps)},
-       {"ssp0",        ARRAY_AND_SIZE(p910_ssp0_grps)},
-       {"ssp1",        ARRAY_AND_SIZE(p910_ssp1_grps)},
-       {"ssp2",        ARRAY_AND_SIZE(p910_ssp2_grps)},
-       {"gssp",        ARRAY_AND_SIZE(p910_gssp_grps)},
-       {"pwm0",        ARRAY_AND_SIZE(p910_pwm0_grps)},
-       {"pwm1",        ARRAY_AND_SIZE(p910_pwm1_grps)},
-       {"pwm2",        ARRAY_AND_SIZE(p910_pwm2_grps)},
-       {"pwm3",        ARRAY_AND_SIZE(p910_pwm3_grps)},
-       {"pri_jtag",    ARRAY_AND_SIZE(p910_pri_jtag_grps)},
-       {"sec1_jtag",   ARRAY_AND_SIZE(p910_sec1_jtag_grps)},
-       {"sec2_jtag",   ARRAY_AND_SIZE(p910_sec2_jtag_grps)},
-       {"hsl",         ARRAY_AND_SIZE(p910_hsl_grps)},
-       {"w1",          ARRAY_AND_SIZE(p910_w1_grps)},
-       {"kpmk",        ARRAY_AND_SIZE(p910_kpmk_grps)},
-       {"kpdk",        ARRAY_AND_SIZE(p910_kpdk_grps)},
-       {"tds",         ARRAY_AND_SIZE(p910_tds_grps)},
-       {"tb",          ARRAY_AND_SIZE(p910_tb_grps)},
-       {"dma0",        ARRAY_AND_SIZE(p910_dma0_grps)},
-       {"dma1",        ARRAY_AND_SIZE(p910_dma1_grps)},
-       {"dma2",        ARRAY_AND_SIZE(p910_dma2_grps)},
-       {"int0",        ARRAY_AND_SIZE(p910_int0_grps)},
-       {"int1",        ARRAY_AND_SIZE(p910_int1_grps)},
-       {"int2",        ARRAY_AND_SIZE(p910_int2_grps)},
-       {"dac_st23",    ARRAY_AND_SIZE(p910_dac_st23_grps)},
-       {"vcxo_out",    ARRAY_AND_SIZE(p910_vcxo_out_grps)},
-       {"vcxo_req",    ARRAY_AND_SIZE(p910_vcxo_req_grps)},
-       {"vcxo_out2",   ARRAY_AND_SIZE(p910_vcxo_out2_grps)},
-       {"vcxo_req2",   ARRAY_AND_SIZE(p910_vcxo_req2_grps)},
-       {"ulpi",        ARRAY_AND_SIZE(p910_ulpi_grps)},
-       {"nand",        ARRAY_AND_SIZE(p910_nand_grps)},
-       {"gpio0",       ARRAY_AND_SIZE(p910_gpio0_grps)},
-       {"gpio1",       ARRAY_AND_SIZE(p910_gpio1_grps)},
-       {"gpio2",       ARRAY_AND_SIZE(p910_gpio2_grps)},
-       {"gpio3",       ARRAY_AND_SIZE(p910_gpio3_grps)},
-       {"gpio20",      ARRAY_AND_SIZE(p910_gpio20_grps)},
-       {"gpio21",      ARRAY_AND_SIZE(p910_gpio21_grps)},
-       {"gpio22",      ARRAY_AND_SIZE(p910_gpio22_grps)},
-       {"gpio23",      ARRAY_AND_SIZE(p910_gpio23_grps)},
-       {"gpio24",      ARRAY_AND_SIZE(p910_gpio24_grps)},
-       {"gpio25",      ARRAY_AND_SIZE(p910_gpio25_grps)},
-       {"gpio26",      ARRAY_AND_SIZE(p910_gpio26_grps)},
-       {"gpio27",      ARRAY_AND_SIZE(p910_gpio27_grps)},
-       {"gpio85",      ARRAY_AND_SIZE(p910_gpio85_grps)},
-       {"gpio86",      ARRAY_AND_SIZE(p910_gpio86_grps)},
-       {"gpio87",      ARRAY_AND_SIZE(p910_gpio87_grps)},
-       {"gpio88",      ARRAY_AND_SIZE(p910_gpio88_grps)},
-       {"gpio89",      ARRAY_AND_SIZE(p910_gpio89_grps)},
-       {"gpio90",      ARRAY_AND_SIZE(p910_gpio90_grps)},
-       {"gpio91",      ARRAY_AND_SIZE(p910_gpio91_grps)},
-       {"gpio92",      ARRAY_AND_SIZE(p910_gpio92_grps)},
-};
-
-static struct pinctrl_desc pxa910_pctrl_desc = {
-       .name           = "pxa910-pinctrl",
-       .owner          = THIS_MODULE,
-};
-
-static struct pxa3xx_pinmux_info pxa910_info = {
-       .mfp            = pxa910_mfp,
-       .num_mfp        = ARRAY_SIZE(pxa910_mfp),
-       .grps           = pxa910_grps,
-       .num_grps       = ARRAY_SIZE(pxa910_grps),
-       .funcs          = pxa910_funcs,
-       .num_funcs      = ARRAY_SIZE(pxa910_funcs),
-       .num_gpio       = 128,
-       .desc           = &pxa910_pctrl_desc,
-       .pads           = pxa910_pads,
-       .num_pads       = ARRAY_SIZE(pxa910_pads),
-
-       .cputype        = PINCTRL_PXA910,
-       .ds_mask        = PXA910_DS_MASK,
-       .ds_shift       = PXA910_DS_SHIFT,
-};
-
-static int pxa910_pinmux_probe(struct platform_device *pdev)
-{
-       return pxa3xx_pinctrl_register(pdev, &pxa910_info);
-}
-
-static int pxa910_pinmux_remove(struct platform_device *pdev)
-{
-       return pxa3xx_pinctrl_unregister(pdev);
-}
-
-static struct platform_driver pxa910_pinmux_driver = {
-       .driver = {
-               .name   = "pxa910-pinmux",
-               .owner  = THIS_MODULE,
-       },
-       .probe  = pxa910_pinmux_probe,
-       .remove = pxa910_pinmux_remove,
-};
-
-static int __init pxa910_pinmux_init(void)
-{
-       return platform_driver_register(&pxa910_pinmux_driver);
-}
-core_initcall_sync(pxa910_pinmux_init);
-
-static void __exit pxa910_pinmux_exit(void)
-{
-       platform_driver_unregister(&pxa910_pinmux_driver);
-}
-module_exit(pxa910_pinmux_exit);
-
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_DESCRIPTION("PXA3xx pin control driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-s3c64xx.c b/drivers/pinctrl/pinctrl-s3c64xx.c
new file mode 100644 (file)
index 0000000..89143c9
--- /dev/null
@@ -0,0 +1,816 @@
+/*
+ * S3C64xx specific support for pinctrl-samsung driver.
+ *
+ * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
+ *
+ * Based on pinctrl-exynos.c, please see the file for original copyrights.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This file contains the Samsung S3C64xx specific information required by the
+ * the Samsung pinctrl/gpiolib driver. It also includes the implementation of
+ * external gpio and wakeup interrupt support.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include "pinctrl-samsung.h"
+
+#define NUM_EINT0              28
+#define NUM_EINT0_IRQ          4
+#define EINT_MAX_PER_REG       16
+#define EINT_MAX_PER_GROUP     16
+
+/* External GPIO and wakeup interrupt related definitions */
+#define SVC_GROUP_SHIFT                4
+#define SVC_GROUP_MASK         0xf
+#define SVC_NUM_MASK           0xf
+#define SVC_GROUP(x)           ((x >> SVC_GROUP_SHIFT) & \
+                                               SVC_GROUP_MASK)
+
+#define EINT12CON_REG          0x200
+#define EINT12MASK_REG         0x240
+#define EINT12PEND_REG         0x260
+
+#define EINT_OFFS(i)           ((i) % (2 * EINT_MAX_PER_GROUP))
+#define EINT_GROUP(i)          ((i) / EINT_MAX_PER_GROUP)
+#define EINT_REG(g)            (4 * ((g) / 2))
+
+#define EINTCON_REG(i)         (EINT12CON_REG + EINT_REG(EINT_GROUP(i)))
+#define EINTMASK_REG(i)                (EINT12MASK_REG + EINT_REG(EINT_GROUP(i)))
+#define EINTPEND_REG(i)                (EINT12PEND_REG + EINT_REG(EINT_GROUP(i)))
+
+#define SERVICE_REG            0x284
+#define SERVICEPEND_REG                0x288
+
+#define EINT0CON0_REG          0x900
+#define EINT0MASK_REG          0x920
+#define EINT0PEND_REG          0x924
+
+/* S3C64xx specific external interrupt trigger types */
+#define EINT_LEVEL_LOW         0
+#define EINT_LEVEL_HIGH                1
+#define EINT_EDGE_FALLING      2
+#define EINT_EDGE_RISING       4
+#define EINT_EDGE_BOTH         6
+#define EINT_CON_MASK          0xF
+#define EINT_CON_LEN           4
+
+static struct samsung_pin_bank_type bank_type_4bit_off = {
+       .fld_width = { 4, 1, 2, 0, 2, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
+};
+
+static struct samsung_pin_bank_type bank_type_4bit_alive = {
+       .fld_width = { 4, 1, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, },
+};
+
+static struct samsung_pin_bank_type bank_type_4bit2_off = {
+       .fld_width = { 4, 1, 2, 0, 2, 2, },
+       .reg_offset = { 0x00, 0x08, 0x0c, 0, 0x10, 0x14, },
+};
+
+static struct samsung_pin_bank_type bank_type_4bit2_alive = {
+       .fld_width = { 4, 1, 2, },
+       .reg_offset = { 0x00, 0x08, 0x0c, },
+};
+
+static struct samsung_pin_bank_type bank_type_2bit_off = {
+       .fld_width = { 2, 1, 2, 0, 2, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
+};
+
+static struct samsung_pin_bank_type bank_type_2bit_alive = {
+       .fld_width = { 2, 1, 2, },
+       .reg_offset = { 0x00, 0x04, 0x08, },
+};
+
+#define PIN_BANK_4BIT(pins, reg, id)                   \
+       {                                               \
+               .type           = &bank_type_4bit_off,  \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_NONE,       \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_4BIT_EINTG(pins, reg, id, eoffs)      \
+       {                                               \
+               .type           = &bank_type_4bit_off,  \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_GPIO,       \
+               .eint_func      = 7,                    \
+               .eint_mask      = (1 << (pins)) - 1,    \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_4BIT_EINTW(pins, reg, id, eoffs, emask) \
+       {                                               \
+               .type           = &bank_type_4bit_alive,\
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_WKUP,       \
+               .eint_func      = 3,                    \
+               .eint_mask      = emask,                \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_4BIT2_EINTG(pins, reg, id, eoffs)     \
+       {                                               \
+               .type           = &bank_type_4bit2_off, \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_GPIO,       \
+               .eint_func      = 7,                    \
+               .eint_mask      = (1 << (pins)) - 1,    \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_4BIT2_EINTW(pins, reg, id, eoffs, emask) \
+       {                                               \
+               .type           = &bank_type_4bit2_alive,\
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_WKUP,       \
+               .eint_func      = 3,                    \
+               .eint_mask      = emask,                \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_4BIT2_ALIVE(pins, reg, id)            \
+       {                                               \
+               .type           = &bank_type_4bit2_alive,\
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_NONE,       \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_2BIT(pins, reg, id)                   \
+       {                                               \
+               .type           = &bank_type_2bit_off,  \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_NONE,       \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_2BIT_EINTG(pins, reg, id, eoffs, emask) \
+       {                                               \
+               .type           = &bank_type_2bit_off,  \
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_GPIO,       \
+               .eint_func      = 3,                    \
+               .eint_mask      = emask,                \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+#define PIN_BANK_2BIT_EINTW(pins, reg, id, eoffs)      \
+       {                                               \
+               .type           = &bank_type_2bit_alive,\
+               .pctl_offset    = reg,                  \
+               .nr_pins        = pins,                 \
+               .eint_type      = EINT_TYPE_WKUP,       \
+               .eint_func      = 2,                    \
+               .eint_mask      = (1 << (pins)) - 1,    \
+               .eint_offset    = eoffs,                \
+               .name           = id                    \
+       }
+
+/**
+ * struct s3c64xx_eint0_data: EINT0 common data
+ * @drvdata: pin controller driver data
+ * @domains: IRQ domains of particular EINT0 interrupts
+ * @pins: pin offsets inside of banks of particular EINT0 interrupts
+ */
+struct s3c64xx_eint0_data {
+       struct samsung_pinctrl_drv_data *drvdata;
+       struct irq_domain *domains[NUM_EINT0];
+       u8 pins[NUM_EINT0];
+};
+
+/**
+ * struct s3c64xx_eint0_domain_data: EINT0 per-domain data
+ * @bank: pin bank related to the domain
+ * @eints: EINT0 interrupts related to the domain
+ */
+struct s3c64xx_eint0_domain_data {
+       struct samsung_pin_bank *bank;
+       u8 eints[];
+};
+
+/**
+ * struct s3c64xx_eint_gpio_data: GPIO EINT data
+ * @drvdata: pin controller driver data
+ * @domains: array of domains related to EINT interrupt groups
+ */
+struct s3c64xx_eint_gpio_data {
+       struct samsung_pinctrl_drv_data *drvdata;
+       struct irq_domain *domains[];
+};
+
+/*
+ * Common functions for S3C64xx EINT configuration
+ */
+
+static int s3c64xx_irq_get_trigger(unsigned int type)
+{
+       int trigger;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               trigger = EINT_EDGE_RISING;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               trigger = EINT_EDGE_FALLING;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               trigger = EINT_EDGE_BOTH;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               trigger = EINT_LEVEL_HIGH;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               trigger = EINT_LEVEL_LOW;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return trigger;
+}
+
+static void s3c64xx_irq_set_handler(unsigned int irq, unsigned int type)
+{
+       /* Edge- and level-triggered interrupts need different handlers */
+       if (type & IRQ_TYPE_EDGE_BOTH)
+               __irq_set_handler_locked(irq, handle_edge_irq);
+       else
+               __irq_set_handler_locked(irq, handle_level_irq);
+}
+
+static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d,
+                                       struct samsung_pin_bank *bank, int pin)
+{
+       struct samsung_pin_bank_type *bank_type = bank->type;
+       unsigned long flags;
+       void __iomem *reg;
+       u8 shift;
+       u32 mask;
+       u32 val;
+
+       /* Make sure that pin is configured as interrupt */
+       reg = d->virt_base + bank->pctl_offset;
+       shift = pin;
+       if (bank_type->fld_width[PINCFG_TYPE_FUNC] * shift >= 32) {
+               /* 4-bit bank type with 2 con regs */
+               reg += 4;
+               shift -= 8;
+       }
+
+       shift = shift * bank_type->fld_width[PINCFG_TYPE_FUNC];
+       mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       val = readl(reg);
+       val &= ~(mask << shift);
+       val |= bank->eint_func << shift;
+       writel(val, reg);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+}
+
+/*
+ * Functions for EINT GPIO configuration (EINT groups 1-9)
+ */
+
+static inline void s3c64xx_gpio_irq_set_mask(struct irq_data *irqd, bool mask)
+{
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
+       void __iomem *reg = d->virt_base + EINTMASK_REG(bank->eint_offset);
+       u32 val;
+
+       val = readl(reg);
+       if (mask)
+               val |= 1 << index;
+       else
+               val &= ~(1 << index);
+       writel(val, reg);
+}
+
+static void s3c64xx_gpio_irq_unmask(struct irq_data *irqd)
+{
+       s3c64xx_gpio_irq_set_mask(irqd, false);
+}
+
+static void s3c64xx_gpio_irq_mask(struct irq_data *irqd)
+{
+       s3c64xx_gpio_irq_set_mask(irqd, true);
+}
+
+static void s3c64xx_gpio_irq_ack(struct irq_data *irqd)
+{
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
+       void __iomem *reg = d->virt_base + EINTPEND_REG(bank->eint_offset);
+
+       writel(1 << index, reg);
+}
+
+static int s3c64xx_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       void __iomem *reg;
+       int trigger;
+       u8 shift;
+       u32 val;
+
+       trigger = s3c64xx_irq_get_trigger(type);
+       if (trigger < 0) {
+               pr_err("unsupported external interrupt type\n");
+               return -EINVAL;
+       }
+
+       s3c64xx_irq_set_handler(irqd->irq, type);
+
+       /* Set up interrupt trigger */
+       reg = d->virt_base + EINTCON_REG(bank->eint_offset);
+       shift = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
+       shift = 4 * (shift / 4); /* 4 EINTs per trigger selector */
+
+       val = readl(reg);
+       val &= ~(EINT_CON_MASK << shift);
+       val |= trigger << shift;
+       writel(val, reg);
+
+       s3c64xx_irq_set_function(d, bank, irqd->hwirq);
+
+       return 0;
+}
+
+/*
+ * irq_chip for gpio interrupts.
+ */
+static struct irq_chip s3c64xx_gpio_irq_chip = {
+       .name           = "GPIO",
+       .irq_unmask     = s3c64xx_gpio_irq_unmask,
+       .irq_mask       = s3c64xx_gpio_irq_mask,
+       .irq_ack        = s3c64xx_gpio_irq_ack,
+       .irq_set_type   = s3c64xx_gpio_irq_set_type,
+};
+
+static int s3c64xx_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+                                       irq_hw_number_t hw)
+{
+       struct samsung_pin_bank *bank = h->host_data;
+
+       if (!(bank->eint_mask & (1 << hw)))
+               return -EINVAL;
+
+       irq_set_chip_and_handler(virq,
+                               &s3c64xx_gpio_irq_chip, handle_level_irq);
+       irq_set_chip_data(virq, bank);
+       set_irq_flags(virq, IRQF_VALID);
+
+       return 0;
+}
+
+/*
+ * irq domain callbacks for external gpio interrupt controller.
+ */
+static const struct irq_domain_ops s3c64xx_gpio_irqd_ops = {
+       .map    = s3c64xx_gpio_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+static void s3c64xx_eint_gpio_irq(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_get_chip(irq);
+       struct s3c64xx_eint_gpio_data *data = irq_get_handler_data(irq);
+       struct samsung_pinctrl_drv_data *drvdata = data->drvdata;
+
+       chained_irq_enter(chip, desc);
+
+       do {
+               unsigned int svc;
+               unsigned int group;
+               unsigned int pin;
+               unsigned int virq;
+
+               svc = readl(drvdata->virt_base + SERVICE_REG);
+               group = SVC_GROUP(svc);
+               pin = svc & SVC_NUM_MASK;
+
+               if (!group)
+                       break;
+
+               /* Group 1 is used for two pin banks */
+               if (group == 1) {
+                       if (pin < 8)
+                               group = 0;
+                       else
+                               pin -= 8;
+               }
+
+               virq = irq_linear_revmap(data->domains[group], pin);
+               /*
+                * Something must be really wrong if an unmapped EINT
+                * was unmasked...
+                */
+               BUG_ON(!virq);
+
+               generic_handle_irq(virq);
+       } while (1);
+
+       chained_irq_exit(chip, desc);
+}
+
+/**
+ * s3c64xx_eint_gpio_init() - setup handling of external gpio interrupts.
+ * @d: driver data of samsung pinctrl driver.
+ */
+static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
+{
+       struct s3c64xx_eint_gpio_data *data;
+       struct samsung_pin_bank *bank;
+       struct device *dev = d->dev;
+       unsigned int nr_domains;
+       unsigned int i;
+
+       if (!d->irq) {
+               dev_err(dev, "irq number not available\n");
+               return -EINVAL;
+       }
+
+       nr_domains = 0;
+       bank = d->ctrl->pin_banks;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               unsigned int nr_eints;
+               unsigned int mask;
+
+               if (bank->eint_type != EINT_TYPE_GPIO)
+                       continue;
+
+               mask = bank->eint_mask;
+               nr_eints = fls(mask);
+
+               bank->irq_domain = irq_domain_add_linear(bank->of_node,
+                                       nr_eints, &s3c64xx_gpio_irqd_ops, bank);
+               if (!bank->irq_domain) {
+                       dev_err(dev, "gpio irq domain add failed\n");
+                       return -ENXIO;
+               }
+
+               ++nr_domains;
+       }
+
+       data = devm_kzalloc(dev, sizeof(*data)
+                       + nr_domains * sizeof(*data->domains), GFP_KERNEL);
+       if (!data) {
+               dev_err(dev, "failed to allocate handler data\n");
+               return -ENOMEM;
+       }
+       data->drvdata = d;
+
+       bank = d->ctrl->pin_banks;
+       nr_domains = 0;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               if (bank->eint_type != EINT_TYPE_GPIO)
+                       continue;
+
+               data->domains[nr_domains++] = bank->irq_domain;
+       }
+
+       irq_set_chained_handler(d->irq, s3c64xx_eint_gpio_irq);
+       irq_set_handler_data(d->irq, data);
+
+       return 0;
+}
+
+/*
+ * Functions for configuration of EINT0 wake-up interrupts
+ */
+
+static inline void s3c64xx_eint0_irq_set_mask(struct irq_data *irqd, bool mask)
+{
+       struct s3c64xx_eint0_domain_data *ddata =
+                                       irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata;
+       u32 val;
+
+       val = readl(d->virt_base + EINT0MASK_REG);
+       if (mask)
+               val |= 1 << ddata->eints[irqd->hwirq];
+       else
+               val &= ~(1 << ddata->eints[irqd->hwirq]);
+       writel(val, d->virt_base + EINT0MASK_REG);
+}
+
+static void s3c64xx_eint0_irq_unmask(struct irq_data *irqd)
+{
+       s3c64xx_eint0_irq_set_mask(irqd, false);
+}
+
+static void s3c64xx_eint0_irq_mask(struct irq_data *irqd)
+{
+       s3c64xx_eint0_irq_set_mask(irqd, true);
+}
+
+static void s3c64xx_eint0_irq_ack(struct irq_data *irqd)
+{
+       struct s3c64xx_eint0_domain_data *ddata =
+                                       irq_data_get_irq_chip_data(irqd);
+       struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata;
+
+       writel(1 << ddata->eints[irqd->hwirq],
+                                       d->virt_base + EINT0PEND_REG);
+}
+
+static int s3c64xx_eint0_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+       struct s3c64xx_eint0_domain_data *ddata =
+                                       irq_data_get_irq_chip_data(irqd);
+       struct samsung_pin_bank *bank = ddata->bank;
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       void __iomem *reg;
+       int trigger;
+       u8 shift;
+       u32 val;
+
+       trigger = s3c64xx_irq_get_trigger(type);
+       if (trigger < 0) {
+               pr_err("unsupported external interrupt type\n");
+               return -EINVAL;
+       }
+
+       s3c64xx_irq_set_handler(irqd->irq, type);
+
+       /* Set up interrupt trigger */
+       reg = d->virt_base + EINT0CON0_REG;
+       shift = ddata->eints[irqd->hwirq];
+       if (shift >= EINT_MAX_PER_REG) {
+               reg += 4;
+               shift -= EINT_MAX_PER_REG;
+       }
+       shift = EINT_CON_LEN * (shift / 2);
+
+       val = readl(reg);
+       val &= ~(EINT_CON_MASK << shift);
+       val |= trigger << shift;
+       writel(val, reg);
+
+       s3c64xx_irq_set_function(d, bank, irqd->hwirq);
+
+       return 0;
+}
+
+/*
+ * irq_chip for wakeup interrupts
+ */
+static struct irq_chip s3c64xx_eint0_irq_chip = {
+       .name           = "EINT0",
+       .irq_unmask     = s3c64xx_eint0_irq_unmask,
+       .irq_mask       = s3c64xx_eint0_irq_mask,
+       .irq_ack        = s3c64xx_eint0_irq_ack,
+       .irq_set_type   = s3c64xx_eint0_irq_set_type,
+};
+
+static inline void s3c64xx_irq_demux_eint(unsigned int irq,
+                                       struct irq_desc *desc, u32 range)
+{
+       struct irq_chip *chip = irq_get_chip(irq);
+       struct s3c64xx_eint0_data *data = irq_get_handler_data(irq);
+       struct samsung_pinctrl_drv_data *drvdata = data->drvdata;
+       unsigned int pend, mask;
+
+       chained_irq_enter(chip, desc);
+
+       pend = readl(drvdata->virt_base + EINT0PEND_REG);
+       mask = readl(drvdata->virt_base + EINT0MASK_REG);
+
+       pend = pend & range & ~mask;
+       pend &= range;
+
+       while (pend) {
+               unsigned int virq;
+
+               irq = fls(pend) - 1;
+               pend &= ~(1 << irq);
+
+               virq = irq_linear_revmap(data->domains[irq], data->pins[irq]);
+               /*
+                * Something must be really wrong if an unmapped EINT
+                * was unmasked...
+                */
+               BUG_ON(!virq);
+
+               generic_handle_irq(virq);
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static void s3c64xx_demux_eint0_3(unsigned int irq, struct irq_desc *desc)
+{
+       s3c64xx_irq_demux_eint(irq, desc, 0xf);
+}
+
+static void s3c64xx_demux_eint4_11(unsigned int irq, struct irq_desc *desc)
+{
+       s3c64xx_irq_demux_eint(irq, desc, 0xff0);
+}
+
+static void s3c64xx_demux_eint12_19(unsigned int irq, struct irq_desc *desc)
+{
+       s3c64xx_irq_demux_eint(irq, desc, 0xff000);
+}
+
+static void s3c64xx_demux_eint20_27(unsigned int irq, struct irq_desc *desc)
+{
+       s3c64xx_irq_demux_eint(irq, desc, 0xff00000);
+}
+
+static irq_flow_handler_t s3c64xx_eint0_handlers[NUM_EINT0_IRQ] = {
+       s3c64xx_demux_eint0_3,
+       s3c64xx_demux_eint4_11,
+       s3c64xx_demux_eint12_19,
+       s3c64xx_demux_eint20_27,
+};
+
+static int s3c64xx_eint0_irq_map(struct irq_domain *h, unsigned int virq,
+                                       irq_hw_number_t hw)
+{
+       struct s3c64xx_eint0_domain_data *ddata = h->host_data;
+       struct samsung_pin_bank *bank = ddata->bank;
+
+       if (!(bank->eint_mask & (1 << hw)))
+               return -EINVAL;
+
+       irq_set_chip_and_handler(virq,
+                               &s3c64xx_eint0_irq_chip, handle_level_irq);
+       irq_set_chip_data(virq, ddata);
+       set_irq_flags(virq, IRQF_VALID);
+
+       return 0;
+}
+
+/*
+ * irq domain callbacks for external wakeup interrupt controller.
+ */
+static const struct irq_domain_ops s3c64xx_eint0_irqd_ops = {
+       .map    = s3c64xx_eint0_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+/* list of external wakeup controllers supported */
+static const struct of_device_id s3c64xx_eint0_irq_ids[] = {
+       { .compatible = "samsung,s3c64xx-wakeup-eint", },
+       { }
+};
+
+/**
+ * s3c64xx_eint_eint0_init() - setup handling of external wakeup interrupts.
+ * @d: driver data of samsung pinctrl driver.
+ */
+static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d)
+{
+       struct device *dev = d->dev;
+       struct device_node *eint0_np = NULL;
+       struct device_node *np;
+       struct samsung_pin_bank *bank;
+       struct s3c64xx_eint0_data *data;
+       unsigned int i;
+
+       for_each_child_of_node(dev->of_node, np) {
+               if (of_match_node(s3c64xx_eint0_irq_ids, np)) {
+                       eint0_np = np;
+                       break;
+               }
+       }
+       if (!eint0_np)
+               return -ENODEV;
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               dev_err(dev, "could not allocate memory for wkup eint data\n");
+               return -ENOMEM;
+       }
+       data->drvdata = d;
+
+       for (i = 0; i < NUM_EINT0_IRQ; ++i) {
+               unsigned int irq;
+
+               irq = irq_of_parse_and_map(eint0_np, i);
+               if (!irq) {
+                       dev_err(dev, "failed to get wakeup EINT IRQ %d\n", i);
+                       return -ENXIO;
+               }
+
+               irq_set_chained_handler(irq, s3c64xx_eint0_handlers[i]);
+               irq_set_handler_data(irq, data);
+       }
+
+       bank = d->ctrl->pin_banks;
+       for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+               struct s3c64xx_eint0_domain_data *ddata;
+               unsigned int nr_eints;
+               unsigned int mask;
+               unsigned int irq;
+               unsigned int pin;
+
+               if (bank->eint_type != EINT_TYPE_WKUP)
+                       continue;
+
+               mask = bank->eint_mask;
+               nr_eints = fls(mask);
+
+               ddata = devm_kzalloc(dev,
+                               sizeof(*ddata) + nr_eints, GFP_KERNEL);
+               if (!ddata) {
+                       dev_err(dev, "failed to allocate domain data\n");
+                       return -ENOMEM;
+               }
+               ddata->bank = bank;
+
+               bank->irq_domain = irq_domain_add_linear(bank->of_node,
+                               nr_eints, &s3c64xx_eint0_irqd_ops, ddata);
+               if (!bank->irq_domain) {
+                       dev_err(dev, "wkup irq domain add failed\n");
+                       return -ENXIO;
+               }
+
+               irq = bank->eint_offset;
+               mask = bank->eint_mask;
+               for (pin = 0; mask; ++pin, mask >>= 1) {
+                       if (!(mask & 1))
+                               continue;
+                       data->domains[irq] = bank->irq_domain;
+                       data->pins[irq] = pin;
+                       ddata->eints[pin] = irq;
+                       ++irq;
+               }
+       }
+
+       return 0;
+}
+
+/* pin banks of s3c64xx pin-controller 0 */
+static struct samsung_pin_bank s3c64xx_pin_banks0[] = {
+       PIN_BANK_4BIT_EINTG(8, 0x000, "gpa", 0),
+       PIN_BANK_4BIT_EINTG(7, 0x020, "gpb", 8),
+       PIN_BANK_4BIT_EINTG(8, 0x040, "gpc", 16),
+       PIN_BANK_4BIT_EINTG(5, 0x060, "gpd", 32),
+       PIN_BANK_4BIT(5, 0x080, "gpe"),
+       PIN_BANK_2BIT_EINTG(16, 0x0a0, "gpf", 48, 0x3fff),
+       PIN_BANK_4BIT_EINTG(7, 0x0c0, "gpg", 64),
+       PIN_BANK_4BIT2_EINTG(10, 0x0e0, "gph", 80),
+       PIN_BANK_2BIT(16, 0x100, "gpi"),
+       PIN_BANK_2BIT(12, 0x120, "gpj"),
+       PIN_BANK_4BIT2_ALIVE(16, 0x800, "gpk"),
+       PIN_BANK_4BIT2_EINTW(15, 0x810, "gpl", 16, 0x7f00),
+       PIN_BANK_4BIT_EINTW(6, 0x820, "gpm", 23, 0x1f),
+       PIN_BANK_2BIT_EINTW(16, 0x830, "gpn", 0),
+       PIN_BANK_2BIT_EINTG(16, 0x140, "gpo", 96, 0xffff),
+       PIN_BANK_2BIT_EINTG(15, 0x160, "gpp", 112, 0x7fff),
+       PIN_BANK_2BIT_EINTG(9, 0x180, "gpq", 128, 0x1ff),
+};
+
+/*
+ * Samsung pinctrl driver data for S3C64xx SoC. S3C64xx SoC includes
+ * one gpio/pin-mux/pinconfig controller.
+ */
+struct samsung_pin_ctrl s3c64xx_pin_ctrl[] = {
+       {
+               /* pin-controller instance 1 data */
+               .pin_banks      = s3c64xx_pin_banks0,
+               .nr_banks       = ARRAY_SIZE(s3c64xx_pin_banks0),
+               .eint_gpio_init = s3c64xx_eint_gpio_init,
+               .eint_wkup_init = s3c64xx_eint_eint0_init,
+               .label          = "S3C64xx-GPIO",
+       },
+};
index f206df1..4f54faf 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/irqdomain.h>
+#include <linux/spinlock.h>
 
 #include "core.h"
 #include "pinctrl-samsung.h"
@@ -214,7 +215,7 @@ static void samsung_dt_free_map(struct pinctrl_dev *pctldev,
 }
 
 /* list of pinctrl callbacks for the pinctrl core */
-static struct pinctrl_ops samsung_pctrl_ops = {
+static const struct pinctrl_ops samsung_pctrl_ops = {
        .get_groups_count       = samsung_get_group_count,
        .get_group_name         = samsung_get_group_name,
        .get_group_pins         = samsung_get_group_pins,
@@ -274,10 +275,6 @@ static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata,
        *offset = pin - b->pin_base;
        if (bank)
                *bank = b;
-
-       /* some banks have two config registers in a single bank */
-       if (*offset * b->func_width > BITS_PER_LONG)
-               *reg += 4;
 }
 
 /* enable or disable a pinmux function */
@@ -289,6 +286,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
        struct samsung_pin_bank *bank;
        void __iomem *reg;
        u32 mask, shift, data, pin_offset, cnt;
+       unsigned long flags;
 
        drvdata = pinctrl_dev_get_drvdata(pctldev);
        pins = drvdata->pin_groups[group].pins;
@@ -298,16 +296,28 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
         * pin function number in the config register.
         */
        for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) {
+               struct samsung_pin_bank_type *type;
+
                pin_to_reg_bank(drvdata, pins[cnt] - drvdata->ctrl->base,
                                &reg, &pin_offset, &bank);
-               mask = (1 << bank->func_width) - 1;
-               shift = pin_offset * bank->func_width;
+               type = bank->type;
+               mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+               shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC];
+               if (shift >= 32) {
+                       /* Some banks have two config registers */
+                       shift -= 32;
+                       reg += 4;
+               }
+
+               spin_lock_irqsave(&bank->slock, flags);
 
-               data = readl(reg);
+               data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]);
                data &= ~(mask << shift);
                if (enable)
                        data |= drvdata->pin_groups[group].func << shift;
-               writel(data, reg);
+               writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]);
+
+               spin_unlock_irqrestore(&bank->slock, flags);
        }
 }
 
@@ -334,30 +344,44 @@ static void samsung_pinmux_disable(struct pinctrl_dev *pctldev,
 static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
                struct pinctrl_gpio_range *range, unsigned offset, bool input)
 {
+       struct samsung_pin_bank_type *type;
        struct samsung_pin_bank *bank;
        struct samsung_pinctrl_drv_data *drvdata;
        void __iomem *reg;
        u32 data, pin_offset, mask, shift;
+       unsigned long flags;
 
        bank = gc_to_pin_bank(range->gc);
+       type = bank->type;
        drvdata = pinctrl_dev_get_drvdata(pctldev);
 
        pin_offset = offset - bank->pin_base;
-       reg = drvdata->virt_base + bank->pctl_offset;
+       reg = drvdata->virt_base + bank->pctl_offset +
+                                       type->reg_offset[PINCFG_TYPE_FUNC];
+
+       mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+       shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC];
+       if (shift >= 32) {
+               /* Some banks have two config registers */
+               shift -= 32;
+               reg += 4;
+       }
 
-       mask = (1 << bank->func_width) - 1;
-       shift = pin_offset * bank->func_width;
+       spin_lock_irqsave(&bank->slock, flags);
 
        data = readl(reg);
        data &= ~(mask << shift);
        if (!input)
                data |= FUNC_OUTPUT << shift;
        writel(data, reg);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+
        return 0;
 }
 
 /* list of pinmux callbacks for the pinmux vertical in pinctrl core */
-static struct pinmux_ops samsung_pinmux_ops = {
+static const struct pinmux_ops samsung_pinmux_ops = {
        .get_functions_count    = samsung_get_functions_count,
        .get_function_name      = samsung_pinmux_get_fname,
        .get_function_groups    = samsung_pinmux_get_groups,
@@ -371,40 +395,26 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
                                unsigned long *config, bool set)
 {
        struct samsung_pinctrl_drv_data *drvdata;
+       struct samsung_pin_bank_type *type;
        struct samsung_pin_bank *bank;
        void __iomem *reg_base;
        enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config);
        u32 data, width, pin_offset, mask, shift;
        u32 cfg_value, cfg_reg;
+       unsigned long flags;
 
        drvdata = pinctrl_dev_get_drvdata(pctldev);
        pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, &reg_base,
                                        &pin_offset, &bank);
+       type = bank->type;
 
-       switch (cfg_type) {
-       case PINCFG_TYPE_PUD:
-               width = bank->pud_width;
-               cfg_reg = PUD_REG;
-               break;
-       case PINCFG_TYPE_DRV:
-               width = bank->drv_width;
-               cfg_reg = DRV_REG;
-               break;
-       case PINCFG_TYPE_CON_PDN:
-               width = bank->conpdn_width;
-               cfg_reg = CONPDN_REG;
-               break;
-       case PINCFG_TYPE_PUD_PDN:
-               width = bank->pudpdn_width;
-               cfg_reg = PUDPDN_REG;
-               break;
-       default:
-               WARN_ON(1);
+       if (cfg_type >= PINCFG_TYPE_NUM || !type->fld_width[cfg_type])
                return -EINVAL;
-       }
 
-       if (!width)
-               return -EINVAL;
+       width = type->fld_width[cfg_type];
+       cfg_reg = type->reg_offset[cfg_type];
+
+       spin_lock_irqsave(&bank->slock, flags);
 
        mask = (1 << width) - 1;
        shift = pin_offset * width;
@@ -420,6 +430,9 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
                data &= mask;
                *config = PINCFG_PACK(cfg_type, data);
        }
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+
        return 0;
 }
 
@@ -468,7 +481,7 @@ static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev,
 }
 
 /* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
-static struct pinconf_ops samsung_pinconf_ops = {
+static const struct pinconf_ops samsung_pinconf_ops = {
        .pin_config_get         = samsung_pinconf_get,
        .pin_config_set         = samsung_pinconf_set,
        .pin_config_group_get   = samsung_pinconf_group_get,
@@ -479,16 +492,22 @@ static struct pinconf_ops samsung_pinconf_ops = {
 static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
 {
        struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+       struct samsung_pin_bank_type *type = bank->type;
+       unsigned long flags;
        void __iomem *reg;
        u32 data;
 
        reg = bank->drvdata->virt_base + bank->pctl_offset;
 
-       data = readl(reg + DAT_REG);
+       spin_lock_irqsave(&bank->slock, flags);
+
+       data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
        data &= ~(1 << offset);
        if (value)
                data |= 1 << offset;
-       writel(data, reg + DAT_REG);
+       writel(data, reg + type->reg_offset[PINCFG_TYPE_DAT]);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
 }
 
 /* gpiolib gpio_get callback function */
@@ -497,10 +516,11 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
        void __iomem *reg;
        u32 data;
        struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+       struct samsung_pin_bank_type *type = bank->type;
 
        reg = bank->drvdata->virt_base + bank->pctl_offset;
 
-       data = readl(reg + DAT_REG);
+       data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
        data >>= offset;
        data &= 1;
        return data;
@@ -859,6 +879,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
 
        bank = ctrl->pin_banks;
        for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+               spin_lock_init(&bank->slock);
                bank->drvdata = d;
                bank->pin_base = ctrl->nr_pins;
                ctrl->nr_pins += bank->nr_pins;
@@ -944,10 +965,16 @@ static int samsung_pinctrl_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id samsung_pinctrl_dt_match[] = {
+#ifdef CONFIG_PINCTRL_EXYNOS
        { .compatible = "samsung,exynos4210-pinctrl",
                .data = (void *)exynos4210_pin_ctrl },
        { .compatible = "samsung,exynos4x12-pinctrl",
                .data = (void *)exynos4x12_pin_ctrl },
+#endif
+#ifdef CONFIG_PINCTRL_S3C64XX
+       { .compatible = "samsung,s3c64xx-pinctrl",
+               .data = s3c64xx_pin_ctrl },
+#endif
        {},
 };
 MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match);
index e2d4e67..45f27b4 100644 (file)
 
 #include <linux/gpio.h>
 
-/* register offsets within a pin bank */
-#define DAT_REG                0x4
-#define PUD_REG                0x8
-#define DRV_REG                0xC
-#define CONPDN_REG     0x10
-#define PUDPDN_REG     0x14
-
 /* pinmux function number for pin as gpio output line */
 #define FUNC_OUTPUT    0x1
 
 /**
  * enum pincfg_type - possible pin configuration types supported.
+ * @PINCFG_TYPE_FUNC: Function configuration.
+ * @PINCFG_TYPE_DAT: Pin value configuration.
  * @PINCFG_TYPE_PUD: Pull up/down configuration.
  * @PINCFG_TYPE_DRV: Drive strength configuration.
  * @PINCFG_TYPE_CON_PDN: Pin function in power down mode.
  * @PINCFG_TYPE_PUD_PDN: Pull up/down configuration in power down mode.
  */
 enum pincfg_type {
+       PINCFG_TYPE_FUNC,
+       PINCFG_TYPE_DAT,
        PINCFG_TYPE_PUD,
        PINCFG_TYPE_DRV,
        PINCFG_TYPE_CON_PDN,
        PINCFG_TYPE_PUD_PDN,
+
+       PINCFG_TYPE_NUM
 };
 
 /*
@@ -103,33 +102,40 @@ enum eint_type {
 struct samsung_pinctrl_drv_data;
 
 /**
+ * struct samsung_pin_bank_type: pin bank type description
+ * @fld_width: widths of configuration bitfields (0 if unavailable)
+ * @reg_offset: offsets of configuration registers (don't care of width is 0)
+ */
+struct samsung_pin_bank_type {
+       u8 fld_width[PINCFG_TYPE_NUM];
+       u8 reg_offset[PINCFG_TYPE_NUM];
+};
+
+/**
  * struct samsung_pin_bank: represent a controller pin-bank.
+ * @type: type of the bank (register offsets and bitfield widths)
  * @pctl_offset: starting offset of the pin-bank registers.
  * @pin_base: starting pin number of the bank.
  * @nr_pins: number of pins included in this bank.
- * @func_width: width of the function selector bit field.
- * @pud_width: width of the pin pull up/down selector bit field.
- * @drv_width: width of the pin driver strength selector bit field.
- * @conpdn_width: width of the sleep mode function selector bin field.
- * @pudpdn_width: width of the sleep mode pull up/down selector bit field.
+ * @eint_func: function to set in CON register to configure pin as EINT.
  * @eint_type: type of the external interrupt supported by the bank.
+ * @eint_mask: bit mask of pins which support EINT function.
  * @name: name to be prefixed for each pin in this pin bank.
  * @of_node: OF node of the bank.
  * @drvdata: link to controller driver data
  * @irq_domain: IRQ domain of the bank.
  * @gpio_chip: GPIO chip of the bank.
  * @grange: linux gpio pin range supported by this bank.
+ * @slock: spinlock protecting bank registers
  */
 struct samsung_pin_bank {
+       struct samsung_pin_bank_type *type;
        u32             pctl_offset;
        u32             pin_base;
        u8              nr_pins;
-       u8              func_width;
-       u8              pud_width;
-       u8              drv_width;
-       u8              conpdn_width;
-       u8              pudpdn_width;
+       u8              eint_func;
        enum eint_type  eint_type;
+       u32             eint_mask;
        u32             eint_offset;
        char            *name;
        struct device_node *of_node;
@@ -137,6 +143,7 @@ struct samsung_pin_bank {
        struct irq_domain *irq_domain;
        struct gpio_chip gpio_chip;
        struct pinctrl_gpio_range grange;
+       spinlock_t slock;
 };
 
 /**
@@ -237,5 +244,6 @@ struct samsung_pmx_func {
 /* list of all exported SoC specific data */
 extern struct samsung_pin_ctrl exynos4210_pin_ctrl[];
 extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
+extern struct samsung_pin_ctrl s3c64xx_pin_ctrl[];
 
 #endif /* __PINCTRL_SAMSUNG_H */
index 5c32e88..5f2d2bf 100644 (file)
 
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf-generic.h>
 
 #include "core.h"
+#include "pinconf.h"
 
 #define DRIVER_NAME                    "pinctrl-single"
 #define PCS_MUX_PINS_NAME              "pinctrl-single,pins"
@@ -59,6 +61,33 @@ struct pcs_func_vals {
 };
 
 /**
+ * struct pcs_conf_vals - pinconf parameter, pinconf register offset
+ * and value, enable, disable, mask
+ * @param:     config parameter
+ * @val:       user input bits in the pinconf register
+ * @enable:    enable bits in the pinconf register
+ * @disable:   disable bits in the pinconf register
+ * @mask:      mask bits in the register value
+ */
+struct pcs_conf_vals {
+       enum pin_config_param param;
+       unsigned val;
+       unsigned enable;
+       unsigned disable;
+       unsigned mask;
+};
+
+/**
+ * struct pcs_conf_type - pinconf property name, pinconf param pair
+ * @name:      property name in DTS file
+ * @param:     config parameter
+ */
+struct pcs_conf_type {
+       const char *name;
+       enum pin_config_param param;
+};
+
+/**
  * struct pcs_function - pinctrl function
  * @name:      pinctrl function name
  * @vals:      register and vals array
@@ -73,6 +102,22 @@ struct pcs_function {
        unsigned nvals;
        const char **pgnames;
        int npgnames;
+       struct pcs_conf_vals *conf;
+       int nconfs;
+       struct list_head node;
+};
+
+/**
+ * struct pcs_gpiofunc_range - pin ranges with same mux value of gpio function
+ * @offset:    offset base of pins
+ * @npins:     number pins with the same mux value of gpio function
+ * @gpiofunc:  mux value of gpio function
+ * @node:      list node
+ */
+struct pcs_gpiofunc_range {
+       unsigned offset;
+       unsigned npins;
+       unsigned gpiofunc;
        struct list_head node;
 };
 
@@ -117,12 +162,14 @@ struct pcs_name {
  * @fshift:    function register shift
  * @foff:      value to turn mux off
  * @fmax:      max number of functions in fmask
+ * @is_pinconf:        whether supports pinconf
  * @names:     array of register names for pins
  * @pins:      physical pins on the SoC
  * @pgtree:    pingroup index radix tree
  * @ftree:     function index radix tree
  * @pingroups: list of pingroups
  * @functions: list of functions
+ * @gpiofuncs: list of gpio functions
  * @ngroups:   number of pingroups
  * @nfuncs:    number of functions
  * @desc:      pin controller descriptor
@@ -142,12 +189,14 @@ struct pcs_device {
        unsigned foff;
        unsigned fmax;
        bool bits_per_mux;
+       bool is_pinconf;
        struct pcs_name *names;
        struct pcs_data pins;
        struct radix_tree_root pgtree;
        struct radix_tree_root ftree;
        struct list_head pingroups;
        struct list_head functions;
+       struct list_head gpiofuncs;
        unsigned ngroups;
        unsigned nfuncs;
        struct pinctrl_desc desc;
@@ -155,6 +204,16 @@ struct pcs_device {
        void (*write)(unsigned val, void __iomem *reg);
 };
 
+static int pcs_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
+                          unsigned long *config);
+static int pcs_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
+                          unsigned long config);
+
+static enum pin_config_param pcs_bias[] = {
+       PIN_CONFIG_BIAS_PULL_DOWN,
+       PIN_CONFIG_BIAS_PULL_UP,
+};
+
 /*
  * REVISIT: Reads and writes could eventually use regmap or something
  * generic. But at least on omaps, some mux registers are performance
@@ -270,7 +329,7 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
                                struct device_node *np_config,
                                struct pinctrl_map **map, unsigned *num_maps);
 
-static struct pinctrl_ops pcs_pinctrl_ops = {
+static const struct pinctrl_ops pcs_pinctrl_ops = {
        .get_groups_count = pcs_get_groups_count,
        .get_group_name = pcs_get_group_name,
        .get_group_pins = pcs_get_group_pins,
@@ -326,6 +385,28 @@ static int pcs_get_function_groups(struct pinctrl_dev *pctldev,
        return 0;
 }
 
+static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin,
+                           struct pcs_function **func)
+{
+       struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+       struct pin_desc *pdesc = pin_desc_get(pctldev, pin);
+       const struct pinctrl_setting_mux *setting;
+       unsigned fselector;
+
+       /* If pin is not described in DTS & enabled, mux_setting is NULL. */
+       setting = pdesc->mux_setting;
+       if (!setting)
+               return -ENOTSUPP;
+       fselector = setting->func;
+       *func = radix_tree_lookup(&pcs->ftree, fselector);
+       if (!(*func)) {
+               dev_err(pcs->dev, "%s could not find function%i\n",
+                       __func__, fselector);
+               return -ENOTSUPP;
+       }
+       return 0;
+}
+
 static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector,
        unsigned group)
 {
@@ -334,6 +415,9 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector,
        int i;
 
        pcs = pinctrl_dev_get_drvdata(pctldev);
+       /* If function mask is null, needn't enable it. */
+       if (!pcs->fmask)
+               return 0;
        func = radix_tree_lookup(&pcs->ftree, fselector);
        if (!func)
                return -EINVAL;
@@ -368,6 +452,10 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
        int i;
 
        pcs = pinctrl_dev_get_drvdata(pctldev);
+       /* If function mask is null, needn't disable it. */
+       if (!pcs->fmask)
+               return;
+
        func = radix_tree_lookup(&pcs->ftree, fselector);
        if (!func) {
                dev_err(pcs->dev, "%s could not find function%i\n",
@@ -403,12 +491,33 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
 }
 
 static int pcs_request_gpio(struct pinctrl_dev *pctldev,
-                       struct pinctrl_gpio_range *range, unsigned offset)
+                           struct pinctrl_gpio_range *range, unsigned pin)
 {
-       return -ENOTSUPP;
+       struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+       struct pcs_gpiofunc_range *frange = NULL;
+       struct list_head *pos, *tmp;
+       int mux_bytes = 0;
+       unsigned data;
+
+       /* If function mask is null, return directly. */
+       if (!pcs->fmask)
+               return -ENOTSUPP;
+
+       list_for_each_safe(pos, tmp, &pcs->gpiofuncs) {
+               frange = list_entry(pos, struct pcs_gpiofunc_range, node);
+               if (pin >= frange->offset + frange->npins
+                       || pin < frange->offset)
+                       continue;
+               mux_bytes = pcs->width / BITS_PER_BYTE;
+               data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask;
+               data |= frange->gpiofunc;
+               pcs->write(data, pcs->base + pin * mux_bytes);
+               break;
+       }
+       return 0;
 }
 
-static struct pinmux_ops pcs_pinmux_ops = {
+static const struct pinmux_ops pcs_pinmux_ops = {
        .get_functions_count = pcs_get_functions_count,
        .get_function_name = pcs_get_function_name,
        .get_function_groups = pcs_get_function_groups,
@@ -417,32 +526,190 @@ static struct pinmux_ops pcs_pinmux_ops = {
        .gpio_request_enable = pcs_request_gpio,
 };
 
+/* Clear BIAS value */
+static void pcs_pinconf_clear_bias(struct pinctrl_dev *pctldev, unsigned pin)
+{
+       unsigned long config;
+       int i;
+       for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) {
+               config = pinconf_to_config_packed(pcs_bias[i], 0);
+               pcs_pinconf_set(pctldev, pin, config);
+       }
+}
+
+/*
+ * Check whether PIN_CONFIG_BIAS_DISABLE is valid.
+ * It's depend on that PULL_DOWN & PULL_UP configs are all invalid.
+ */
+static bool pcs_pinconf_bias_disable(struct pinctrl_dev *pctldev, unsigned pin)
+{
+       unsigned long config;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) {
+               config = pinconf_to_config_packed(pcs_bias[i], 0);
+               if (!pcs_pinconf_get(pctldev, pin, &config))
+                       goto out;
+       }
+       return true;
+out:
+       return false;
+}
+
 static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
                                unsigned pin, unsigned long *config)
 {
+       struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+       struct pcs_function *func;
+       enum pin_config_param param;
+       unsigned offset = 0, data = 0, i, j, ret;
+
+       ret = pcs_get_function(pctldev, pin, &func);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < func->nconfs; i++) {
+               param = pinconf_to_config_param(*config);
+               if (param == PIN_CONFIG_BIAS_DISABLE) {
+                       if (pcs_pinconf_bias_disable(pctldev, pin)) {
+                               *config = 0;
+                               return 0;
+                       } else {
+                               return -ENOTSUPP;
+                       }
+               } else if (param != func->conf[i].param) {
+                       continue;
+               }
+
+               offset = pin * (pcs->width / BITS_PER_BYTE);
+               data = pcs->read(pcs->base + offset) & func->conf[i].mask;
+               switch (func->conf[i].param) {
+               /* 4 parameters */
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+               case PIN_CONFIG_BIAS_PULL_UP:
+               case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+                       if ((data != func->conf[i].enable) ||
+                           (data == func->conf[i].disable))
+                               return -ENOTSUPP;
+                       *config = 0;
+                       break;
+               /* 2 parameters */
+               case PIN_CONFIG_INPUT_SCHMITT:
+                       for (j = 0; j < func->nconfs; j++) {
+                               switch (func->conf[j].param) {
+                               case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+                                       if (data != func->conf[j].enable)
+                                               return -ENOTSUPP;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+                       *config = data;
+                       break;
+               case PIN_CONFIG_DRIVE_STRENGTH:
+               case PIN_CONFIG_SLEW_RATE:
+               default:
+                       *config = data;
+                       break;
+               }
+               return 0;
+       }
        return -ENOTSUPP;
 }
 
 static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
                                unsigned pin, unsigned long config)
 {
+       struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+       struct pcs_function *func;
+       unsigned offset = 0, shift = 0, i, data, ret;
+       u16 arg;
+
+       ret = pcs_get_function(pctldev, pin, &func);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < func->nconfs; i++) {
+               if (pinconf_to_config_param(config) == func->conf[i].param) {
+                       offset = pin * (pcs->width / BITS_PER_BYTE);
+                       data = pcs->read(pcs->base + offset);
+                       arg = pinconf_to_config_argument(config);
+                       switch (func->conf[i].param) {
+                       /* 2 parameters */
+                       case PIN_CONFIG_INPUT_SCHMITT:
+                       case PIN_CONFIG_DRIVE_STRENGTH:
+                       case PIN_CONFIG_SLEW_RATE:
+                               shift = ffs(func->conf[i].mask) - 1;
+                               data &= ~func->conf[i].mask;
+                               data |= (arg << shift) & func->conf[i].mask;
+                               break;
+                       /* 4 parameters */
+                       case PIN_CONFIG_BIAS_DISABLE:
+                               pcs_pinconf_clear_bias(pctldev, pin);
+                               break;
+                       case PIN_CONFIG_BIAS_PULL_DOWN:
+                       case PIN_CONFIG_BIAS_PULL_UP:
+                               if (arg)
+                                       pcs_pinconf_clear_bias(pctldev, pin);
+                               /* fall through */
+                       case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+                               data &= ~func->conf[i].mask;
+                               if (arg)
+                                       data |= func->conf[i].enable;
+                               else
+                                       data |= func->conf[i].disable;
+                               break;
+                       default:
+                               return -ENOTSUPP;
+                       }
+                       pcs->write(data, pcs->base + offset);
+                       return 0;
+               }
+       }
        return -ENOTSUPP;
 }
 
 static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev,
                                unsigned group, unsigned long *config)
 {
-       return -ENOTSUPP;
+       const unsigned *pins;
+       unsigned npins, old = 0;
+       int i, ret;
+
+       ret = pcs_get_group_pins(pctldev, group, &pins, &npins);
+       if (ret)
+               return ret;
+       for (i = 0; i < npins; i++) {
+               if (pcs_pinconf_get(pctldev, pins[i], config))
+                       return -ENOTSUPP;
+               /* configs do not match between two pins */
+               if (i && (old != *config))
+                       return -ENOTSUPP;
+               old = *config;
+       }
+       return 0;
 }
 
 static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev,
                                unsigned group, unsigned long config)
 {
-       return -ENOTSUPP;
+       const unsigned *pins;
+       unsigned npins;
+       int i, ret;
+
+       ret = pcs_get_group_pins(pctldev, group, &pins, &npins);
+       if (ret)
+               return ret;
+       for (i = 0; i < npins; i++) {
+               if (pcs_pinconf_set(pctldev, pins[i], config))
+                       return -ENOTSUPP;
+       }
+       return 0;
 }
 
 static void pcs_pinconf_dbg_show(struct pinctrl_dev *pctldev,
-                               struct seq_file *s, unsigned offset)
+                               struct seq_file *s, unsigned pin)
 {
 }
 
@@ -451,13 +718,22 @@ static void pcs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
 {
 }
 
-static struct pinconf_ops pcs_pinconf_ops = {
+static void pcs_pinconf_config_dbg_show(struct pinctrl_dev *pctldev,
+                                       struct seq_file *s,
+                                       unsigned long config)
+{
+       pinconf_generic_dump_config(pctldev, s, config);
+}
+
+static const struct pinconf_ops pcs_pinconf_ops = {
        .pin_config_get = pcs_pinconf_get,
        .pin_config_set = pcs_pinconf_set,
        .pin_config_group_get = pcs_pinconf_group_get,
        .pin_config_group_set = pcs_pinconf_group_set,
        .pin_config_dbg_show = pcs_pinconf_dbg_show,
        .pin_config_group_dbg_show = pcs_pinconf_group_dbg_show,
+       .pin_config_config_dbg_show = pcs_pinconf_config_dbg_show,
+       .is_generic = true,
 };
 
 /**
@@ -648,11 +924,158 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
        return index;
 }
 
+/*
+ * check whether data matches enable bits or disable bits
+ * Return value: 1 for matching enable bits, 0 for matching disable bits,
+ *               and negative value for matching failure.
+ */
+static int pcs_config_match(unsigned data, unsigned enable, unsigned disable)
+{
+       int ret = -EINVAL;
+
+       if (data == enable)
+               ret = 1;
+       else if (data == disable)
+               ret = 0;
+       return ret;
+}
+
+static void add_config(struct pcs_conf_vals **conf, enum pin_config_param param,
+                      unsigned value, unsigned enable, unsigned disable,
+                      unsigned mask)
+{
+       (*conf)->param = param;
+       (*conf)->val = value;
+       (*conf)->enable = enable;
+       (*conf)->disable = disable;
+       (*conf)->mask = mask;
+       (*conf)++;
+}
+
+static void add_setting(unsigned long **setting, enum pin_config_param param,
+                       unsigned arg)
+{
+       **setting = pinconf_to_config_packed(param, arg);
+       (*setting)++;
+}
+
+/* add pinconf setting with 2 parameters */
+static void pcs_add_conf2(struct pcs_device *pcs, struct device_node *np,
+                         const char *name, enum pin_config_param param,
+                         struct pcs_conf_vals **conf, unsigned long **settings)
+{
+       unsigned value[2], shift;
+       int ret;
+
+       ret = of_property_read_u32_array(np, name, value, 2);
+       if (ret)
+               return;
+       /* set value & mask */
+       value[0] &= value[1];
+       shift = ffs(value[1]) - 1;
+       /* skip enable & disable */
+       add_config(conf, param, value[0], 0, 0, value[1]);
+       add_setting(settings, param, value[0] >> shift);
+}
+
+/* add pinconf setting with 4 parameters */
+static void pcs_add_conf4(struct pcs_device *pcs, struct device_node *np,
+                         const char *name, enum pin_config_param param,
+                         struct pcs_conf_vals **conf, unsigned long **settings)
+{
+       unsigned value[4];
+       int ret;
+
+       /* value to set, enable, disable, mask */
+       ret = of_property_read_u32_array(np, name, value, 4);
+       if (ret)
+               return;
+       if (!value[3]) {
+               dev_err(pcs->dev, "mask field of the property can't be 0\n");
+               return;
+       }
+       value[0] &= value[3];
+       value[1] &= value[3];
+       value[2] &= value[3];
+       ret = pcs_config_match(value[0], value[1], value[2]);
+       if (ret < 0)
+               dev_dbg(pcs->dev, "failed to match enable or disable bits\n");
+       add_config(conf, param, value[0], value[1], value[2], value[3]);
+       add_setting(settings, param, ret);
+}
+
+static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
+                            struct pcs_function *func,
+                            struct pinctrl_map **map)
+
+{
+       struct pinctrl_map *m = *map;
+       int i = 0, nconfs = 0;
+       unsigned long *settings = NULL, *s = NULL;
+       struct pcs_conf_vals *conf = NULL;
+       struct pcs_conf_type prop2[] = {
+               { "pinctrl-single,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, },
+               { "pinctrl-single,slew-rate", PIN_CONFIG_SLEW_RATE, },
+               { "pinctrl-single,input-schmitt", PIN_CONFIG_INPUT_SCHMITT, },
+       };
+       struct pcs_conf_type prop4[] = {
+               { "pinctrl-single,bias-pullup", PIN_CONFIG_BIAS_PULL_UP, },
+               { "pinctrl-single,bias-pulldown", PIN_CONFIG_BIAS_PULL_DOWN, },
+               { "pinctrl-single,input-schmitt-enable",
+                       PIN_CONFIG_INPUT_SCHMITT_ENABLE, },
+       };
+
+       /* If pinconf isn't supported, don't parse properties in below. */
+       if (!pcs->is_pinconf)
+               return 0;
+
+       /* cacluate how much properties are supported in current node */
+       for (i = 0; i < ARRAY_SIZE(prop2); i++) {
+               if (of_find_property(np, prop2[i].name, NULL))
+                       nconfs++;
+       }
+       for (i = 0; i < ARRAY_SIZE(prop4); i++) {
+               if (of_find_property(np, prop4[i].name, NULL))
+                       nconfs++;
+       }
+       if (!nconfs)
+               return 0;
+
+       func->conf = devm_kzalloc(pcs->dev,
+                                 sizeof(struct pcs_conf_vals) * nconfs,
+                                 GFP_KERNEL);
+       if (!func->conf)
+               return -ENOMEM;
+       func->nconfs = nconfs;
+       conf = &(func->conf[0]);
+       m++;
+       settings = devm_kzalloc(pcs->dev, sizeof(unsigned long) * nconfs,
+                               GFP_KERNEL);
+       if (!settings)
+               return -ENOMEM;
+       s = &settings[0];
+
+       for (i = 0; i < ARRAY_SIZE(prop2); i++)
+               pcs_add_conf2(pcs, np, prop2[i].name, prop2[i].param,
+                             &conf, &s);
+       for (i = 0; i < ARRAY_SIZE(prop4); i++)
+               pcs_add_conf4(pcs, np, prop4[i].name, prop4[i].param,
+                             &conf, &s);
+       m->type = PIN_MAP_TYPE_CONFIGS_GROUP;
+       m->data.configs.group_or_pin = np->name;
+       m->data.configs.configs = settings;
+       m->data.configs.num_configs = nconfs;
+       return 0;
+}
+
+static void pcs_free_pingroups(struct pcs_device *pcs);
+
 /**
  * smux_parse_one_pinctrl_entry() - parses a device tree mux entry
  * @pcs: pinctrl driver instance
  * @np: device node of the mux entry
  * @map: map entry
+ * @num_maps: number of map
  * @pgnames: pingroup names
  *
  * Note that this binding currently supports only sets of one register + value.
@@ -669,6 +1092,7 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
 static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
                                                struct device_node *np,
                                                struct pinctrl_map **map,
+                                               unsigned *num_maps,
                                                const char **pgnames)
 {
        struct pcs_func_vals *vals;
@@ -741,8 +1165,18 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
        (*map)->data.mux.group = np->name;
        (*map)->data.mux.function = np->name;
 
+       if (pcs->is_pinconf) {
+               if (pcs_parse_pinconf(pcs, np, function, map))
+                       goto free_pingroups;
+               *num_maps = 2;
+       } else {
+               *num_maps = 1;
+       }
        return 0;
 
+free_pingroups:
+       pcs_free_pingroups(pcs);
+       *num_maps = 1;
 free_function:
        pcs_remove_function(pcs, function);
 
@@ -771,7 +1205,8 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
 
        pcs = pinctrl_dev_get_drvdata(pctldev);
 
-       *map = devm_kzalloc(pcs->dev, sizeof(**map), GFP_KERNEL);
+       /* create 2 maps. One is for pinmux, and the other is for pinconf. */
+       *map = devm_kzalloc(pcs->dev, sizeof(**map) * 2, GFP_KERNEL);
        if (!*map)
                return -ENOMEM;
 
@@ -783,13 +1218,13 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
                goto free_map;
        }
 
-       ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, pgnames);
+       ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, num_maps,
+                                         pgnames);
        if (ret < 0) {
                dev_err(pcs->dev, "no pins entries for %s\n",
                        np_config->name);
                goto free_pgnames;
        }
-       *num_maps = 1;
 
        return 0;
 
@@ -879,6 +1314,37 @@ static void pcs_free_resources(struct pcs_device *pcs)
 
 static struct of_device_id pcs_of_match[];
 
+static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs)
+{
+       const char *propname = "pinctrl-single,gpio-range";
+       const char *cellname = "#pinctrl-single,gpio-range-cells";
+       struct of_phandle_args gpiospec;
+       struct pcs_gpiofunc_range *range;
+       int ret, i;
+
+       for (i = 0; ; i++) {
+               ret = of_parse_phandle_with_args(node, propname, cellname,
+                                                i, &gpiospec);
+               /* Do not treat it as error. Only treat it as end condition. */
+               if (ret) {
+                       ret = 0;
+                       break;
+               }
+               range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL);
+               if (!range) {
+                       ret = -ENOMEM;
+                       break;
+               }
+               range->offset = gpiospec.args[0];
+               range->npins = gpiospec.args[1];
+               range->gpiofunc = gpiospec.args[2];
+               mutex_lock(&pcs->mutex);
+               list_add_tail(&range->node, &pcs->gpiofuncs);
+               mutex_unlock(&pcs->mutex);
+       }
+       return ret;
+}
+
 static int pcs_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -900,14 +1366,23 @@ static int pcs_probe(struct platform_device *pdev)
        mutex_init(&pcs->mutex);
        INIT_LIST_HEAD(&pcs->pingroups);
        INIT_LIST_HEAD(&pcs->functions);
+       INIT_LIST_HEAD(&pcs->gpiofuncs);
+       pcs->is_pinconf = match->data;
 
        PCS_GET_PROP_U32("pinctrl-single,register-width", &pcs->width,
                         "register width not specified\n");
 
-       PCS_GET_PROP_U32("pinctrl-single,function-mask", &pcs->fmask,
-                        "function register mask not specified\n");
-       pcs->fshift = ffs(pcs->fmask) - 1;
-       pcs->fmax = pcs->fmask >> pcs->fshift;
+       ret = of_property_read_u32(np, "pinctrl-single,function-mask",
+                                  &pcs->fmask);
+       if (!ret) {
+               pcs->fshift = ffs(pcs->fmask) - 1;
+               pcs->fmax = pcs->fmask >> pcs->fshift;
+       } else {
+               /* If mask property doesn't exist, function mux is invalid. */
+               pcs->fmask = 0;
+               pcs->fshift = 0;
+               pcs->fmax = 0;
+       }
 
        ret = of_property_read_u32(np, "pinctrl-single,function-off",
                                        &pcs->foff);
@@ -961,7 +1436,8 @@ static int pcs_probe(struct platform_device *pdev)
        pcs->desc.name = DRIVER_NAME;
        pcs->desc.pctlops = &pcs_pinctrl_ops;
        pcs->desc.pmxops = &pcs_pinmux_ops;
-       pcs->desc.confops = &pcs_pinconf_ops;
+       if (pcs->is_pinconf)
+               pcs->desc.confops = &pcs_pinconf_ops;
        pcs->desc.owner = THIS_MODULE;
 
        ret = pcs_allocate_pin_table(pcs);
@@ -975,6 +1451,10 @@ static int pcs_probe(struct platform_device *pdev)
                goto free;
        }
 
+       ret = pcs_add_gpio_func(np, pcs);
+       if (ret < 0)
+               goto free;
+
        dev_info(pcs->dev, "%i pins at pa %p size %u\n",
                 pcs->desc.npins, pcs->base, pcs->size);
 
@@ -999,7 +1479,8 @@ static int pcs_remove(struct platform_device *pdev)
 }
 
 static struct of_device_id pcs_of_match[] = {
-       { .compatible = DRIVER_NAME, },
+       { .compatible = "pinctrl-single", .data = (void *)false },
+       { .compatible = "pinconf-single", .data = (void *)true },
        { },
 };
 MODULE_DEVICE_TABLE(of, pcs_of_match);
index d02498b..fb90625 100644 (file)
@@ -979,7 +979,7 @@ static void sirfsoc_dt_free_map(struct pinctrl_dev *pctldev,
        kfree(map);
 }
 
-static struct pinctrl_ops sirfsoc_pctrl_ops = {
+static const struct pinctrl_ops sirfsoc_pctrl_ops = {
        .get_groups_count = sirfsoc_get_groups_count,
        .get_group_name = sirfsoc_get_group_name,
        .get_group_pins = sirfsoc_get_group_pins,
@@ -1181,7 +1181,7 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
        return 0;
 }
 
-static struct pinmux_ops sirfsoc_pinmux_ops = {
+static const struct pinmux_ops sirfsoc_pinmux_ops = {
        .enable = sirfsoc_pinmux_enable,
        .disable = sirfsoc_pinmux_disable,
        .get_functions_count = sirfsoc_pinmux_get_funcs_count,
@@ -1685,15 +1685,12 @@ static void sirfsoc_gpio_set_pullup(const u32 *pullups)
        const unsigned long *p = (const unsigned long *)pullups;
 
        for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
-               n = find_first_bit(p + i, BITS_PER_LONG);
-               while (n < BITS_PER_LONG) {
+               for_each_set_bit(n, p + i, BITS_PER_LONG) {
                        u32 offset = SIRFSOC_GPIO_CTRL(i, n);
                        u32 val = readl(sgpio_bank[i].chip.regs + offset);
                        val |= SIRFSOC_GPIO_CTL_PULL_MASK;
                        val |= SIRFSOC_GPIO_CTL_PULL_HIGH;
                        writel(val, sgpio_bank[i].chip.regs + offset);
-
-                       n = find_next_bit(p + i, BITS_PER_LONG, n + 1);
                }
        }
 }
@@ -1704,15 +1701,12 @@ static void sirfsoc_gpio_set_pulldown(const u32 *pulldowns)
        const unsigned long *p = (const unsigned long *)pulldowns;
 
        for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
-               n = find_first_bit(p + i, BITS_PER_LONG);
-               while (n < BITS_PER_LONG) {
+               for_each_set_bit(n, p + i, BITS_PER_LONG) {
                        u32 offset = SIRFSOC_GPIO_CTRL(i, n);
                        u32 val = readl(sgpio_bank[i].chip.regs + offset);
                        val |= SIRFSOC_GPIO_CTL_PULL_MASK;
                        val &= ~SIRFSOC_GPIO_CTL_PULL_HIGH;
                        writel(val, sgpio_bank[i].chip.regs + offset);
-
-                       n = find_next_bit(p + i, BITS_PER_LONG, n + 1);
                }
        }
 }
index 80b11e3..c52fc2c 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/io.h>
+#include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/of.h>
 static const struct sunxi_desc_pin sun4i_a10_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ERXD3 */
+               SUNXI_FUNCTION(0x3, "spi1"),            /* CS0 */
+               SUNXI_FUNCTION(0x4, "uart2")),          /* RTS */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA1,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ERXD2 */
+               SUNXI_FUNCTION(0x3, "spi1"),            /* CLK */
+               SUNXI_FUNCTION(0x4, "uart2")),          /* CTS */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ERXD1 */
+               SUNXI_FUNCTION(0x3, "spi1"),            /* MOSI */
+               SUNXI_FUNCTION(0x4, "uart2")),          /* TX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ERXD0 */
+               SUNXI_FUNCTION(0x3, "spi1"),            /* MISO */
+               SUNXI_FUNCTION(0x4, "uart2")),          /* RX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ETXD3 */
+               SUNXI_FUNCTION(0x3, "spi1")),           /* CS1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ETXD2 */
+               SUNXI_FUNCTION(0x3, "spi3")),           /* CS0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA6,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ETXD1 */
+               SUNXI_FUNCTION(0x3, "spi3")),           /* CLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA7,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ETXD0 */
+               SUNXI_FUNCTION(0x3, "spi3")),           /* MOSI */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA8,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ERXCK */
+               SUNXI_FUNCTION(0x3, "spi3")),           /* MISO */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA9,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ERXERR */
+               SUNXI_FUNCTION(0x3, "spi3")),           /* CS1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ERXDV */
                SUNXI_FUNCTION(0x4, "uart1")),          /* TX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA11,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* EMDC */
                SUNXI_FUNCTION(0x4, "uart1")),          /* RX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA12,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* EMDIO */
+               SUNXI_FUNCTION(0x3, "uart6"),           /* TX */
                SUNXI_FUNCTION(0x4, "uart1")),          /* RTS */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA13,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ETXEN */
+               SUNXI_FUNCTION(0x3, "uart6"),           /* RX */
                SUNXI_FUNCTION(0x4, "uart1")),          /* CTS */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA14,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ETXCK */
+               SUNXI_FUNCTION(0x3, "uart7"),           /* TX */
                SUNXI_FUNCTION(0x4, "uart1")),          /* DTR */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA15,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ECRS */
+               SUNXI_FUNCTION(0x3, "uart7"),           /* RX */
                SUNXI_FUNCTION(0x4, "uart1")),          /* DSR */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA16,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ECOL */
+               SUNXI_FUNCTION(0x3, "can"),             /* TX */
                SUNXI_FUNCTION(0x4, "uart1")),          /* DCD */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PA17,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "emac"),            /* ETXERR */
+               SUNXI_FUNCTION(0x3, "can"),             /* RX */
                SUNXI_FUNCTION(0x4, "uart1")),          /* RING */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c0")),           /* SCK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c0")),           /* SDA */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "pwm")),            /* PWM0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ir0")),            /* TX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ir0")),            /* RX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s"),             /* MCLK */
+               SUNXI_FUNCTION(0x3, "ac97")),           /* MCLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB6,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s"),             /* BCLK */
+               SUNXI_FUNCTION(0x3, "ac97")),           /* BCLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB7,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s"),             /* LRCK */
+               SUNXI_FUNCTION(0x3, "ac97")),           /* SYNC */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB8,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s"),             /* DO0 */
+               SUNXI_FUNCTION(0x3, "ac97")),           /* DO */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB9,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s")),            /* DO1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s")),            /* DO2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB11,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s")),            /* DO3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB12,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2s"),             /* DI */
+               SUNXI_FUNCTION(0x3, "ac97")),           /* DI */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB13,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi2")),           /* CS1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB14,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi2"),            /* CS0 */
+               SUNXI_FUNCTION(0x3, "jtag")),           /* MS0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi2"),            /* CLK */
+               SUNXI_FUNCTION(0x3, "jtag")),           /* CK0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi2"),            /* MOSI */
+               SUNXI_FUNCTION(0x3, "jtag")),           /* DO0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi2"),            /* MISO */
+               SUNXI_FUNCTION(0x3, "jtag")),           /* DI0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c1")),           /* SCK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB19,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c1")),           /* SDA */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB20,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c2")),           /* SCK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB21,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c2")),           /* SDA */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB22,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "uart0")),          /* TX */
+               SUNXI_FUNCTION(0x2, "uart0"),           /* TX */
+               SUNXI_FUNCTION(0x3, "ir1")),            /* TX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB23,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "uart0")),          /* RX */
+               SUNXI_FUNCTION(0x2, "uart0"),           /* RX */
+               SUNXI_FUNCTION(0x3, "ir1")),            /* RX */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NWE */
+               SUNXI_FUNCTION(0x3, "spi0")),           /* MOSI */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NALE */
+               SUNXI_FUNCTION(0x3, "spi0")),           /* MISO */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NCLE */
+               SUNXI_FUNCTION(0x3, "spi0")),           /* SCK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),          /* NCE1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),          /* NCE0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),  /* NRE# */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NRB0 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* CMD */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NRB1 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* CLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ0 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* D0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ1 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* D1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ2 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* D2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ3 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* D3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),          /* NDQ4 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),          /* NDQ5 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),          /* NDQ6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),          /* NDQ7 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC16,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),          /* NWP */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC17,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),          /* NCE2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC18,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),          /* NCE3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NCE4 */
+               SUNXI_FUNCTION(0x3, "spi2")),           /* CS0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC20,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NCE5 */
+               SUNXI_FUNCTION(0x3, "spi2")),           /* CLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC21,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NCE6 */
+               SUNXI_FUNCTION(0x3, "spi2")),           /* MOSI */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC22,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NCE7 */
+               SUNXI_FUNCTION(0x3, "spi2")),           /* MISO */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC23,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x3, "spi0")),           /* CS0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC24,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),          /* NDQS */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D0 */
+               SUNXI_FUNCTION(0x3, "lvds0")),          /* VP0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD1,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D1 */
+               SUNXI_FUNCTION(0x3, "lvds0")),          /* VN0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D2 */
+               SUNXI_FUNCTION(0x3, "lvds0")),          /* VP1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D3 */
+               SUNXI_FUNCTION(0x3, "lvds0")),          /* VN1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D4 */
+               SUNXI_FUNCTION(0x3, "lvds0")),          /* VP2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D5 */
+               SUNXI_FUNCTION(0x3, "lvds0")),          /* VN2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D6 */
+               SUNXI_FUNCTION(0x3, "lvds0")),          /* VPC */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D7 */
+               SUNXI_FUNCTION(0x3, "lvds0")),          /* VNC */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD8,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D8 */
+               SUNXI_FUNCTION(0x3, "lvds0")),          /* VP3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD9,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D9 */
+               SUNXI_FUNCTION(0x3, "lvds0")),          /* VM3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D10 */
+               SUNXI_FUNCTION(0x3, "lvds1")),          /* VP0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D11 */
+               SUNXI_FUNCTION(0x3, "lvds1")),          /* VN0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D12 */
+               SUNXI_FUNCTION(0x3, "lvds1")),          /* VP1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D13 */
+               SUNXI_FUNCTION(0x3, "lvds1")),          /* VN1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D14 */
+               SUNXI_FUNCTION(0x3, "lvds1")),          /* VP2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D15 */
+               SUNXI_FUNCTION(0x3, "lvds1")),          /* VN2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD16,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D16 */
+               SUNXI_FUNCTION(0x3, "lvds1")),          /* VPC */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD17,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D17 */
+               SUNXI_FUNCTION(0x3, "lvds1")),          /* VNC */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D18 */
+               SUNXI_FUNCTION(0x3, "lvds1")),          /* VP3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D19 */
+               SUNXI_FUNCTION(0x3, "lvds1")),          /* VN3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D20 */
+               SUNXI_FUNCTION(0x3, "csi1")),           /* MCLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D21 */
+               SUNXI_FUNCTION(0x3, "sim")),            /* VPPEN */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D22 */
+               SUNXI_FUNCTION(0x3, "sim")),            /* VPPPP */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* D23 */
+               SUNXI_FUNCTION(0x3, "sim")),            /* DET */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* CLK */
+               SUNXI_FUNCTION(0x3, "sim")),            /* VCCEN */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* DE */
+               SUNXI_FUNCTION(0x3, "sim")),            /* RST */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* HSYNC */
+               SUNXI_FUNCTION(0x3, "sim")),            /* SCK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0"),            /* VSYNC */
+               SUNXI_FUNCTION(0x3, "sim")),            /* SDA */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts0"),             /* CLK */
+               SUNXI_FUNCTION(0x3, "csi0")),           /* PCK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts0"),             /* ERR */
+               SUNXI_FUNCTION(0x3, "csi0")),           /* CK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts0"),             /* SYNC */
+               SUNXI_FUNCTION(0x3, "csi0")),           /* HSYNC */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts0"),             /* DVLD */
+               SUNXI_FUNCTION(0x3, "csi0")),           /* VSYNC */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts0"),             /* D0 */
+               SUNXI_FUNCTION(0x3, "csi0")),           /* D0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts0"),             /* D1 */
+               SUNXI_FUNCTION(0x3, "csi0"),            /* D1 */
+               SUNXI_FUNCTION(0x4, "sim")),            /* VPPEN */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts0"),             /* D2 */
+               SUNXI_FUNCTION(0x3, "csi0")),           /* D2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts0"),             /* D3 */
+               SUNXI_FUNCTION(0x3, "csi0")),           /* D3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts0"),             /* D4 */
+               SUNXI_FUNCTION(0x3, "csi0")),           /* D4 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts0"),             /* D5 */
+               SUNXI_FUNCTION(0x3, "csi0")),           /* D5 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts0"),             /* D6 */
+               SUNXI_FUNCTION(0x3, "csi0")),           /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts0"),             /* D7 */
+               SUNXI_FUNCTION(0x3, "csi0")),           /* D7 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc0"),            /* D1 */
+               SUNXI_FUNCTION(0x4, "jtag")),           /* MSI */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc0"),            /* D0 */
+               SUNXI_FUNCTION(0x4, "jtag")),           /* DI1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc0"),            /* CLK */
                SUNXI_FUNCTION(0x4, "uart0")),          /* TX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc0"),            /* CMD */
+               SUNXI_FUNCTION(0x4, "jtag")),           /* DO1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc0"),            /* D3 */
                SUNXI_FUNCTION(0x4, "uart0")),          /* RX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc0"),            /* D2 */
+               SUNXI_FUNCTION(0x4, "jtag")),           /* CK1 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts1"),             /* CLK */
+               SUNXI_FUNCTION(0x3, "csi1"),            /* PCK */
+               SUNXI_FUNCTION(0x4, "mmc1")),           /* CMD */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts1"),             /* ERR */
+               SUNXI_FUNCTION(0x3, "csi1"),            /* CK */
+               SUNXI_FUNCTION(0x4, "mmc1")),           /* CLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts1"),             /* SYNC */
+               SUNXI_FUNCTION(0x3, "csi1"),            /* HSYNC */
+               SUNXI_FUNCTION(0x4, "mmc1")),           /* D0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts1"),             /* DVLD */
+               SUNXI_FUNCTION(0x3, "csi1"),            /* VSYNC */
+               SUNXI_FUNCTION(0x4, "mmc1")),           /* D1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts1"),             /* D0 */
+               SUNXI_FUNCTION(0x3, "csi1"),            /* D0 */
+               SUNXI_FUNCTION(0x4, "mmc1"),            /* D2 */
+               SUNXI_FUNCTION(0x5, "csi0")),           /* D8 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts1"),             /* D1 */
+               SUNXI_FUNCTION(0x3, "csi1"),            /* D1 */
+               SUNXI_FUNCTION(0x4, "mmc1"),            /* D3 */
+               SUNXI_FUNCTION(0x5, "csi0")),           /* D9 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG6,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts1"),             /* D2 */
+               SUNXI_FUNCTION(0x3, "csi1"),            /* D2 */
+               SUNXI_FUNCTION(0x4, "uart3"),           /* TX */
+               SUNXI_FUNCTION(0x5, "csi0")),           /* D10 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG7,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts1"),             /* D3 */
+               SUNXI_FUNCTION(0x3, "csi1"),            /* D3 */
+               SUNXI_FUNCTION(0x4, "uart3"),           /* RX */
+               SUNXI_FUNCTION(0x5, "csi0")),           /* D11 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG8,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts1"),             /* D4 */
+               SUNXI_FUNCTION(0x3, "csi1"),            /* D4 */
+               SUNXI_FUNCTION(0x4, "uart3"),           /* RTS */
+               SUNXI_FUNCTION(0x5, "csi0")),           /* D12 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts1"),             /* D5 */
+               SUNXI_FUNCTION(0x3, "csi1"),            /* D5 */
+               SUNXI_FUNCTION(0x4, "uart3"),           /* CTS */
+               SUNXI_FUNCTION(0x5, "csi0")),           /* D13 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts1"),             /* D6 */
+               SUNXI_FUNCTION(0x3, "csi1"),            /* D6 */
+               SUNXI_FUNCTION(0x4, "uart4"),           /* TX */
+               SUNXI_FUNCTION(0x5, "csi0")),           /* D14 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ts1"),             /* D7 */
+               SUNXI_FUNCTION(0x3, "csi1"),            /* D7 */
+               SUNXI_FUNCTION(0x4, "uart4"),           /* RX */
+               SUNXI_FUNCTION(0x5, "csi0")),           /* D15 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D0 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAA0 */
+               SUNXI_FUNCTION(0x4, "uart3"),           /* TX */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH1,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D1 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAA1 */
+               SUNXI_FUNCTION(0x4, "uart3"),           /* RX */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D2 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAA2 */
+               SUNXI_FUNCTION(0x4, "uart3"),           /* RTS */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D3 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAIRQ */
+               SUNXI_FUNCTION(0x4, "uart3"),           /* CTS */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D4 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD0 */
+               SUNXI_FUNCTION(0x4, "uart4"),           /* TX */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D4 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D5 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD1 */
+               SUNXI_FUNCTION(0x4, "uart4"),           /* RX */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D5 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH6,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D6 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD2 */
+               SUNXI_FUNCTION(0x4, "uart5"),           /* TX */
+               SUNXI_FUNCTION(0x5, "ms"),              /* BS */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH7,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D7 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD3 */
+               SUNXI_FUNCTION(0x4, "uart5"),           /* RX */
+               SUNXI_FUNCTION(0x5, "ms"),              /* CLK */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D7 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH8,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D8 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD4 */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* IN0 */
+               SUNXI_FUNCTION(0x5, "ms"),              /* D0 */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D8 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH9,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D9 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD5 */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* IN1 */
+               SUNXI_FUNCTION(0x5, "ms"),              /* D1 */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D9 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D10 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD6 */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* IN2 */
+               SUNXI_FUNCTION(0x5, "ms"),              /* D2 */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D10 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH11,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D11 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD7 */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* IN3 */
+               SUNXI_FUNCTION(0x5, "ms"),              /* D3 */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D11 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH12,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D12 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD8 */
+               SUNXI_FUNCTION(0x4, "ps2"),             /* SCK1 */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D12 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH13,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D13 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD9 */
+               SUNXI_FUNCTION(0x4, "ps2"),             /* SDA1 */
+               SUNXI_FUNCTION(0x5, "sim"),             /* RST */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D13 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH14,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D14 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD10 */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* IN4 */
+               SUNXI_FUNCTION(0x5, "sim"),             /* VPPEN */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D14 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH15,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D15 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD11 */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* IN5 */
+               SUNXI_FUNCTION(0x5, "sim"),             /* VPPPP */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D15 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH16,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D16 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD12 */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* IN6 */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D16 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH17,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D17 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD13 */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* IN7 */
+               SUNXI_FUNCTION(0x5, "sim"),             /* VCCEN */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D17 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH18,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D18 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD14 */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT0 */
+               SUNXI_FUNCTION(0x5, "sim"),             /* SCK */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D18 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH19,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D19 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD15 */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT1 */
+               SUNXI_FUNCTION(0x5, "sim"),             /* SDA */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D19 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH20,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D20 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAOE */
+               SUNXI_FUNCTION(0x4, "can"),             /* TX */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D20 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH21,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D21 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATADREQ */
+               SUNXI_FUNCTION(0x4, "can"),             /* RX */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D21 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH22,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D22 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATADACK */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT2 */
+               SUNXI_FUNCTION(0x5, "mmc1"),            /* CMD */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D22 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH23,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* D23 */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATACS0 */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT3 */
+               SUNXI_FUNCTION(0x5, "mmc1"),            /* CLK */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* D23 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH24,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* CLK */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATACS1 */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT4 */
+               SUNXI_FUNCTION(0x5, "mmc1"),            /* D0 */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* PCLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH25,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* DE */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAIORDY */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT5 */
+               SUNXI_FUNCTION(0x5, "mmc1"),            /* D1 */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* FIELD */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH26,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* HSYNC */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAIOR */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT6 */
+               SUNXI_FUNCTION(0x5, "mmc1"),            /* D2 */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* HSYNC */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PH27,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd1"),            /* VSYNC */
+               SUNXI_FUNCTION(0x3, "pata"),            /* ATAIOW */
+               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT7 */
+               SUNXI_FUNCTION(0x5, "mmc1"),            /* D3 */
+               SUNXI_FUNCTION(0x7, "csi1")),           /* VSYNC */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -518,277 +893,401 @@ static const struct sunxi_desc_pin sun4i_a10_pins[] = {
                SUNXI_FUNCTION(0x1, "gpio_out")),
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "pwm")),            /* PWM1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc3")),           /* CMD */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc3")),           /* CLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI6,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc3")),           /* D0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI7,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc3")),           /* D1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI8,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc3")),           /* D2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI9,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc3")),           /* D3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi0"),            /* CS0 */
+               SUNXI_FUNCTION(0x3, "uart5")),          /* TX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI11,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi0"),            /* CLK */
+               SUNXI_FUNCTION(0x3, "uart5")),          /* RX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI12,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi0"),            /* MOSI */
+               SUNXI_FUNCTION(0x3, "uart6")),          /* TX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI13,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi0"),            /* MISO */
+               SUNXI_FUNCTION(0x3, "uart6")),          /* RX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI14,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi0"),            /* CS1 */
+               SUNXI_FUNCTION(0x3, "ps2"),             /* SCK1 */
+               SUNXI_FUNCTION(0x4, "timer4")),         /* TCLKIN0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI15,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi1"),            /* CS1 */
+               SUNXI_FUNCTION(0x3, "ps2"),             /* SDA1 */
+               SUNXI_FUNCTION(0x4, "timer5")),         /* TCLKIN1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI16,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi1"),            /* CS0 */
+               SUNXI_FUNCTION(0x3, "uart2")),          /* RTS */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI17,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi1"),            /* CLK */
+               SUNXI_FUNCTION(0x3, "uart2")),          /* CTS */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI18,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi1"),            /* MOSI */
+               SUNXI_FUNCTION(0x3, "uart2")),          /* TX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI19,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi1"),            /* MISO */
+               SUNXI_FUNCTION(0x3, "uart2")),          /* RX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI20,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ps2"),             /* SCK0 */
+               SUNXI_FUNCTION(0x3, "uart7"),           /* TX */
+               SUNXI_FUNCTION(0x4, "hdmi")),           /* HSCL */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PI21,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ps2"),             /* SDA0 */
+               SUNXI_FUNCTION(0x3, "uart7"),           /* RX */
+               SUNXI_FUNCTION(0x4, "hdmi")),           /* HSDA */
 };
 
 static const struct sunxi_desc_pin sun5i_a13_pins[] = {
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c0")),           /* SCK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c0")),           /* SDA */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "pwm")),
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ir0")),            /* TX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "ir0")),            /* RX */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi2")),           /* CS1 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c1")),           /* SCK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c1")),           /* SDA */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c2")),           /* SCK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "i2c2")),           /* SDA */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NWE */
+               SUNXI_FUNCTION(0x3, "spi0")),           /* MOSI */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NALE */
+               SUNXI_FUNCTION(0x3, "spi0")),           /* MISO */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NCLE */
+               SUNXI_FUNCTION(0x3, "spi0")),           /* CLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NCE1 */
+               SUNXI_FUNCTION(0x3, "spi0")),           /* CS0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),          /* NCE0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0")),          /* NRE */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NRB0 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* CMD */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NRB1 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* CLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ0 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* D0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ1 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* D1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ2 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* D2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ3 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* D3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ4 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* D4 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ5 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* D5 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ6 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ7 */
+               SUNXI_FUNCTION(0x3, "mmc2")),           /* D7 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQS */
+               SUNXI_FUNCTION(0x4, "uart3")),          /* RTS */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D4 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D5 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D7 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D10 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D11 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D12 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D13 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D14 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D15 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D18 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D19 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D20 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D21 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D22 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* D23 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* CLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* DE */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* HSYNC */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "lcd0")),           /* VSYNC */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x3, "csi0"),            /* PCLK */
+               SUNXI_FUNCTION(0x4, "spi2")),           /* CS0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x3, "csi0"),            /* MCLK */
+               SUNXI_FUNCTION(0x4, "spi2")),           /* CLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x3, "csi0"),            /* HSYNC */
+               SUNXI_FUNCTION(0x4, "spi2")),           /* MOSI */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x3, "csi0"),            /* VSYNC */
+               SUNXI_FUNCTION(0x4, "spi2")),           /* MISO */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x3, "csi0"),            /* D0 */
+               SUNXI_FUNCTION(0x4, "mmc2")),           /* D0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x3, "csi0"),            /* D1 */
+               SUNXI_FUNCTION(0x4, "mmc2")),           /* D1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x3, "csi0"),            /* D2 */
+               SUNXI_FUNCTION(0x4, "mmc2")),           /* D2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x3, "csi0"),            /* D3 */
+               SUNXI_FUNCTION(0x4, "mmc2")),           /* D3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x3, "csi0"),            /* D4 */
+               SUNXI_FUNCTION(0x4, "mmc2")),           /* CMD */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x3, "csi0"),            /* D5 */
+               SUNXI_FUNCTION(0x4, "mmc2")),           /* CLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x3, "csi0"),            /* D6 */
                SUNXI_FUNCTION(0x4, "uart1")),          /* TX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x3, "csi0"),            /* D7 */
                SUNXI_FUNCTION(0x4, "uart1")),          /* RX */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x4, "mmc0")),           /* D1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x4, "mmc0")),           /* D0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x4, "mmc0")),           /* CLK */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x4, "mmc0")),           /* CMD */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x4, "mmc0")),           /* D3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x4, "mmc0")),           /* D2 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
                SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -802,24 +1301,34 @@ static const struct sunxi_desc_pin sun5i_a13_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc1"),            /* CMD */
                SUNXI_FUNCTION(0x4, "uart1")),          /* TX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
                SUNXI_FUNCTION(0x0, "gpio_in"),
                SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "mmc1"),            /* CLK */
                SUNXI_FUNCTION(0x4, "uart1")),          /* RX */
-       /* Hole */
+/* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi1"),            /* CS0 */
+               SUNXI_FUNCTION(0x3, "uart3")),          /* TX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi1"),            /* CLK */
+               SUNXI_FUNCTION(0x3, "uart3")),          /* RX */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi1"),            /* MOSI */
+               SUNXI_FUNCTION(0x3, "uart3")),          /* CTS */
        SUNXI_PIN(SUNXI_PINCTRL_PIN_PG12,
                SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
+               SUNXI_FUNCTION(0x1, "gpio_out"),
+               SUNXI_FUNCTION(0x2, "spi1"),            /* MISO */
+               SUNXI_FUNCTION(0x3, "uart3")),          /* RTS */
 };
 
 static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
@@ -1029,7 +1538,7 @@ static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
        kfree(map);
 }
 
-static struct pinctrl_ops sunxi_pctrl_ops = {
+static const struct pinctrl_ops sunxi_pctrl_ops = {
        .dt_node_to_map         = sunxi_pctrl_dt_node_to_map,
        .dt_free_map            = sunxi_pctrl_dt_free_map,
        .get_groups_count       = sunxi_pctrl_get_groups_count,
@@ -1098,7 +1607,7 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
        return 0;
 }
 
-static struct pinconf_ops sunxi_pconf_ops = {
+static const struct pinconf_ops sunxi_pconf_ops = {
        .pin_config_group_get   = sunxi_pconf_group_get,
        .pin_config_group_set   = sunxi_pconf_group_set,
 };
@@ -1204,7 +1713,7 @@ error:
        return ret;
 }
 
-static struct pinmux_ops sunxi_pmx_ops = {
+static const struct pinmux_ops sunxi_pmx_ops = {
        .get_functions_count    = sunxi_pmx_get_funcs_cnt,
        .get_function_name      = sunxi_pmx_get_func_name,
        .get_function_groups    = sunxi_pmx_get_func_groups,
@@ -1409,6 +1918,7 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev)
        struct pinctrl_pin_desc *pins;
        struct sunxi_pinctrl *pctl;
        int i, ret, last_pin;
+       struct clk *clk;
 
        pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
        if (!pctl)
@@ -1479,6 +1989,12 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev)
                        goto gpiochip_error;
        }
 
+       clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk))
+               goto gpiochip_error;
+
+       clk_prepare_enable(clk);
+
        dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
 
        return 0;
index f195d77..2fa9bc6 100644 (file)
@@ -316,7 +316,7 @@ static int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
        return 0;
 }
 
-static struct pinctrl_ops tegra_pinctrl_ops = {
+static const struct pinctrl_ops tegra_pinctrl_ops = {
        .get_groups_count = tegra_pinctrl_get_groups_count,
        .get_group_name = tegra_pinctrl_get_group_name,
        .get_group_pins = tegra_pinctrl_get_group_pins,
@@ -401,7 +401,7 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
        pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
 }
 
-static struct pinmux_ops tegra_pinmux_ops = {
+static const struct pinmux_ops tegra_pinmux_ops = {
        .get_functions_count = tegra_pinctrl_get_funcs_count,
        .get_function_name = tegra_pinctrl_get_func_name,
        .get_function_groups = tegra_pinctrl_get_func_groups,
@@ -676,7 +676,7 @@ static void tegra_pinconf_config_dbg_show(struct pinctrl_dev *pctldev,
 }
 #endif
 
-static struct pinconf_ops tegra_pinconf_ops = {
+static const struct pinconf_ops tegra_pinconf_ops = {
        .pin_config_get = tegra_pinconf_get,
        .pin_config_set = tegra_pinconf_set,
        .pin_config_group_get = tegra_pinconf_group_get,
index 2b57725..6a3a750 100644 (file)
@@ -860,7 +860,7 @@ static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
        seq_printf(s, " " DRIVER_NAME);
 }
 
-static struct pinctrl_ops u300_pctrl_ops = {
+static const struct pinctrl_ops u300_pctrl_ops = {
        .get_groups_count = u300_get_groups_count,
        .get_group_name = u300_get_group_name,
        .get_group_pins = u300_get_group_pins,
@@ -1003,7 +1003,7 @@ static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
        return 0;
 }
 
-static struct pinmux_ops u300_pmx_ops = {
+static const struct pinmux_ops u300_pmx_ops = {
        .get_functions_count = u300_pmx_get_funcs_count,
        .get_function_name = u300_pmx_get_func_name,
        .get_function_groups = u300_pmx_get_groups,
@@ -1046,7 +1046,7 @@ static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
        return 0;
 }
 
-static struct pinconf_ops u300_pconf_ops = {
+static const struct pinconf_ops u300_pconf_ops = {
        .is_generic = true,
        .pin_config_get = u300_pin_config_get,
        .pin_config_set = u300_pin_config_set,
index 068224e..f2977cf 100644 (file)
@@ -553,7 +553,7 @@ int xway_pinconf_group_set(struct pinctrl_dev *pctldev,
        return ret;
 }
 
-static struct pinconf_ops xway_pinconf_ops = {
+static const struct pinconf_ops xway_pinconf_ops = {
        .pin_config_get = xway_pinconf_get,
        .pin_config_set = xway_pinconf_set,
        .pin_config_group_set = xway_pinconf_group_set,
index bd83c8b..88cc509 100644 (file)
@@ -506,7 +506,7 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
        if (!pmxops)
                return 0;
 
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pctldev->mutex);
        nfuncs = pmxops->get_functions_count(pctldev);
        while (func_selector < nfuncs) {
                const char *func = pmxops->get_function_name(pctldev,
@@ -530,7 +530,7 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
                func_selector++;
        }
 
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
 
        return 0;
 }
@@ -548,7 +548,7 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
        seq_puts(s, "Pinmux settings per pin\n");
        seq_puts(s, "Format: pin (name): mux_owner gpio_owner hog?\n");
 
-       mutex_lock(&pinctrl_mutex);
+       mutex_lock(&pctldev->mutex);
 
        /* The pin number can be retrived from the pin controller descriptor */
        for (i = 0; i < pctldev->desc->npins; i++) {
@@ -583,7 +583,7 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
                        seq_printf(s, "\n");
        }
 
-       mutex_unlock(&pinctrl_mutex);
+       mutex_unlock(&pctldev->mutex);
 
        return 0;
 }
index 6a7dae7..116da04 100644 (file)
@@ -198,7 +198,7 @@ static void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
        kfree(map);
 }
 
-static struct pinctrl_ops spear_pinctrl_ops = {
+static const struct pinctrl_ops spear_pinctrl_ops = {
        .get_groups_count = spear_pinctrl_get_groups_cnt,
        .get_group_name = spear_pinctrl_get_group_name,
        .get_group_pins = spear_pinctrl_get_group_pins,
@@ -340,7 +340,7 @@ static void gpio_disable_free(struct pinctrl_dev *pctldev,
        gpio_request_endisable(pctldev, range, offset, false);
 }
 
-static struct pinmux_ops spear_pinmux_ops = {
+static const struct pinmux_ops spear_pinmux_ops = {
        .get_functions_count = spear_pinctrl_get_funcs_count,
        .get_function_name = spear_pinctrl_get_func_name,
        .get_function_groups = spear_pinctrl_get_func_groups,
index 45cacf7..1a779bb 100644 (file)
@@ -134,7 +134,6 @@ static const struct key_entry hp_wmi_keymap[] = {
        { KE_KEY, 0x2142, { KEY_MEDIA } },
        { KE_KEY, 0x213b, { KEY_INFO } },
        { KE_KEY, 0x2169, { KEY_DIRECTION } },
-       { KE_KEY, 0x216a, { KEY_SETUP } },
        { KE_KEY, 0x231b, { KEY_HELP } },
        { KE_END, 0 }
 };
@@ -925,9 +924,6 @@ static int __init hp_wmi_init(void)
                err = hp_wmi_input_setup();
                if (err)
                        return err;
-               
-               //Enable magic for hotkeys that run on the SMBus
-               ec_write(0xe6,0x6e);
        }
 
        if (bios_capable) {
index 9a90756..edec135 100644 (file)
@@ -1964,9 +1964,6 @@ struct tp_nvram_state {
 /* kthread for the hotkey poller */
 static struct task_struct *tpacpi_hotkey_task;
 
-/* Acquired while the poller kthread is running, use to sync start/stop */
-static struct mutex hotkey_thread_mutex;
-
 /*
  * Acquire mutex to write poller control variables as an
  * atomic block.
@@ -2462,8 +2459,6 @@ static int hotkey_kthread(void *data)
        unsigned int poll_freq;
        bool was_frozen;
 
-       mutex_lock(&hotkey_thread_mutex);
-
        if (tpacpi_lifecycle == TPACPI_LIFE_EXITING)
                goto exit;
 
@@ -2523,7 +2518,6 @@ static int hotkey_kthread(void *data)
        }
 
 exit:
-       mutex_unlock(&hotkey_thread_mutex);
        return 0;
 }
 
@@ -2533,9 +2527,6 @@ static void hotkey_poll_stop_sync(void)
        if (tpacpi_hotkey_task) {
                kthread_stop(tpacpi_hotkey_task);
                tpacpi_hotkey_task = NULL;
-               mutex_lock(&hotkey_thread_mutex);
-               /* at this point, the thread did exit */
-               mutex_unlock(&hotkey_thread_mutex);
        }
 }
 
@@ -3234,7 +3225,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
        mutex_init(&hotkey_mutex);
 
 #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
-       mutex_init(&hotkey_thread_mutex);
        mutex_init(&hotkey_thread_data_mutex);
 #endif
 
index f1b7fdc..82758cb 100644 (file)
@@ -246,7 +246,7 @@ static struct dentry *dasd_debugfs_setup(const char *name,
 static int dasd_state_known_to_basic(struct dasd_device *device)
 {
        struct dasd_block *block = device->block;
-       int rc;
+       int rc = 0;
 
        /* Allocate and register gendisk structure. */
        if (block) {
@@ -273,7 +273,8 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
        DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
 
        device->state = DASD_STATE_BASIC;
-       return 0;
+
+       return rc;
 }
 
 /*
@@ -282,6 +283,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
 static int dasd_state_basic_to_known(struct dasd_device *device)
 {
        int rc;
+
        if (device->block) {
                dasd_profile_exit(&device->block->profile);
                if (device->block->debugfs_dentry)
@@ -332,8 +334,10 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
                if (block->base->discipline->do_analysis != NULL)
                        rc = block->base->discipline->do_analysis(block);
                if (rc) {
-                       if (rc != -EAGAIN)
+                       if (rc != -EAGAIN) {
                                device->state = DASD_STATE_UNFMT;
+                               goto out;
+                       }
                        return rc;
                }
                dasd_setup_queue(block);
@@ -341,11 +345,16 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
                             block->blocks << block->s2b_shift);
                device->state = DASD_STATE_READY;
                rc = dasd_scan_partitions(block);
-               if (rc)
+               if (rc) {
                        device->state = DASD_STATE_BASIC;
+                       return rc;
+               }
        } else {
                device->state = DASD_STATE_READY;
        }
+out:
+       if (device->discipline->basic_to_ready)
+               rc = device->discipline->basic_to_ready(device);
        return rc;
 }
 
@@ -368,6 +377,11 @@ static int dasd_state_ready_to_basic(struct dasd_device *device)
 {
        int rc;
 
+       if (device->discipline->ready_to_basic) {
+               rc = device->discipline->ready_to_basic(device);
+               if (rc)
+                       return rc;
+       }
        device->state = DASD_STATE_BASIC;
        if (device->block) {
                struct dasd_block *block = device->block;
@@ -402,16 +416,10 @@ static int dasd_state_unfmt_to_basic(struct dasd_device *device)
 static int
 dasd_state_ready_to_online(struct dasd_device * device)
 {
-       int rc;
        struct gendisk *disk;
        struct disk_part_iter piter;
        struct hd_struct *part;
 
-       if (device->discipline->ready_to_online) {
-               rc = device->discipline->ready_to_online(device);
-               if (rc)
-                       return rc;
-       }
        device->state = DASD_STATE_ONLINE;
        if (device->block) {
                dasd_schedule_block_bh(device->block);
@@ -444,6 +452,7 @@ static int dasd_state_online_to_ready(struct dasd_device *device)
                if (rc)
                        return rc;
        }
+
        device->state = DASD_STATE_READY;
        if (device->block && !(device->features & DASD_FEATURE_USERAW)) {
                disk = device->block->bdev->bd_disk;
@@ -2223,6 +2232,77 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
        return rc;
 }
 
+static inline int _wait_for_wakeup_queue(struct list_head *ccw_queue)
+{
+       struct dasd_ccw_req *cqr;
+
+       list_for_each_entry(cqr, ccw_queue, blocklist) {
+               if (cqr->callback_data != DASD_SLEEPON_END_TAG)
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int _dasd_sleep_on_queue(struct list_head *ccw_queue, int interruptible)
+{
+       struct dasd_device *device;
+       int rc;
+       struct dasd_ccw_req *cqr, *n;
+
+retry:
+       list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
+               device = cqr->startdev;
+               if (cqr->status != DASD_CQR_FILLED) /*could be failed*/
+                       continue;
+
+               if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) &&
+                   !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
+                       cqr->status = DASD_CQR_FAILED;
+                       cqr->intrc = -EPERM;
+                       continue;
+               }
+               /*Non-temporary stop condition will trigger fail fast*/
+               if (device->stopped & ~DASD_STOPPED_PENDING &&
+                   test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+                   !dasd_eer_enabled(device)) {
+                       cqr->status = DASD_CQR_FAILED;
+                       cqr->intrc = -EAGAIN;
+                       continue;
+               }
+
+               /*Don't try to start requests if device is stopped*/
+               if (interruptible) {
+                       rc = wait_event_interruptible(
+                               generic_waitq, !device->stopped);
+                       if (rc == -ERESTARTSYS) {
+                               cqr->status = DASD_CQR_FAILED;
+                               cqr->intrc = rc;
+                               continue;
+                       }
+               } else
+                       wait_event(generic_waitq, !(device->stopped));
+
+               if (!cqr->callback)
+                       cqr->callback = dasd_wakeup_cb;
+               cqr->callback_data = DASD_SLEEPON_START_TAG;
+               dasd_add_request_tail(cqr);
+       }
+
+       wait_event(generic_waitq, _wait_for_wakeup_queue(ccw_queue));
+
+       rc = 0;
+       list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
+               if (__dasd_sleep_on_erp(cqr))
+                       rc = 1;
+       }
+       if (rc)
+               goto retry;
+
+
+       return 0;
+}
+
 /*
  * Queue a request to the tail of the device ccw_queue and wait for
  * it's completion.
@@ -2233,6 +2313,15 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr)
 }
 
 /*
+ * Start requests from a ccw_queue and wait for their completion.
+ */
+int dasd_sleep_on_queue(struct list_head *ccw_queue)
+{
+       return _dasd_sleep_on_queue(ccw_queue, 0);
+}
+EXPORT_SYMBOL(dasd_sleep_on_queue);
+
+/*
  * Queue a request to the tail of the device ccw_queue and wait
  * interruptible for it's completion.
  */
@@ -2663,6 +2752,26 @@ static void _dasd_wake_block_flush_cb(struct dasd_ccw_req *cqr, void *data)
 }
 
 /*
+ * Requeue a request back to the block request queue
+ * only works for block requests
+ */
+static int _dasd_requeue_request(struct dasd_ccw_req *cqr)
+{
+       struct dasd_block *block = cqr->block;
+       struct request *req;
+       unsigned long flags;
+
+       if (!block)
+               return -EINVAL;
+       spin_lock_irqsave(&block->queue_lock, flags);
+       req = (struct request *) cqr->callback_data;
+       blk_requeue_request(block->request_queue, req);
+       spin_unlock_irqrestore(&block->queue_lock, flags);
+
+       return 0;
+}
+
+/*
  * Go through all request on the dasd_block request queue, cancel them
  * on the respective dasd_device, and return them to the generic
  * block layer.
@@ -3380,10 +3489,11 @@ EXPORT_SYMBOL_GPL(dasd_generic_verify_path);
 
 int dasd_generic_pm_freeze(struct ccw_device *cdev)
 {
+       struct dasd_device *device = dasd_device_from_cdev(cdev);
+       struct list_head freeze_queue;
        struct dasd_ccw_req *cqr, *n;
+       struct dasd_ccw_req *refers;
        int rc;
-       struct list_head freeze_queue;
-       struct dasd_device *device = dasd_device_from_cdev(cdev);
 
        if (IS_ERR(device))
                return PTR_ERR(device);
@@ -3396,7 +3506,8 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
 
        /* disallow new I/O  */
        dasd_device_set_stop_bits(device, DASD_STOPPED_PM);
-       /* clear active requests */
+
+       /* clear active requests and requeue them to block layer if possible */
        INIT_LIST_HEAD(&freeze_queue);
        spin_lock_irq(get_ccwdev_lock(cdev));
        rc = 0;
@@ -3416,7 +3527,6 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
                }
                list_move_tail(&cqr->devlist, &freeze_queue);
        }
-
        spin_unlock_irq(get_ccwdev_lock(cdev));
 
        list_for_each_entry_safe(cqr, n, &freeze_queue, devlist) {
@@ -3424,12 +3534,38 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
                           (cqr->status != DASD_CQR_CLEAR_PENDING));
                if (cqr->status == DASD_CQR_CLEARED)
                        cqr->status = DASD_CQR_QUEUED;
+
+               /* requeue requests to blocklayer will only work for
+                  block device requests */
+               if (_dasd_requeue_request(cqr))
+                       continue;
+
+               /* remove requests from device and block queue */
+               list_del_init(&cqr->devlist);
+               while (cqr->refers != NULL) {
+                       refers = cqr->refers;
+                       /* remove the request from the block queue */
+                       list_del(&cqr->blocklist);
+                       /* free the finished erp request */
+                       dasd_free_erp_request(cqr, cqr->memdev);
+                       cqr = refers;
+               }
+               if (cqr->block)
+                       list_del_init(&cqr->blocklist);
+               cqr->block->base->discipline->free_cp(
+                       cqr, (struct request *) cqr->callback_data);
        }
-       /* move freeze_queue to start of the ccw_queue */
-       spin_lock_irq(get_ccwdev_lock(cdev));
-       list_splice_tail(&freeze_queue, &device->ccw_queue);
-       spin_unlock_irq(get_ccwdev_lock(cdev));
 
+       /*
+        * if requests remain then they are internal request
+        * and go back to the device queue
+        */
+       if (!list_empty(&freeze_queue)) {
+               /* move freeze_queue to start of the ccw_queue */
+               spin_lock_irq(get_ccwdev_lock(cdev));
+               list_splice_tail(&freeze_queue, &device->ccw_queue);
+               spin_unlock_irq(get_ccwdev_lock(cdev));
+       }
        dasd_put_device(device);
        return rc;
 }
index c196827..a71bb8a 100644 (file)
@@ -410,8 +410,7 @@ dasd_add_busid(const char *bus_id, int features)
        struct dasd_devmap *devmap, *new, *tmp;
        int hash;
 
-       new = (struct dasd_devmap *)
-               kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
+       new = kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
        if (!new)
                return ERR_PTR(-ENOMEM);
        spin_lock(&dasd_devmap_lock);
index 6999fd9..6a44b27 100644 (file)
@@ -2022,7 +2022,7 @@ static int dasd_eckd_do_analysis(struct dasd_block *block)
                return dasd_eckd_end_analysis(block);
 }
 
-static int dasd_eckd_ready_to_online(struct dasd_device *device)
+static int dasd_eckd_basic_to_ready(struct dasd_device *device)
 {
        return dasd_alias_add_device(device);
 };
@@ -2031,6 +2031,11 @@ static int dasd_eckd_online_to_ready(struct dasd_device *device)
 {
        cancel_work_sync(&device->reload_device);
        cancel_work_sync(&device->kick_validate);
+       return 0;
+};
+
+static int dasd_eckd_ready_to_basic(struct dasd_device *device)
+{
        return dasd_alias_remove_device(device);
 };
 
@@ -2050,45 +2055,34 @@ dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
 }
 
 static struct dasd_ccw_req *
-dasd_eckd_format_device(struct dasd_device * device,
-                       struct format_data_t * fdata)
+dasd_eckd_build_format(struct dasd_device *base,
+                      struct format_data_t *fdata)
 {
-       struct dasd_eckd_private *private;
+       struct dasd_eckd_private *base_priv;
+       struct dasd_eckd_private *start_priv;
+       struct dasd_device *startdev;
        struct dasd_ccw_req *fcp;
        struct eckd_count *ect;
+       struct ch_t address;
        struct ccw1 *ccw;
        void *data;
        int rpt;
-       struct ch_t address;
        int cplength, datasize;
-       int i;
+       int i, j;
        int intensity = 0;
        int r0_perm;
+       int nr_tracks;
 
-       private = (struct dasd_eckd_private *) device->private;
-       rpt = recs_per_track(&private->rdc_data, 0, fdata->blksize);
-       set_ch_t(&address,
-                fdata->start_unit / private->rdc_data.trk_per_cyl,
-                fdata->start_unit % private->rdc_data.trk_per_cyl);
+       startdev = dasd_alias_get_start_dev(base);
+       if (!startdev)
+               startdev = base;
 
-       /* Sanity checks. */
-       if (fdata->start_unit >=
-           (private->real_cyl * private->rdc_data.trk_per_cyl)) {
-               dev_warn(&device->cdev->dev, "Start track number %d used in "
-                        "formatting is too big\n", fdata->start_unit);
-               return ERR_PTR(-EINVAL);
-       }
-       if (fdata->start_unit > fdata->stop_unit) {
-               dev_warn(&device->cdev->dev, "Start track %d used in "
-                        "formatting exceeds end track\n", fdata->start_unit);
-               return ERR_PTR(-EINVAL);
-       }
-       if (dasd_check_blocksize(fdata->blksize) != 0) {
-               dev_warn(&device->cdev->dev,
-                        "The DASD cannot be formatted with block size %d\n",
-                        fdata->blksize);
-               return ERR_PTR(-EINVAL);
-       }
+       start_priv = (struct dasd_eckd_private *) startdev->private;
+       base_priv = (struct dasd_eckd_private *) base->private;
+
+       rpt = recs_per_track(&base_priv->rdc_data, 0, fdata->blksize);
+
+       nr_tracks = fdata->stop_unit - fdata->start_unit + 1;
 
        /*
         * fdata->intensity is a bit string that tells us what to do:
@@ -2106,149 +2100,282 @@ dasd_eckd_format_device(struct dasd_device * device,
                r0_perm = 1;
                intensity = fdata->intensity;
        }
+
        switch (intensity) {
        case 0x00:      /* Normal format */
        case 0x08:      /* Normal format, use cdl. */
-               cplength = 2 + rpt;
-               datasize = sizeof(struct DE_eckd_data) +
+               cplength = 2 + (rpt*nr_tracks);
+               datasize = sizeof(struct PFX_eckd_data) +
                        sizeof(struct LO_eckd_data) +
-                       rpt * sizeof(struct eckd_count);
+                       rpt * nr_tracks * sizeof(struct eckd_count);
                break;
        case 0x01:      /* Write record zero and format track. */
        case 0x09:      /* Write record zero and format track, use cdl. */
-               cplength = 3 + rpt;
-               datasize = sizeof(struct DE_eckd_data) +
+               cplength = 2 + rpt * nr_tracks;
+               datasize = sizeof(struct PFX_eckd_data) +
                        sizeof(struct LO_eckd_data) +
                        sizeof(struct eckd_count) +
-                       rpt * sizeof(struct eckd_count);
+                       rpt * nr_tracks * sizeof(struct eckd_count);
                break;
        case 0x04:      /* Invalidate track. */
        case 0x0c:      /* Invalidate track, use cdl. */
                cplength = 3;
-               datasize = sizeof(struct DE_eckd_data) +
+               datasize = sizeof(struct PFX_eckd_data) +
                        sizeof(struct LO_eckd_data) +
                        sizeof(struct eckd_count);
                break;
        default:
-               dev_warn(&device->cdev->dev, "An I/O control call used "
-                        "incorrect flags 0x%x\n", fdata->intensity);
+               dev_warn(&startdev->cdev->dev,
+                        "An I/O control call used incorrect flags 0x%x\n",
+                        fdata->intensity);
                return ERR_PTR(-EINVAL);
        }
        /* Allocate the format ccw request. */
-       fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device);
+       fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength,
+                                  datasize, startdev);
        if (IS_ERR(fcp))
                return fcp;
 
+       start_priv->count++;
        data = fcp->data;
        ccw = fcp->cpaddr;
 
        switch (intensity & ~0x08) {
        case 0x00: /* Normal format. */
-               define_extent(ccw++, (struct DE_eckd_data *) data,
-                             fdata->start_unit, fdata->start_unit,
-                             DASD_ECKD_CCW_WRITE_CKD, device);
+               prefix(ccw++, (struct PFX_eckd_data *) data,
+                      fdata->start_unit, fdata->stop_unit,
+                      DASD_ECKD_CCW_WRITE_CKD, base, startdev);
                /* grant subsystem permission to format R0 */
                if (r0_perm)
-                       ((struct DE_eckd_data *)data)->ga_extended |= 0x04;
-               data += sizeof(struct DE_eckd_data);
+                       ((struct PFX_eckd_data *)data)
+                               ->define_extent.ga_extended |= 0x04;
+               data += sizeof(struct PFX_eckd_data);
                ccw[-1].flags |= CCW_FLAG_CC;
                locate_record(ccw++, (struct LO_eckd_data *) data,
-                             fdata->start_unit, 0, rpt,
-                             DASD_ECKD_CCW_WRITE_CKD, device,
+                             fdata->start_unit, 0, rpt*nr_tracks,
+                             DASD_ECKD_CCW_WRITE_CKD, base,
                              fdata->blksize);
                data += sizeof(struct LO_eckd_data);
                break;
        case 0x01: /* Write record zero + format track. */
-               define_extent(ccw++, (struct DE_eckd_data *) data,
-                             fdata->start_unit, fdata->start_unit,
-                             DASD_ECKD_CCW_WRITE_RECORD_ZERO,
-                             device);
-               data += sizeof(struct DE_eckd_data);
+               prefix(ccw++, (struct PFX_eckd_data *) data,
+                      fdata->start_unit, fdata->stop_unit,
+                      DASD_ECKD_CCW_WRITE_RECORD_ZERO,
+                      base, startdev);
+               data += sizeof(struct PFX_eckd_data);
                ccw[-1].flags |= CCW_FLAG_CC;
                locate_record(ccw++, (struct LO_eckd_data *) data,
-                             fdata->start_unit, 0, rpt + 1,
-                             DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
-                             device->block->bp_block);
+                             fdata->start_unit, 0, rpt * nr_tracks + 1,
+                             DASD_ECKD_CCW_WRITE_RECORD_ZERO, base,
+                             base->block->bp_block);
                data += sizeof(struct LO_eckd_data);
                break;
        case 0x04: /* Invalidate track. */
-               define_extent(ccw++, (struct DE_eckd_data *) data,
-                             fdata->start_unit, fdata->start_unit,
-                             DASD_ECKD_CCW_WRITE_CKD, device);
-               data += sizeof(struct DE_eckd_data);
+               prefix(ccw++, (struct PFX_eckd_data *) data,
+                      fdata->start_unit, fdata->stop_unit,
+                      DASD_ECKD_CCW_WRITE_CKD, base, startdev);
+               data += sizeof(struct PFX_eckd_data);
                ccw[-1].flags |= CCW_FLAG_CC;
                locate_record(ccw++, (struct LO_eckd_data *) data,
                              fdata->start_unit, 0, 1,
-                             DASD_ECKD_CCW_WRITE_CKD, device, 8);
+                             DASD_ECKD_CCW_WRITE_CKD, base, 8);
                data += sizeof(struct LO_eckd_data);
                break;
        }
-       if (intensity & 0x01) { /* write record zero */
-               ect = (struct eckd_count *) data;
-               data += sizeof(struct eckd_count);
-               ect->cyl = address.cyl;
-               ect->head = address.head;
-               ect->record = 0;
-               ect->kl = 0;
-               ect->dl = 8;
-               ccw[-1].flags |= CCW_FLAG_CC;
-               ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
-               ccw->flags = CCW_FLAG_SLI;
-               ccw->count = 8;
-               ccw->cda = (__u32)(addr_t) ect;
-               ccw++;
-       }
-       if ((intensity & ~0x08) & 0x04) {       /* erase track */
-               ect = (struct eckd_count *) data;
-               data += sizeof(struct eckd_count);
-               ect->cyl = address.cyl;
-               ect->head = address.head;
-               ect->record = 1;
-               ect->kl = 0;
-               ect->dl = 0;
-               ccw[-1].flags |= CCW_FLAG_CC;
-               ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
-               ccw->flags = CCW_FLAG_SLI;
-               ccw->count = 8;
-               ccw->cda = (__u32)(addr_t) ect;
-       } else {                /* write remaining records */
-               for (i = 0; i < rpt; i++) {
+
+       for (j = 0; j < nr_tracks; j++) {
+               /* calculate cylinder and head for the current track */
+               set_ch_t(&address,
+                        (fdata->start_unit + j) /
+                        base_priv->rdc_data.trk_per_cyl,
+                        (fdata->start_unit + j) %
+                        base_priv->rdc_data.trk_per_cyl);
+               if (intensity & 0x01) { /* write record zero */
                        ect = (struct eckd_count *) data;
                        data += sizeof(struct eckd_count);
                        ect->cyl = address.cyl;
                        ect->head = address.head;
-                       ect->record = i + 1;
+                       ect->record = 0;
                        ect->kl = 0;
-                       ect->dl = fdata->blksize;
-                       /* Check for special tracks 0-1 when formatting CDL */
-                       if ((intensity & 0x08) &&
-                           fdata->start_unit == 0) {
-                               if (i < 3) {
-                                       ect->kl = 4;
-                                       ect->dl = sizes_trk0[i] - 4;
-                               }
-                       }
-                       if ((intensity & 0x08) &&
-                           fdata->start_unit == 1) {
-                               ect->kl = 44;
-                               ect->dl = LABEL_SIZE - 44;
-                       }
+                       ect->dl = 8;
                        ccw[-1].flags |= CCW_FLAG_CC;
-                       ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
+                       ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
                        ccw->flags = CCW_FLAG_SLI;
                        ccw->count = 8;
                        ccw->cda = (__u32)(addr_t) ect;
                        ccw++;
                }
+               if ((intensity & ~0x08) & 0x04) {       /* erase track */
+                       ect = (struct eckd_count *) data;
+                       data += sizeof(struct eckd_count);
+                       ect->cyl = address.cyl;
+                       ect->head = address.head;
+                       ect->record = 1;
+                       ect->kl = 0;
+                       ect->dl = 0;
+                       ccw[-1].flags |= CCW_FLAG_CC;
+                       ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
+                       ccw->flags = CCW_FLAG_SLI;
+                       ccw->count = 8;
+                       ccw->cda = (__u32)(addr_t) ect;
+               } else {                /* write remaining records */
+                       for (i = 0; i < rpt; i++) {
+                               ect = (struct eckd_count *) data;
+                               data += sizeof(struct eckd_count);
+                               ect->cyl = address.cyl;
+                               ect->head = address.head;
+                               ect->record = i + 1;
+                               ect->kl = 0;
+                               ect->dl = fdata->blksize;
+                               /*
+                                * Check for special tracks 0-1
+                                * when formatting CDL
+                                */
+                               if ((intensity & 0x08) &&
+                                   fdata->start_unit == 0) {
+                                       if (i < 3) {
+                                               ect->kl = 4;
+                                               ect->dl = sizes_trk0[i] - 4;
+                                       }
+                               }
+                               if ((intensity & 0x08) &&
+                                   fdata->start_unit == 1) {
+                                       ect->kl = 44;
+                                       ect->dl = LABEL_SIZE - 44;
+                               }
+                               ccw[-1].flags |= CCW_FLAG_CC;
+                               if (i != 0 || j == 0)
+                                       ccw->cmd_code =
+                                               DASD_ECKD_CCW_WRITE_CKD;
+                               else
+                                       ccw->cmd_code =
+                                               DASD_ECKD_CCW_WRITE_CKD_MT;
+                               ccw->flags = CCW_FLAG_SLI;
+                               ccw->count = 8;
+                                       ccw->cda = (__u32)(addr_t) ect;
+                                       ccw++;
+                       }
+               }
        }
-       fcp->startdev = device;
-       fcp->memdev = device;
+
+       fcp->startdev = startdev;
+       fcp->memdev = startdev;
        fcp->retries = 256;
+       fcp->expires = startdev->default_expires * HZ;
        fcp->buildclk = get_tod_clock();
        fcp->status = DASD_CQR_FILLED;
+
        return fcp;
 }
 
+static int
+dasd_eckd_format_device(struct dasd_device *base,
+                       struct format_data_t *fdata)
+{
+       struct dasd_ccw_req *cqr, *n;
+       struct dasd_block *block;
+       struct dasd_eckd_private *private;
+       struct list_head format_queue;
+       struct dasd_device *device;
+       int old_stop, format_step;
+       int step, rc = 0;
+
+       block = base->block;
+       private = (struct dasd_eckd_private *) base->private;
+
+       /* Sanity checks. */
+       if (fdata->start_unit >=
+           (private->real_cyl * private->rdc_data.trk_per_cyl)) {
+               dev_warn(&base->cdev->dev,
+                        "Start track number %u used in formatting is too big\n",
+                        fdata->start_unit);
+               return -EINVAL;
+       }
+       if (fdata->stop_unit >=
+           (private->real_cyl * private->rdc_data.trk_per_cyl)) {
+               dev_warn(&base->cdev->dev,
+                        "Stop track number %u used in formatting is too big\n",
+                        fdata->stop_unit);
+               return -EINVAL;
+       }
+       if (fdata->start_unit > fdata->stop_unit) {
+               dev_warn(&base->cdev->dev,
+                        "Start track %u used in formatting exceeds end track\n",
+                        fdata->start_unit);
+               return -EINVAL;
+       }
+       if (dasd_check_blocksize(fdata->blksize) != 0) {
+               dev_warn(&base->cdev->dev,
+                        "The DASD cannot be formatted with block size %u\n",
+                        fdata->blksize);
+               return -EINVAL;
+       }
+
+       INIT_LIST_HEAD(&format_queue);
+       old_stop = fdata->stop_unit;
+
+       while (fdata->start_unit <= 1) {
+               fdata->stop_unit = fdata->start_unit;
+               cqr = dasd_eckd_build_format(base, fdata);
+               list_add(&cqr->blocklist, &format_queue);
+
+               fdata->stop_unit = old_stop;
+               fdata->start_unit++;
+
+               if (fdata->start_unit > fdata->stop_unit)
+                       goto sleep;
+       }
+
+retry:
+       format_step = 255 / recs_per_track(&private->rdc_data, 0,
+                                          fdata->blksize);
+       while (fdata->start_unit <= old_stop) {
+               step = fdata->stop_unit - fdata->start_unit + 1;
+               if (step > format_step)
+                       fdata->stop_unit = fdata->start_unit + format_step - 1;
+
+               cqr = dasd_eckd_build_format(base, fdata);
+               if (IS_ERR(cqr)) {
+                       if (PTR_ERR(cqr) == -ENOMEM) {
+                               /*
+                                * not enough memory available
+                                * go to out and start requests
+                                * retry after first requests were finished
+                                */
+                               fdata->stop_unit = old_stop;
+                               goto sleep;
+                       } else
+                               return PTR_ERR(cqr);
+               }
+               list_add(&cqr->blocklist, &format_queue);
+
+               fdata->start_unit = fdata->stop_unit + 1;
+               fdata->stop_unit = old_stop;
+       }
+
+sleep:
+       dasd_sleep_on_queue(&format_queue);
+
+       list_for_each_entry_safe(cqr, n, &format_queue, blocklist) {
+               device = cqr->startdev;
+               private = (struct dasd_eckd_private *) device->private;
+               if (cqr->status == DASD_CQR_FAILED)
+                       rc = -EIO;
+               list_del_init(&cqr->blocklist);
+               dasd_sfree_request(cqr, device);
+               private->count--;
+       }
+
+       /*
+        * in case of ENOMEM we need to retry after
+        * first requests are finished
+        */
+       if (fdata->start_unit <= fdata->stop_unit)
+               goto retry;
+
+       return rc;
+}
+
 static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
 {
        cqr->status = DASD_CQR_FILLED;
@@ -4305,8 +4432,9 @@ static struct dasd_discipline dasd_eckd_discipline = {
        .uncheck_device = dasd_eckd_uncheck_device,
        .do_analysis = dasd_eckd_do_analysis,
        .verify_path = dasd_eckd_verify_path,
-       .ready_to_online = dasd_eckd_ready_to_online,
+       .basic_to_ready = dasd_eckd_basic_to_ready,
        .online_to_ready = dasd_eckd_online_to_ready,
+       .ready_to_basic = dasd_eckd_ready_to_basic,
        .fill_geometry = dasd_eckd_fill_geometry,
        .start_IO = dasd_start_IO,
        .term_IO = dasd_term_IO,
index 899e3f5..0785bd9 100644 (file)
@@ -300,10 +300,11 @@ struct dasd_discipline {
         * Last things to do when a device is set online, and first things
         * when it is set offline.
         */
-       int (*ready_to_online) (struct dasd_device *);
+       int (*basic_to_ready) (struct dasd_device *);
        int (*online_to_ready) (struct dasd_device *);
+       int (*ready_to_basic)  (struct dasd_device *);
 
-       /*
+       /* (struct dasd_device *);
         * Device operation functions. build_cp creates a ccw chain for
         * a block device request, start_io starts the request and
         * term_IO cancels it (e.g. in case of a timeout). format_device
@@ -317,8 +318,8 @@ struct dasd_discipline {
        int (*start_IO) (struct dasd_ccw_req *);
        int (*term_IO) (struct dasd_ccw_req *);
        void (*handle_terminated_request) (struct dasd_ccw_req *);
-       struct dasd_ccw_req *(*format_device) (struct dasd_device *,
-                                              struct format_data_t *);
+       int (*format_device) (struct dasd_device *,
+                             struct format_data_t *);
        int (*free_cp) (struct dasd_ccw_req *, struct request *);
 
        /*
@@ -672,6 +673,7 @@ int  dasd_term_IO(struct dasd_ccw_req *);
 void dasd_schedule_device_bh(struct dasd_device *);
 void dasd_schedule_block_bh(struct dasd_block *);
 int  dasd_sleep_on(struct dasd_ccw_req *);
+int  dasd_sleep_on_queue(struct list_head *);
 int  dasd_sleep_on_immediatly(struct dasd_ccw_req *);
 int  dasd_sleep_on_interruptible(struct dasd_ccw_req *);
 void dasd_device_set_timer(struct dasd_device *, int);
index 03c0e04..8be1b51 100644 (file)
@@ -143,12 +143,12 @@ static int dasd_ioctl_resume(struct dasd_block *block)
 /*
  * performs formatting of _device_ according to _fdata_
  * Note: The discipline's format_function is assumed to deliver formatting
- * commands to format a single unit of the device. In terms of the ECKD
- * devices this means CCWs are generated to format a single track.
+ * commands to format multiple units of the device. In terms of the ECKD
+ * devices this means CCWs are generated to format multiple tracks.
  */
-static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
+static int
+dasd_format(struct dasd_block *block, struct format_data_t *fdata)
 {
-       struct dasd_ccw_req *cqr;
        struct dasd_device *base;
        int rc;
 
@@ -157,8 +157,8 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
                return -EPERM;
 
        if (base->state != DASD_STATE_BASIC) {
-               pr_warning("%s: The DASD cannot be formatted while it is "
-                          "enabled\n",  dev_name(&base->cdev->dev));
+               pr_warn("%s: The DASD cannot be formatted while it is enabled\n",
+                       dev_name(&base->cdev->dev));
                return -EBUSY;
        }
 
@@ -178,21 +178,10 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
                bdput(bdev);
        }
 
-       while (fdata->start_unit <= fdata->stop_unit) {
-               cqr = base->discipline->format_device(base, fdata);
-               if (IS_ERR(cqr))
-                       return PTR_ERR(cqr);
-               rc = dasd_sleep_on_interruptible(cqr);
-               dasd_sfree_request(cqr, cqr->memdev);
-               if (rc) {
-                       if (rc != -ERESTARTSYS)
-                               pr_err("%s: Formatting unit %d failed with "
-                                      "rc=%d\n", dev_name(&base->cdev->dev),
-                                      fdata->start_unit, rc);
-                       return rc;
-               }
-               fdata->start_unit++;
-       }
+       rc = base->discipline->format_device(base, fdata);
+       if (rc)
+               return rc;
+
        return 0;
 }
 
index e9b9c83..b303cab 100644 (file)
@@ -465,7 +465,7 @@ static int __init scm_blk_init(void)
        scm_major = ret;
        ret = scm_alloc_rqs(nr_requests);
        if (ret)
-               goto out_unreg;
+               goto out_free;
 
        scm_debug = debug_register("scm_log", 16, 1, 16);
        if (!scm_debug) {
@@ -486,7 +486,6 @@ out_dbf:
        debug_unregister(scm_debug);
 out_free:
        scm_free_rqs();
-out_unreg:
        unregister_blkdev(scm_major, "scm");
 out:
        return ret;
index f4bb61b..c0d102e 100644 (file)
@@ -223,6 +223,8 @@ void scm_cluster_request_irq(struct scm_request *scmrq)
 
 bool scm_cluster_size_valid(void)
 {
-       return write_cluster_size == 0 || write_cluster_size == 32 ||
-               write_cluster_size == 64 || write_cluster_size == 128;
+       if (write_cluster_size == 1 || write_cluster_size > 128)
+               return false;
+
+       return !(write_cluster_size & (write_cluster_size - 1));
 }
index 7b00fa6..eb5d227 100644 (file)
@@ -502,7 +502,7 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
                raw3215_try_io(raw);
                raw->flags &= ~RAW3215_FLUSHING;
 #ifdef CONFIG_TN3215_CONSOLE
-               wait_cons_dev();
+               ccw_device_wait_idle(raw->cdev);
 #endif
                /* Enough room freed up ? */
                if (RAW3215_BUFFER_SIZE - raw->count >= length)
@@ -858,7 +858,7 @@ static void con3215_flush(void)
        raw = raw3215[0];  /* console 3215 is the first one */
        if (raw->port.flags & ASYNC_SUSPENDED)
                /* The console is still frozen for suspend. */
-               if (ccw_device_force_console())
+               if (ccw_device_force_console(raw->cdev))
                        /* Forcing didn't work, no panic message .. */
                        return;
        spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
index f4ff515..0da3ae3 100644 (file)
@@ -174,8 +174,7 @@ static void mon_free_mem(struct mon_private *monpriv)
        int i;
 
        for (i = 0; i < MON_MSGLIM; i++)
-               if (monpriv->msg_array[i])
-                       kfree(monpriv->msg_array[i]);
+               kfree(monpriv->msg_array[i]);
        kfree(monpriv);
 }
 
index 4c9030a..24a08e8 100644 (file)
@@ -796,7 +796,7 @@ struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
        do {
                __raw3270_reset_device(rp);
                while (!raw3270_state_final(rp)) {
-                       wait_cons_dev();
+                       ccw_device_wait_idle(rp->cdev);
                        barrier();
                }
        } while (rp->state != RAW3270_STATE_READY);
@@ -810,7 +810,7 @@ raw3270_wait_cons_dev(struct raw3270 *rp)
        unsigned long flags;
 
        spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
-       wait_cons_dev();
+       ccw_device_wait_idle(rp->cdev);
        spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
 }
 
@@ -1274,7 +1274,7 @@ void raw3270_pm_unfreeze(struct raw3270_view *view)
 
        rp = view->dev;
        if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
-               ccw_device_force_console();
+               ccw_device_force_console(rp->cdev);
 #endif
 }
 
index cd79838..178836e 100644 (file)
@@ -561,6 +561,8 @@ static void __init sclp_add_standby_memory(void)
        add_memory_merged(0);
 }
 
+#define MEM_SCT_SIZE (1UL << SECTION_SIZE_BITS)
+
 static void __init insert_increment(u16 rn, int standby, int assigned)
 {
        struct memory_increment *incr, *new_incr;
@@ -573,7 +575,7 @@ static void __init insert_increment(u16 rn, int standby, int assigned)
        new_incr->rn = rn;
        new_incr->standby = standby;
        if (!standby)
-               new_incr->usecount = 1;
+               new_incr->usecount = rzm > MEM_SCT_SIZE ? rzm/MEM_SCT_SIZE : 1;
        last_rn = 0;
        prev = &sclp_mem_list;
        list_for_each_entry(incr, &sclp_mem_list, list) {
index 1d61a01..2282061 100644 (file)
@@ -127,7 +127,7 @@ static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
        }
        if (mode == TO_USER) {
                if (copy_to_user((__force __user void*) dest + offs, buf,
-                                PAGE_SIZE))
+                                count - offs))
                        return -EFAULT;
        } else
                memcpy(dest + offs, buf, count - offs);
index 50ad5fd..21fabc6 100644 (file)
@@ -377,6 +377,26 @@ static void chp_release(struct device *dev)
 }
 
 /**
+ * chp_update_desc - update channel-path description
+ * @chp - channel-path
+ *
+ * Update the channel-path description of the specified channel-path.
+ * Return zero on success, non-zero otherwise.
+ */
+int chp_update_desc(struct channel_path *chp)
+{
+       int rc;
+
+       rc = chsc_determine_base_channel_path_desc(chp->chpid, &chp->desc);
+       if (rc)
+               return rc;
+
+       rc = chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1);
+
+       return rc;
+}
+
+/**
  * chp_new - register a new channel-path
  * @chpid - channel-path ID
  *
@@ -403,7 +423,7 @@ int chp_new(struct chp_id chpid)
        mutex_init(&chp->lock);
 
        /* Obtain channel path description and fill it in. */
-       ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+       ret = chp_update_desc(chp);
        if (ret)
                goto out_free;
        if ((chp->desc.flags & 0x80) == 0) {
index e1399db..9284b78 100644 (file)
@@ -44,6 +44,7 @@ struct channel_path {
        struct mutex lock; /* Serialize access to below members. */
        int state;
        struct channel_path_desc desc;
+       struct channel_path_desc_fmt1 desc_fmt1;
        /* Channel-measurement related stuff: */
        int cmg;
        int shared;
@@ -62,6 +63,7 @@ int chp_is_registered(struct chp_id chpid);
 void *chp_get_chp_desc(struct chp_id chpid);
 void chp_remove_cmg_attr(struct channel_path *chp);
 int chp_add_cmg_attr(struct channel_path *chp);
+int chp_update_desc(struct channel_path *chp);
 int chp_new(struct chp_id chpid);
 void chp_cfg_schedule(struct chp_id chpid, int configure);
 void chp_cfg_cancel_deconfigure(struct chp_id chpid);
index e16c553..8ea7d9b 100644 (file)
@@ -376,7 +376,7 @@ static void chsc_process_sei_chp_avail(struct chsc_sei_nt0_area *sei_area)
                        continue;
                }
                mutex_lock(&chp->lock);
-               chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+               chp_update_desc(chp);
                mutex_unlock(&chp->lock);
        }
 }
@@ -631,8 +631,8 @@ int chsc_chp_vary(struct chp_id chpid, int on)
         * Redo PathVerification on the devices the chpid connects to
         */
        if (on) {
-               /* Try to update the channel path descritor. */
-               chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+               /* Try to update the channel path description. */
+               chp_update_desc(chp);
                for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
                                           __s390_vary_chpid_on, &chpid);
        } else
@@ -825,9 +825,10 @@ int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid,
 {
        struct chsc_response_struct *chsc_resp;
        struct chsc_scpd *scpd_area;
+       unsigned long flags;
        int ret;
 
-       spin_lock_irq(&chsc_page_lock);
+       spin_lock_irqsave(&chsc_page_lock, flags);
        scpd_area = chsc_page;
        ret = chsc_determine_channel_path_desc(chpid, 0, 0, 1, 0, scpd_area);
        if (ret)
@@ -835,7 +836,7 @@ int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid,
        chsc_resp = (void *)&scpd_area->response;
        memcpy(desc, &chsc_resp->data, sizeof(*desc));
 out:
-       spin_unlock_irq(&chsc_page_lock);
+       spin_unlock_irqrestore(&chsc_page_lock, flags);
        return ret;
 }
 
index 986ef6a..935d80b 100644 (file)
@@ -471,15 +471,6 @@ int cio_disable_subchannel(struct subchannel *sch)
 }
 EXPORT_SYMBOL_GPL(cio_disable_subchannel);
 
-int cio_create_sch_lock(struct subchannel *sch)
-{
-       sch->lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
-       if (!sch->lock)
-               return -ENOMEM;
-       spin_lock_init(sch->lock);
-       return 0;
-}
-
 static int cio_check_devno_blacklisted(struct subchannel *sch)
 {
        if (is_blacklisted(sch->schid.ssid, sch->schib.pmcw.dev)) {
@@ -536,32 +527,19 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
        sprintf(dbf_txt, "valsch%x", schid.sch_no);
        CIO_TRACE_EVENT(4, dbf_txt);
 
-       /* Nuke all fields. */
-       memset(sch, 0, sizeof(struct subchannel));
-
-       sch->schid = schid;
-       if (cio_is_console(schid)) {
-               sch->lock = cio_get_console_lock();
-       } else {
-               err = cio_create_sch_lock(sch);
-               if (err)
-                       goto out;
-       }
-       mutex_init(&sch->reg_mutex);
-
        /*
         * The first subchannel that is not-operational (ccode==3)
-        *  indicates that there aren't any more devices available.
+        * indicates that there aren't any more devices available.
         * If stsch gets an exception, it means the current subchannel set
-        *  is not valid.
+        * is not valid.
         */
-       ccode = stsch_err (schid, &sch->schib);
+       ccode = stsch_err(schid, &sch->schib);
        if (ccode) {
                err = (ccode == 3) ? -ENXIO : ccode;
                goto out;
        }
-       /* Copy subchannel type from path management control word. */
        sch->st = sch->schib.pmcw.st;
+       sch->schid = schid;
 
        switch (sch->st) {
        case SUBCHANNEL_TYPE_IO:
@@ -578,11 +556,7 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
 
        CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
                      sch->schid.ssid, sch->schid.sch_no, sch->st);
-       return 0;
 out:
-       if (!cio_is_console(schid))
-               kfree(sch->lock);
-       sch->lock = NULL;
        return err;
 }
 
@@ -650,15 +624,13 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
 }
 
 #ifdef CONFIG_CCW_CONSOLE
-static struct subchannel console_subchannel;
-static struct io_subchannel_private console_priv;
-static int console_subchannel_in_use;
+static struct subchannel *console_sch;
 
 /*
  * Use cio_tsch to update the subchannel status and call the interrupt handler
- * if status had been pending. Called with the console_subchannel lock.
+ * if status had been pending. Called with the subchannel's lock held.
  */
-static void cio_tsch(struct subchannel *sch)
+void cio_tsch(struct subchannel *sch)
 {
        struct irb *irb;
        int irq_context;
@@ -675,6 +647,7 @@ static void cio_tsch(struct subchannel *sch)
                local_bh_disable();
                irq_enter();
        }
+       kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
        if (sch->driver && sch->driver->irq)
                sch->driver->irq(sch);
        else
@@ -685,135 +658,90 @@ static void cio_tsch(struct subchannel *sch)
        }
 }
 
-void *cio_get_console_priv(void)
-{
-       return &console_priv;
-}
-
-/*
- * busy wait for the next interrupt on the console
- */
-void wait_cons_dev(void)
+static int cio_test_for_console(struct subchannel_id schid, void *data)
 {
-       if (!console_subchannel_in_use)
-               return;
-
-       while (1) {
-               cio_tsch(&console_subchannel);
-               if (console_subchannel.schib.scsw.cmd.actl == 0)
-                       break;
-               udelay_simple(100);
-       }
-}
+       struct schib schib;
 
-static int
-cio_test_for_console(struct subchannel_id schid, void *data)
-{
-       if (stsch_err(schid, &console_subchannel.schib) != 0)
+       if (stsch_err(schid, &schib) != 0)
                return -ENXIO;
-       if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) &&
-           console_subchannel.schib.pmcw.dnv &&
-           (console_subchannel.schib.pmcw.dev == console_devno)) {
+       if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
+           (schib.pmcw.dev == console_devno)) {
                console_irq = schid.sch_no;
                return 1; /* found */
        }
        return 0;
 }
 
-
-static int
-cio_get_console_sch_no(void)
+static int cio_get_console_sch_no(void)
 {
        struct subchannel_id schid;
-       
+       struct schib schib;
+
        init_subchannel_id(&schid);
        if (console_irq != -1) {
                /* VM provided us with the irq number of the console. */
                schid.sch_no = console_irq;
-               if (stsch_err(schid, &console_subchannel.schib) != 0 ||
-                   (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) ||
-                   !console_subchannel.schib.pmcw.dnv)
+               if (stsch_err(schid, &schib) != 0 ||
+                   (schib.pmcw.st != SUBCHANNEL_TYPE_IO) || !schib.pmcw.dnv)
                        return -1;
-               console_devno = console_subchannel.schib.pmcw.dev;
+               console_devno = schib.pmcw.dev;
        } else if (console_devno != -1) {
                /* At least the console device number is known. */
                for_each_subchannel(cio_test_for_console, NULL);
-               if (console_irq == -1)
-                       return -1;
-       } else {
-               /* unlike in 2.4, we cannot autoprobe here, since
-                * the channel subsystem is not fully initialized.
-                * With some luck, the HWC console can take over */
-               return -1;
        }
        return console_irq;
 }
 
-struct subchannel *
-cio_probe_console(void)
+struct subchannel *cio_probe_console(void)
 {
-       int sch_no, ret;
        struct subchannel_id schid;
+       struct subchannel *sch;
+       int sch_no, ret;
 
-       if (xchg(&console_subchannel_in_use, 1) != 0)
-               return ERR_PTR(-EBUSY);
        sch_no = cio_get_console_sch_no();
        if (sch_no == -1) {
-               console_subchannel_in_use = 0;
                pr_warning("No CCW console was found\n");
                return ERR_PTR(-ENODEV);
        }
-       memset(&console_subchannel, 0, sizeof(struct subchannel));
        init_subchannel_id(&schid);
        schid.sch_no = sch_no;
-       ret = cio_validate_subchannel(&console_subchannel, schid);
-       if (ret) {
-               console_subchannel_in_use = 0;
-               return ERR_PTR(-ENODEV);
-       }
+       sch = css_alloc_subchannel(schid);
+       if (IS_ERR(sch))
+               return sch;
 
-       /*
-        * enable console I/O-interrupt subclass
-        */
        isc_register(CONSOLE_ISC);
-       console_subchannel.config.isc = CONSOLE_ISC;
-       console_subchannel.config.intparm = (u32)(addr_t)&console_subchannel;
-       ret = cio_commit_config(&console_subchannel);
+       sch->config.isc = CONSOLE_ISC;
+       sch->config.intparm = (u32)(addr_t)sch;
+       ret = cio_commit_config(sch);
        if (ret) {
                isc_unregister(CONSOLE_ISC);
-               console_subchannel_in_use = 0;
+               put_device(&sch->dev);
                return ERR_PTR(ret);
        }
-       return &console_subchannel;
-}
-
-void
-cio_release_console(void)
-{
-       console_subchannel.config.intparm = 0;
-       cio_commit_config(&console_subchannel);
-       isc_unregister(CONSOLE_ISC);
-       console_subchannel_in_use = 0;
+       console_sch = sch;
+       return sch;
 }
 
-/* Bah... hack to catch console special sausages. */
-int
-cio_is_console(struct subchannel_id schid)
+int cio_is_console(struct subchannel_id schid)
 {
-       if (!console_subchannel_in_use)
+       if (!console_sch)
                return 0;
-       return schid_equal(&schid, &console_subchannel.schid);
+       return schid_equal(&schid, &console_sch->schid);
 }
 
-struct subchannel *
-cio_get_console_subchannel(void)
+void cio_register_early_subchannels(void)
 {
-       if (!console_subchannel_in_use)
-               return NULL;
-       return &console_subchannel;
+       int ret;
+
+       if (!console_sch)
+               return;
+
+       ret = css_register_subchannel(console_sch);
+       if (ret)
+               put_device(&console_sch->dev);
 }
+#endif /* CONFIG_CCW_CONSOLE */
 
-#endif
 static int
 __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
 {
index 4a1ff5c..d62f5e7 100644 (file)
@@ -121,23 +121,18 @@ extern int cio_commit_config(struct subchannel *sch);
 int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
 int cio_tm_intrg(struct subchannel *sch);
 
-int cio_create_sch_lock(struct subchannel *);
 void do_adapter_IO(u8 isc);
 void do_IRQ(struct pt_regs *);
 
 /* Use with care. */
 #ifdef CONFIG_CCW_CONSOLE
 extern struct subchannel *cio_probe_console(void);
-extern void cio_release_console(void);
 extern int cio_is_console(struct subchannel_id);
-extern struct subchannel *cio_get_console_subchannel(void);
-extern spinlock_t * cio_get_console_lock(void);
-extern void *cio_get_console_priv(void);
+extern void cio_register_early_subchannels(void);
+extern void cio_tsch(struct subchannel *sch);
 #else
 #define cio_is_console(schid) 0
-#define cio_get_console_subchannel() NULL
-#define cio_get_console_lock() NULL
-#define cio_get_console_priv() NULL
+static inline void cio_register_early_subchannels(void) {}
 #endif
 
 #endif
index a239237..1ebe5d3 100644 (file)
@@ -137,37 +137,53 @@ out:
 
 static void css_sch_todo(struct work_struct *work);
 
-static struct subchannel *
-css_alloc_subchannel(struct subchannel_id schid)
+static int css_sch_create_locks(struct subchannel *sch)
+{
+       sch->lock = kmalloc(sizeof(*sch->lock), GFP_KERNEL);
+       if (!sch->lock)
+               return -ENOMEM;
+
+       spin_lock_init(sch->lock);
+       mutex_init(&sch->reg_mutex);
+
+       return 0;
+}
+
+static void css_subchannel_release(struct device *dev)
+{
+       struct subchannel *sch = to_subchannel(dev);
+
+       sch->config.intparm = 0;
+       cio_commit_config(sch);
+       kfree(sch->lock);
+       kfree(sch);
+}
+
+struct subchannel *css_alloc_subchannel(struct subchannel_id schid)
 {
        struct subchannel *sch;
        int ret;
 
-       sch = kmalloc (sizeof (*sch), GFP_KERNEL | GFP_DMA);
-       if (sch == NULL)
+       sch = kzalloc(sizeof(*sch), GFP_KERNEL | GFP_DMA);
+       if (!sch)
                return ERR_PTR(-ENOMEM);
-       ret = cio_validate_subchannel (sch, schid);
-       if (ret < 0) {
-               kfree(sch);
-               return ERR_PTR(ret);
-       }
+
+       ret = cio_validate_subchannel(sch, schid);
+       if (ret < 0)
+               goto err;
+
+       ret = css_sch_create_locks(sch);
+       if (ret)
+               goto err;
+
        INIT_WORK(&sch->todo_work, css_sch_todo);
+       sch->dev.release = &css_subchannel_release;
+       device_initialize(&sch->dev);
        return sch;
-}
-
-static void
-css_subchannel_release(struct device *dev)
-{
-       struct subchannel *sch;
 
-       sch = to_subchannel(dev);
-       if (!cio_is_console(sch->schid)) {
-               /* Reset intparm to zeroes. */
-               sch->config.intparm = 0;
-               cio_commit_config(sch);
-               kfree(sch->lock);
-               kfree(sch);
-       }
+err:
+       kfree(sch);
+       return ERR_PTR(ret);
 }
 
 static int css_sch_device_register(struct subchannel *sch)
@@ -177,7 +193,7 @@ static int css_sch_device_register(struct subchannel *sch)
        mutex_lock(&sch->reg_mutex);
        dev_set_name(&sch->dev, "0.%x.%04x", sch->schid.ssid,
                     sch->schid.sch_no);
-       ret = device_register(&sch->dev);
+       ret = device_add(&sch->dev);
        mutex_unlock(&sch->reg_mutex);
        return ret;
 }
@@ -228,16 +244,11 @@ void css_update_ssd_info(struct subchannel *sch)
 {
        int ret;
 
-       if (cio_is_console(sch->schid)) {
-               /* Console is initialized too early for functions requiring
-                * memory allocation. */
+       ret = chsc_get_ssd_info(sch->schid, &sch->ssd_info);
+       if (ret)
                ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw);
-       } else {
-               ret = chsc_get_ssd_info(sch->schid, &sch->ssd_info);
-               if (ret)
-                       ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw);
-               ssd_register_chpids(&sch->ssd_info);
-       }
+
+       ssd_register_chpids(&sch->ssd_info);
 }
 
 static ssize_t type_show(struct device *dev, struct device_attribute *attr,
@@ -275,14 +286,13 @@ static const struct attribute_group *default_subch_attr_groups[] = {
        NULL,
 };
 
-static int css_register_subchannel(struct subchannel *sch)
+int css_register_subchannel(struct subchannel *sch)
 {
        int ret;
 
        /* Initialize the subchannel structure */
        sch->dev.parent = &channel_subsystems[0]->device;
        sch->dev.bus = &css_bus_type;
-       sch->dev.release = &css_subchannel_release;
        sch->dev.groups = default_subch_attr_groups;
        /*
         * We don't want to generate uevents for I/O subchannels that don't
@@ -314,23 +324,19 @@ static int css_register_subchannel(struct subchannel *sch)
        return ret;
 }
 
-int css_probe_device(struct subchannel_id schid)
+static int css_probe_device(struct subchannel_id schid)
 {
-       int ret;
        struct subchannel *sch;
+       int ret;
+
+       sch = css_alloc_subchannel(schid);
+       if (IS_ERR(sch))
+               return PTR_ERR(sch);
 
-       if (cio_is_console(schid))
-               sch = cio_get_console_subchannel();
-       else {
-               sch = css_alloc_subchannel(schid);
-               if (IS_ERR(sch))
-                       return PTR_ERR(sch);
-       }
        ret = css_register_subchannel(sch);
-       if (ret) {
-               if (!cio_is_console(schid))
-                       put_device(&sch->dev);
-       }
+       if (ret)
+               put_device(&sch->dev);
+
        return ret;
 }
 
@@ -770,7 +776,7 @@ static int __init setup_css(int nr)
        css->pseudo_subchannel->dev.release = css_subchannel_release;
        dev_set_name(&css->pseudo_subchannel->dev, "defunct");
        mutex_init(&css->pseudo_subchannel->reg_mutex);
-       ret = cio_create_sch_lock(css->pseudo_subchannel);
+       ret = css_sch_create_locks(css->pseudo_subchannel);
        if (ret) {
                kfree(css->pseudo_subchannel);
                return ret;
@@ -870,8 +876,7 @@ static struct notifier_block css_power_notifier = {
 
 /*
  * Now that the driver core is running, we can setup our channel subsystem.
- * The struct subchannel's are created during probing (except for the
- * static console subchannel).
+ * The struct subchannel's are created during probing.
  */
 static int __init css_bus_init(void)
 {
@@ -1050,6 +1055,8 @@ int css_complete_work(void)
  */
 static int __init channel_subsystem_init_sync(void)
 {
+       /* Register subchannels which are already in use. */
+       cio_register_early_subchannels();
        /* Start initial subchannel evaluation. */
        css_schedule_eval_all();
        css_complete_work();
@@ -1065,9 +1072,8 @@ void channel_subsystem_reinit(void)
        chsc_enable_facility(CHSC_SDA_OC_MSS);
        chp_id_for_each(&chpid) {
                chp = chpid_to_chp(chpid);
-               if (!chp)
-                       continue;
-               chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+               if (chp)
+                       chp_update_desc(chp);
        }
 }
 
index 4af3dfe..b1de603 100644 (file)
@@ -101,7 +101,8 @@ extern int css_driver_register(struct css_driver *);
 extern void css_driver_unregister(struct css_driver *);
 
 extern void css_sch_device_unregister(struct subchannel *);
-extern int css_probe_device(struct subchannel_id);
+extern int css_register_subchannel(struct subchannel *);
+extern struct subchannel *css_alloc_subchannel(struct subchannel_id);
 extern struct subchannel *get_subchannel_by_schid(struct subchannel_id);
 extern int css_init_done;
 extern int max_ssid;
@@ -109,7 +110,6 @@ int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
                               int (*fn_unknown)(struct subchannel_id,
                               void *), void *data);
 extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
-extern void css_reiterate_subchannels(void);
 void css_update_ssd_info(struct subchannel *sch);
 
 struct channel_subsystem {
index c6767f5..1ab5f6c 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/list.h>
 #include <linux/device.h>
 #include <linux/workqueue.h>
+#include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/kernel_stat.h>
 
@@ -43,6 +44,10 @@ static DEFINE_SPINLOCK(recovery_lock);
 static int recovery_phase;
 static const unsigned long recovery_delay[] = { 3, 30, 300 };
 
+static atomic_t ccw_device_init_count = ATOMIC_INIT(0);
+static DECLARE_WAIT_QUEUE_HEAD(ccw_device_init_wq);
+static struct bus_type ccw_bus_type;
+
 /******************* bus type handling ***********************/
 
 /* The Linux driver model distinguishes between a bus type and
@@ -127,8 +132,6 @@ static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
        return ret;
 }
 
-static struct bus_type ccw_bus_type;
-
 static void io_subchannel_irq(struct subchannel *);
 static int io_subchannel_probe(struct subchannel *);
 static int io_subchannel_remove(struct subchannel *);
@@ -137,8 +140,6 @@ static int io_subchannel_sch_event(struct subchannel *, int);
 static int io_subchannel_chp_event(struct subchannel *, struct chp_link *,
                                   int);
 static void recovery_func(unsigned long data);
-wait_queue_head_t ccw_device_init_wq;
-atomic_t ccw_device_init_count;
 
 static struct css_device_id io_subchannel_ids[] = {
        { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, },
@@ -191,10 +192,7 @@ int __init io_subchannel_init(void)
 {
        int ret;
 
-       init_waitqueue_head(&ccw_device_init_wq);
-       atomic_set(&ccw_device_init_count, 0);
        setup_timer(&recovery_timer, recovery_func, 0);
-
        ret = bus_register(&ccw_bus_type);
        if (ret)
                return ret;
@@ -1086,19 +1084,14 @@ static int io_subchannel_probe(struct subchannel *sch)
                dev_set_uevent_suppress(&sch->dev, 0);
                kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
                cdev = sch_get_cdev(sch);
-               cdev->dev.groups = ccwdev_attr_groups;
-               device_initialize(&cdev->dev);
-               cdev->private->flags.initialized = 1;
-               ccw_device_register(cdev);
-               /*
-                * Check if the device is already online. If it is
-                * the reference count needs to be corrected since we
-                * didn't obtain a reference in ccw_device_set_online.
-                */
-               if (cdev->private->state != DEV_STATE_NOT_OPER &&
-                   cdev->private->state != DEV_STATE_OFFLINE &&
-                   cdev->private->state != DEV_STATE_BOXED)
-                       get_device(&cdev->dev);
+               rc = ccw_device_register(cdev);
+               if (rc) {
+                       /* Release online reference. */
+                       put_device(&cdev->dev);
+                       goto out_schedule;
+               }
+               if (atomic_dec_and_test(&ccw_device_init_count))
+                       wake_up(&ccw_device_init_wq);
                return 0;
        }
        io_subchannel_init_fields(sch);
@@ -1580,88 +1573,102 @@ out:
 }
 
 #ifdef CONFIG_CCW_CONSOLE
-static struct ccw_device console_cdev;
-static struct ccw_device_private console_private;
-static int console_cdev_in_use;
-
-static DEFINE_SPINLOCK(ccw_console_lock);
-
-spinlock_t * cio_get_console_lock(void)
-{
-       return &ccw_console_lock;
-}
-
 static int ccw_device_console_enable(struct ccw_device *cdev,
                                     struct subchannel *sch)
 {
-       struct io_subchannel_private *io_priv = cio_get_console_priv();
        int rc;
 
-       /* Attach subchannel private data. */
-       memset(io_priv, 0, sizeof(*io_priv));
-       set_io_private(sch, io_priv);
        io_subchannel_init_fields(sch);
        rc = cio_commit_config(sch);
        if (rc)
                return rc;
        sch->driver = &io_subchannel_driver;
-       /* Initialize the ccw_device structure. */
-       cdev->dev.parent= &sch->dev;
        sch_set_cdev(sch, cdev);
        io_subchannel_recog(cdev, sch);
        /* Now wait for the async. recognition to come to an end. */
        spin_lock_irq(cdev->ccwlock);
        while (!dev_fsm_final_state(cdev))
-               wait_cons_dev();
-       rc = -EIO;
-       if (cdev->private->state != DEV_STATE_OFFLINE)
+               ccw_device_wait_idle(cdev);
+
+       /* Hold on to an extra reference while device is online. */
+       get_device(&cdev->dev);
+       rc = ccw_device_online(cdev);
+       if (rc)
                goto out_unlock;
-       ccw_device_online(cdev);
+
        while (!dev_fsm_final_state(cdev))
-               wait_cons_dev();
-       if (cdev->private->state != DEV_STATE_ONLINE)
-               goto out_unlock;
-       rc = 0;
+               ccw_device_wait_idle(cdev);
+
+       if (cdev->private->state == DEV_STATE_ONLINE)
+               cdev->online = 1;
+       else
+               rc = -EIO;
 out_unlock:
        spin_unlock_irq(cdev->ccwlock);
+       if (rc) /* Give up online reference since onlining failed. */
+               put_device(&cdev->dev);
        return rc;
 }
 
-struct ccw_device *
-ccw_device_probe_console(void)
+struct ccw_device *ccw_device_probe_console(void)
 {
+       struct io_subchannel_private *io_priv;
+       struct ccw_device *cdev;
        struct subchannel *sch;
        int ret;
 
-       if (xchg(&console_cdev_in_use, 1) != 0)
-               return ERR_PTR(-EBUSY);
        sch = cio_probe_console();
-       if (IS_ERR(sch)) {
-               console_cdev_in_use = 0;
-               return (void *) sch;
+       if (IS_ERR(sch))
+               return ERR_CAST(sch);
+
+       io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA);
+       if (!io_priv) {
+               put_device(&sch->dev);
+               return ERR_PTR(-ENOMEM);
        }
-       memset(&console_cdev, 0, sizeof(struct ccw_device));
-       memset(&console_private, 0, sizeof(struct ccw_device_private));
-       console_cdev.private = &console_private;
-       console_private.cdev = &console_cdev;
-       console_private.int_class = IRQIO_CIO;
-       ret = ccw_device_console_enable(&console_cdev, sch);
+       cdev = io_subchannel_create_ccwdev(sch);
+       if (IS_ERR(cdev)) {
+               put_device(&sch->dev);
+               kfree(io_priv);
+               return cdev;
+       }
+       set_io_private(sch, io_priv);
+       ret = ccw_device_console_enable(cdev, sch);
        if (ret) {
-               cio_release_console();
-               console_cdev_in_use = 0;
+               set_io_private(sch, NULL);
+               put_device(&sch->dev);
+               put_device(&cdev->dev);
+               kfree(io_priv);
                return ERR_PTR(ret);
        }
-       console_cdev.online = 1;
-       return &console_cdev;
+       return cdev;
+}
+
+/**
+ * ccw_device_wait_idle() - busy wait for device to become idle
+ * @cdev: ccw device
+ *
+ * Poll until activity control is zero, that is, no function or data
+ * transfer is pending/active.
+ * Called with device lock being held.
+ */
+void ccw_device_wait_idle(struct ccw_device *cdev)
+{
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+
+       while (1) {
+               cio_tsch(sch);
+               if (sch->schib.scsw.cmd.actl == 0)
+                       break;
+               udelay_simple(100);
+       }
 }
 
 static int ccw_device_pm_restore(struct device *dev);
 
-int ccw_device_force_console(void)
+int ccw_device_force_console(struct ccw_device *cdev)
 {
-       if (!console_cdev_in_use)
-               return -ENODEV;
-       return ccw_device_pm_restore(&console_cdev.dev);
+       return ccw_device_pm_restore(&cdev->dev);
 }
 EXPORT_SYMBOL_GPL(ccw_device_force_console);
 #endif
index 7d4ecb6..8d1d298 100644 (file)
@@ -81,8 +81,6 @@ dev_fsm_final_state(struct ccw_device *cdev)
                cdev->private->state == DEV_STATE_BOXED);
 }
 
-extern wait_queue_head_t ccw_device_init_wq;
-extern atomic_t ccw_device_init_count;
 int __init io_subchannel_init(void);
 
 void io_subchannel_recog_done(struct ccw_device *cdev);
index c77b6e0..4845d64 100644 (file)
@@ -704,9 +704,9 @@ EXPORT_SYMBOL(ccw_device_tm_start_timeout);
 int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask)
 {
        struct subchannel *sch = to_subchannel(cdev->dev.parent);
-       struct channel_path_desc_fmt1 desc;
+       struct channel_path *chp;
        struct chp_id chpid;
-       int mdc = 0, ret, i;
+       int mdc = 0, i;
 
        /* Adjust requested path mask to excluded varied off paths. */
        if (mask)
@@ -719,14 +719,20 @@ int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask)
                if (!(mask & (0x80 >> i)))
                        continue;
                chpid.id = sch->schib.pmcw.chpid[i];
-               ret = chsc_determine_fmt1_channel_path_desc(chpid, &desc);
-               if (ret)
-                       return ret;
-               if (!desc.f)
+               chp = chpid_to_chp(chpid);
+               if (!chp)
+                       continue;
+
+               mutex_lock(&chp->lock);
+               if (!chp->desc_fmt1.f) {
+                       mutex_unlock(&chp->lock);
                        return 0;
-               if (!desc.r)
+               }
+               if (!chp->desc_fmt1.r)
                        mdc = 1;
-               mdc = mdc ? min(mdc, (int)desc.mdc) : desc.mdc;
+               mdc = mdc ? min_t(int, mdc, chp->desc_fmt1.mdc) :
+                           chp->desc_fmt1.mdc;
+               mutex_unlock(&chp->lock);
        }
 
        return mdc;
index 65d13e3..5a99908 100644 (file)
@@ -17,7 +17,7 @@ struct idset {
 
 static inline unsigned long bitmap_size(int num_ssid, int num_id)
 {
-       return __BITOPS_WORDS(num_ssid * num_id) * sizeof(unsigned long);
+       return BITS_TO_LONGS(num_ssid * num_id) * sizeof(unsigned long);
 }
 
 static struct idset *idset_new(int num_ssid, int num_id)
index 1a9d1e3..c1441ed 100644 (file)
@@ -282,7 +282,7 @@ static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void __init reset_one_i2c(struct bbc_i2c_bus *bp)
+static void reset_one_i2c(struct bbc_i2c_bus *bp)
 {
        writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0);
        writeb(bp->own, bp->i2c_control_regs + 0x1);
@@ -291,7 +291,7 @@ static void __init reset_one_i2c(struct bbc_i2c_bus *bp)
        writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0);
 }
 
-static struct bbc_i2c_bus * __init attach_one_i2c(struct platform_device *op, int index)
+static struct bbc_i2c_bus * attach_one_i2c(struct platform_device *op, int index)
 {
        struct bbc_i2c_bus *bp;
        struct device_node *dp;
index 408d254..684cc34 100644 (file)
@@ -1488,7 +1488,4 @@ struct megasas_mgmt_info {
        int max_index;
 };
 
-#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
-#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
-
 #endif                         /*LSI_MEGARAID_SAS_H */
index 9d53540..7c90d57 100644 (file)
@@ -3984,12 +3984,12 @@ static int megasas_probe_one(struct pci_dev *pdev,
        if (reset_devices) {
                pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
                if (pos) {
-                       pci_read_config_word(pdev, msi_control_reg(pos),
+                       pci_read_config_word(pdev, pos + PCI_MSIX_FLAGS,
                                             &control);
                        if (control & PCI_MSIX_FLAGS_ENABLE) {
                                dev_info(&pdev->dev, "resetting MSI-X\n");
                                pci_write_config_word(pdev,
-                                                     msi_control_reg(pos),
+                                                     pos + PCI_MSIX_FLAGS,
                                                      control &
                                                      ~PCI_MSIX_FLAGS_ENABLE);
                        }
index ce90d05..7455092 100644 (file)
@@ -703,7 +703,7 @@ static struct pci_device_id mvs_pci_table[] = {
        { PCI_VDEVICE(TTI, 0x2744), chip_9480 },
        { PCI_VDEVICE(TTI, 0x2760), chip_9480 },
        {
-               .vendor         = 0x1b4b,
+               .vendor         = PCI_VENDOR_ID_MARVELL_EXT,
                .device         = 0x9480,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = 0x9480,
@@ -712,7 +712,7 @@ static struct pci_device_id mvs_pci_table[] = {
                .driver_data    = chip_9480,
        },
        {
-               .vendor         = 0x1b4b,
+               .vendor         = PCI_VENDOR_ID_MARVELL_EXT,
                .device         = 0x9445,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = 0x9480,
@@ -721,7 +721,7 @@ static struct pci_device_id mvs_pci_table[] = {
                .driver_data    = chip_9445,
        },
        {
-               .vendor         = 0x1b4b,
+               .vendor         = PCI_VENDOR_ID_MARVELL_EXT,
                .device         = 0x9485,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = 0x9480,
index 4594cca..c3601b5 100644 (file)
@@ -49,8 +49,8 @@ MODULE_AUTHOR("jyli@marvell.com");
 MODULE_DESCRIPTION("Marvell UMI Driver");
 
 static DEFINE_PCI_DEVICE_TABLE(mvumi_pci_table) = {
-       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_2, PCI_DEVICE_ID_MARVELL_MV9143) },
-       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_2, PCI_DEVICE_ID_MARVELL_MV9580) },
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, PCI_DEVICE_ID_MARVELL_MV9143) },
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, PCI_DEVICE_ID_MARVELL_MV9580) },
        { 0 }
 };
 
index e360135..41f1687 100644 (file)
@@ -32,7 +32,6 @@
 #define VER_BUILD              1500
 
 #define MV_DRIVER_NAME                 "mvumi"
-#define PCI_VENDOR_ID_MARVELL_2                0x1b4b
 #define PCI_DEVICE_ID_MARVELL_MV9143   0x9143
 #define PCI_DEVICE_ID_MARVELL_MV9580   0x9580
 
index 4c0f6d8..7b0bce9 100644 (file)
@@ -675,3 +675,32 @@ u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc)
                return 0;
        }
 }
+
+void ssb_pmu_spuravoid_pllupdate(struct ssb_chipcommon *cc, int spuravoid)
+{
+       u32 pmu_ctl = 0;
+
+       switch (cc->dev->bus->chip_id) {
+       case 0x4322:
+               ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100070);
+               ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x1014140a);
+               ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888854);
+               if (spuravoid == 1)
+                       ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05201828);
+               else
+                       ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05001828);
+               pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD;
+               break;
+       case 43222:
+               /* TODO: BCM43222 requires updating PLLs too */
+               return;
+       default:
+               ssb_printk(KERN_ERR PFX
+                          "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
+                          cc->dev->bus->chip_id);
+               return;
+       }
+
+       chipco_set32(cc, SSB_CHIPCO_PMU_CTL, pmu_ctl);
+}
+EXPORT_SYMBOL_GPL(ssb_pmu_spuravoid_pllupdate);
diff --git a/drivers/ssbi/Kconfig b/drivers/ssbi/Kconfig
new file mode 100644 (file)
index 0000000..1ae4040
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# SSBI bus support
+#
+
+menu "Qualcomm MSM SSBI bus support"
+
+config SSBI
+       tristate "Qualcomm Single-wire Serial Bus Interface (SSBI)"
+       help
+         If you say yes to this option, support will be included for the
+         built-in SSBI interface on Qualcomm MSM family processors.
+
+         This is required for communicating with Qualcomm PMICs and
+         other devices that have the SSBI interface.
+
+endmenu
diff --git a/drivers/ssbi/Makefile b/drivers/ssbi/Makefile
new file mode 100644 (file)
index 0000000..38fb70c
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_SSBI) += ssbi.o
diff --git a/drivers/ssbi/ssbi.c b/drivers/ssbi/ssbi.c
new file mode 100644 (file)
index 0000000..f32da02
--- /dev/null
@@ -0,0 +1,379 @@
+/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010, Google Inc.
+ *
+ * Original authors: Code Aurora Forum
+ *
+ * Author: Dima Zavin <dima@android.com>
+ *  - Largely rewritten from original to not be an i2c driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/ssbi.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+/* SSBI 2.0 controller registers */
+#define SSBI2_CMD                      0x0008
+#define SSBI2_RD                       0x0010
+#define SSBI2_STATUS                   0x0014
+#define SSBI2_MODE2                    0x001C
+
+/* SSBI_CMD fields */
+#define SSBI_CMD_RDWRN                 (1 << 24)
+
+/* SSBI_STATUS fields */
+#define SSBI_STATUS_RD_READY           (1 << 2)
+#define SSBI_STATUS_READY              (1 << 1)
+#define SSBI_STATUS_MCHN_BUSY          (1 << 0)
+
+/* SSBI_MODE2 fields */
+#define SSBI_MODE2_REG_ADDR_15_8_SHFT  0x04
+#define SSBI_MODE2_REG_ADDR_15_8_MASK  (0x7f << SSBI_MODE2_REG_ADDR_15_8_SHFT)
+
+#define SET_SSBI_MODE2_REG_ADDR_15_8(MD, AD) \
+       (((MD) & 0x0F) | ((((AD) >> 8) << SSBI_MODE2_REG_ADDR_15_8_SHFT) & \
+       SSBI_MODE2_REG_ADDR_15_8_MASK))
+
+/* SSBI PMIC Arbiter command registers */
+#define SSBI_PA_CMD                    0x0000
+#define SSBI_PA_RD_STATUS              0x0004
+
+/* SSBI_PA_CMD fields */
+#define SSBI_PA_CMD_RDWRN              (1 << 24)
+#define SSBI_PA_CMD_ADDR_MASK          0x7fff /* REG_ADDR_7_0, REG_ADDR_8_14*/
+
+/* SSBI_PA_RD_STATUS fields */
+#define SSBI_PA_RD_STATUS_TRANS_DONE   (1 << 27)
+#define SSBI_PA_RD_STATUS_TRANS_DENIED (1 << 26)
+
+#define SSBI_TIMEOUT_US                        100
+
+struct ssbi {
+       struct device           *slave;
+       void __iomem            *base;
+       spinlock_t              lock;
+       enum ssbi_controller_type controller_type;
+       int (*read)(struct ssbi *, u16 addr, u8 *buf, int len);
+       int (*write)(struct ssbi *, u16 addr, u8 *buf, int len);
+};
+
+#define to_ssbi(dev)   platform_get_drvdata(to_platform_device(dev))
+
+static inline u32 ssbi_readl(struct ssbi *ssbi, u32 reg)
+{
+       return readl(ssbi->base + reg);
+}
+
+static inline void ssbi_writel(struct ssbi *ssbi, u32 val, u32 reg)
+{
+       writel(val, ssbi->base + reg);
+}
+
+/*
+ * Via private exchange with one of the original authors, the hardware
+ * should generally finish a transaction in about 5us.  The worst
+ * case, is when using the arbiter and both other CPUs have just
+ * started trying to use the SSBI bus will result in a time of about
+ * 20us.  It should never take longer than this.
+ *
+ * As such, this wait merely spins, with a udelay.
+ */
+static int ssbi_wait_mask(struct ssbi *ssbi, u32 set_mask, u32 clr_mask)
+{
+       u32 timeout = SSBI_TIMEOUT_US;
+       u32 val;
+
+       while (timeout--) {
+               val = ssbi_readl(ssbi, SSBI2_STATUS);
+               if (((val & set_mask) == set_mask) && ((val & clr_mask) == 0))
+                       return 0;
+               udelay(1);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int
+ssbi_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
+{
+       u32 cmd = SSBI_CMD_RDWRN | ((addr & 0xff) << 16);
+       int ret = 0;
+
+       if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) {
+               u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2);
+               mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr);
+               ssbi_writel(ssbi, mode2, SSBI2_MODE2);
+       }
+
+       while (len) {
+               ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0);
+               if (ret)
+                       goto err;
+
+               ssbi_writel(ssbi, cmd, SSBI2_CMD);
+               ret = ssbi_wait_mask(ssbi, SSBI_STATUS_RD_READY, 0);
+               if (ret)
+                       goto err;
+               *buf++ = ssbi_readl(ssbi, SSBI2_RD) & 0xff;
+               len--;
+       }
+
+err:
+       return ret;
+}
+
+static int
+ssbi_write_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
+{
+       int ret = 0;
+
+       if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) {
+               u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2);
+               mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr);
+               ssbi_writel(ssbi, mode2, SSBI2_MODE2);
+       }
+
+       while (len) {
+               ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0);
+               if (ret)
+                       goto err;
+
+               ssbi_writel(ssbi, ((addr & 0xff) << 16) | *buf, SSBI2_CMD);
+               ret = ssbi_wait_mask(ssbi, 0, SSBI_STATUS_MCHN_BUSY);
+               if (ret)
+                       goto err;
+               buf++;
+               len--;
+       }
+
+err:
+       return ret;
+}
+
+/*
+ * See ssbi_wait_mask for an explanation of the time and the
+ * busywait.
+ */
+static inline int
+ssbi_pa_transfer(struct ssbi *ssbi, u32 cmd, u8 *data)
+{
+       u32 timeout = SSBI_TIMEOUT_US;
+       u32 rd_status = 0;
+
+       ssbi_writel(ssbi, cmd, SSBI_PA_CMD);
+
+       while (timeout--) {
+               rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS);
+
+               if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED)
+                       return -EPERM;
+
+               if (rd_status & SSBI_PA_RD_STATUS_TRANS_DONE) {
+                       if (data)
+                               *data = rd_status & 0xff;
+                       return 0;
+               }
+               udelay(1);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int
+ssbi_pa_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
+{
+       u32 cmd;
+       int ret = 0;
+
+       cmd = SSBI_PA_CMD_RDWRN | (addr & SSBI_PA_CMD_ADDR_MASK) << 8;
+
+       while (len) {
+               ret = ssbi_pa_transfer(ssbi, cmd, buf);
+               if (ret)
+                       goto err;
+               buf++;
+               len--;
+       }
+
+err:
+       return ret;
+}
+
+static int
+ssbi_pa_write_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
+{
+       u32 cmd;
+       int ret = 0;
+
+       while (len) {
+               cmd = (addr & SSBI_PA_CMD_ADDR_MASK) << 8 | *buf;
+               ret = ssbi_pa_transfer(ssbi, cmd, NULL);
+               if (ret)
+                       goto err;
+               buf++;
+               len--;
+       }
+
+err:
+       return ret;
+}
+
+int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len)
+{
+       struct ssbi *ssbi = to_ssbi(dev);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&ssbi->lock, flags);
+       ret = ssbi->read(ssbi, addr, buf, len);
+       spin_unlock_irqrestore(&ssbi->lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ssbi_read);
+
+int ssbi_write(struct device *dev, u16 addr, u8 *buf, int len)
+{
+       struct ssbi *ssbi = to_ssbi(dev);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&ssbi->lock, flags);
+       ret = ssbi->write(ssbi, addr, buf, len);
+       spin_unlock_irqrestore(&ssbi->lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ssbi_write);
+
+static int ssbi_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct resource *mem_res;
+       struct ssbi *ssbi;
+       int ret = 0;
+       const char *type;
+
+       ssbi = kzalloc(sizeof(struct ssbi), GFP_KERNEL);
+       if (!ssbi) {
+               pr_err("can not allocate ssbi_data\n");
+               return -ENOMEM;
+       }
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_res) {
+               pr_err("missing mem resource\n");
+               ret = -EINVAL;
+               goto err_get_mem_res;
+       }
+
+       ssbi->base = ioremap(mem_res->start, resource_size(mem_res));
+       if (!ssbi->base) {
+               pr_err("ioremap of 0x%p failed\n", (void *)mem_res->start);
+               ret = -EINVAL;
+               goto err_ioremap;
+       }
+       platform_set_drvdata(pdev, ssbi);
+
+       type = of_get_property(np, "qcom,controller-type", NULL);
+       if (type == NULL) {
+               pr_err("Missing qcom,controller-type property\n");
+               ret = -EINVAL;
+               goto err_ssbi_controller;
+       }
+       dev_info(&pdev->dev, "SSBI controller type: '%s'\n", type);
+       if (strcmp(type, "ssbi") == 0)
+               ssbi->controller_type = MSM_SBI_CTRL_SSBI;
+       else if (strcmp(type, "ssbi2") == 0)
+               ssbi->controller_type = MSM_SBI_CTRL_SSBI2;
+       else if (strcmp(type, "pmic-arbiter") == 0)
+               ssbi->controller_type = MSM_SBI_CTRL_PMIC_ARBITER;
+       else {
+               pr_err("Unknown qcom,controller-type\n");
+               ret = -EINVAL;
+               goto err_ssbi_controller;
+       }
+
+       if (ssbi->controller_type == MSM_SBI_CTRL_PMIC_ARBITER) {
+               ssbi->read = ssbi_pa_read_bytes;
+               ssbi->write = ssbi_pa_write_bytes;
+       } else {
+               ssbi->read = ssbi_read_bytes;
+               ssbi->write = ssbi_write_bytes;
+       }
+
+       spin_lock_init(&ssbi->lock);
+
+       ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
+       if (ret)
+               goto err_ssbi_controller;
+
+       return 0;
+
+err_ssbi_controller:
+       platform_set_drvdata(pdev, NULL);
+       iounmap(ssbi->base);
+err_ioremap:
+err_get_mem_res:
+       kfree(ssbi);
+       return ret;
+}
+
+static int ssbi_remove(struct platform_device *pdev)
+{
+       struct ssbi *ssbi = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       iounmap(ssbi->base);
+       kfree(ssbi);
+       return 0;
+}
+
+static struct of_device_id ssbi_match_table[] = {
+       { .compatible = "qcom,ssbi" },
+       {}
+};
+
+static struct platform_driver ssbi_driver = {
+       .probe          = ssbi_probe,
+       .remove         = ssbi_remove,
+       .driver         = {
+               .name   = "ssbi",
+               .owner  = THIS_MODULE,
+               .of_match_table = ssbi_match_table,
+       },
+};
+
+static int __init ssbi_init(void)
+{
+       return platform_driver_register(&ssbi_driver);
+}
+module_init(ssbi_init);
+
+static void __exit ssbi_exit(void)
+{
+       platform_driver_unregister(&ssbi_driver);
+}
+module_exit(ssbi_exit)
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:ssbi");
+MODULE_AUTHOR("Dima Zavin <dima@android.com>");
index b7d48b3..1b74b88 100644 (file)
@@ -852,18 +852,6 @@ static struct pcmcia_driver serial_cs_driver = {
        .suspend        = serial_suspend,
        .resume         = serial_resume,
 };
-
-static int __init init_serial_cs(void)
-{
-       return pcmcia_register_driver(&serial_cs_driver);
-}
-
-static void __exit exit_serial_cs(void)
-{
-       pcmcia_unregister_driver(&serial_cs_driver);
-}
-
-module_init(init_serial_cs);
-module_exit(exit_serial_cs);
+module_pcmcia_driver(serial_cs_driver);
 
 MODULE_LICENSE("GPL");
index 05400ac..b045268 100644 (file)
@@ -941,6 +941,14 @@ void start_tty(struct tty_struct *tty)
 
 EXPORT_SYMBOL(start_tty);
 
+static void tty_update_time(struct timespec *time)
+{
+       unsigned long sec = get_seconds();
+       sec -= sec % 60;
+       if ((long)(sec - time->tv_sec) > 0)
+               time->tv_sec = sec;
+}
+
 /**
  *     tty_read        -       read method for tty device files
  *     @file: pointer to tty file
@@ -960,10 +968,11 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
                        loff_t *ppos)
 {
        int i;
+       struct inode *inode = file_inode(file);
        struct tty_struct *tty = file_tty(file);
        struct tty_ldisc *ld;
 
-       if (tty_paranoia_check(tty, file_inode(file), "tty_read"))
+       if (tty_paranoia_check(tty, inode, "tty_read"))
                return -EIO;
        if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
                return -EIO;
@@ -977,6 +986,9 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
                i = -EIO;
        tty_ldisc_deref(ld);
 
+       if (i > 0)
+               tty_update_time(&inode->i_atime);
+
        return i;
 }
 
@@ -1077,8 +1089,10 @@ static inline ssize_t do_tty_write(
                        break;
                cond_resched();
        }
-       if (written)
+       if (written) {
+               tty_update_time(&file_inode(file)->i_mtime);
                ret = written;
+       }
 out:
        tty_write_unlock(tty);
        return ret;
index c8b9262..b645c47 100644 (file)
@@ -374,6 +374,7 @@ static int uio_get_minor(struct uio_device *idev)
        retval = idr_alloc(&uio_idr, idev, 0, UIO_MAX_DEVICES, GFP_KERNEL);
        if (retval >= 0) {
                idev->minor = retval;
+               retval = 0;
        } else if (retval == -ENOSPC) {
                dev_err(idev->dev, "too many uio devices\n");
                retval = -EINVAL;
index 3b6f50e..469564e 100644 (file)
@@ -200,17 +200,4 @@ static struct pcmcia_driver sl811_cs_driver = {
        .remove         = sl811_cs_detach,
        .id_table       = sl811_ids,
 };
-
-/*====================================================================*/
-
-static int __init init_sl811_cs(void)
-{
-       return pcmcia_register_driver(&sl811_cs_driver);
-}
-module_init(init_sl811_cs);
-
-static void __exit exit_sl811_cs(void)
-{
-       pcmcia_unregister_driver(&sl811_cs_driver);
-}
-module_exit(exit_sl811_cs);
+module_pcmcia_driver(sl811_cs_driver);
index 7abc5c8..09d2e3f 100644 (file)
@@ -70,7 +70,7 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
                pci_write_config_word(pdev, PCI_COMMAND, cmd);
        }
 
-       msix_pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+       msix_pos = pdev->msix_cap;
        if (msix_pos) {
                u16 flags;
                u32 table;
@@ -78,8 +78,8 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
                pci_read_config_word(pdev, msix_pos + PCI_MSIX_FLAGS, &flags);
                pci_read_config_dword(pdev, msix_pos + PCI_MSIX_TABLE, &table);
 
-               vdev->msix_bar = table & PCI_MSIX_FLAGS_BIRMASK;
-               vdev->msix_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
+               vdev->msix_bar = table & PCI_MSIX_TABLE_BIR;
+               vdev->msix_offset = table & PCI_MSIX_TABLE_OFFSET;
                vdev->msix_size = ((flags & PCI_MSIX_FLAGS_QSIZE) + 1) * 16;
        } else
                vdev->msix_bar = 0xFF;
@@ -183,7 +183,7 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
                u8 pos;
                u16 flags;
 
-               pos = pci_find_capability(vdev->pdev, PCI_CAP_ID_MSI);
+               pos = vdev->pdev->msi_cap;
                if (pos) {
                        pci_read_config_word(vdev->pdev,
                                             pos + PCI_MSI_FLAGS, &flags);
@@ -194,7 +194,7 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
                u8 pos;
                u16 flags;
 
-               pos = pci_find_capability(vdev->pdev, PCI_CAP_ID_MSIX);
+               pos = vdev->pdev->msix_cap;
                if (pos) {
                        pci_read_config_word(vdev->pdev,
                                             pos + PCI_MSIX_FLAGS, &flags);
index 4c1546f..981c1c0 100644 (file)
@@ -31,26 +31,8 @@ config VIDEO_OUTPUT_CONTROL
          This framework adds support for low-level control of the video 
          output switch.
 
-config DISPLAY_TIMING
-       bool
-
-config VIDEOMODE
-       bool
-
-config OF_DISPLAY_TIMING
-       bool "Enable device tree display timing support"
-       depends on OF
-       select DISPLAY_TIMING
-       help
-         helper to parse display timings from the devicetree
-
-config OF_VIDEOMODE
-       bool "Enable device tree videomode support"
-       depends on OF
-       select VIDEOMODE
-       select OF_DISPLAY_TIMING
-       help
-         helper to get videomodes from the devicetree
+config VIDEOMODE_HELPERS
+       bool
 
 config HDMI
        bool
@@ -212,14 +194,6 @@ config FB_SYS_FOPS
        depends on FB
        default n
 
-config FB_WMT_GE_ROPS
-       tristate
-       depends on FB
-       default n
-       ---help---
-         Include functions for accelerated rectangle filling and area
-         copying using WonderMedia Graphics Engine operations.
-
 config FB_DEFERRED_IO
        bool
        depends on FB
@@ -1797,22 +1771,37 @@ config FB_AU1200
          option au1200fb:panel=<name>.
 
 config FB_VT8500
-       bool "VT8500 LCD Driver"
+       bool "VIA VT8500 framebuffer support"
        depends on (FB = y) && ARM && ARCH_VT8500
-       select FB_WMT_GE_ROPS
+       select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS)
+       select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS)
        select FB_SYS_IMAGEBLIT
+       select FB_MODE_HELPERS
+       select VIDEOMODE_HELPERS
        help
          This is the framebuffer driver for VIA VT8500 integrated LCD
          controller.
 
 config FB_WM8505
-       bool "WM8505 frame buffer support"
+       bool "Wondermedia WM8xxx-series frame buffer support"
        depends on (FB = y) && ARM && ARCH_VT8500
-       select FB_WMT_GE_ROPS
+       select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS)
+       select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS)
        select FB_SYS_IMAGEBLIT
+       select FB_MODE_HELPERS
+       select VIDEOMODE_HELPERS
+       help
+         This is the framebuffer driver for WonderMedia WM8xxx-series
+         integrated LCD controller. This driver covers the WM8505, WM8650
+         and WM8850 SoCs.
+
+config FB_WMT_GE_ROPS
+       bool "VT8500/WM8xxx accelerated raster ops support"
+       depends on (FB = y) && (FB_VT8500 || FB_WM8505)
+       default n
        help
-         This is the framebuffer driver for WonderMedia WM8505/WM8650
-         integrated LCD controller.
+         This adds support for accelerated raster operations on the
+         VIA VT8500 and Wondermedia 85xx series SoCs.
 
 source "drivers/video/geode/Kconfig"
 
@@ -2277,7 +2266,7 @@ config XEN_FBDEV_FRONTEND
        select FB_SYS_IMAGEBLIT
        select FB_SYS_FOPS
        select FB_DEFERRED_IO
-       select INPUT_XEN_KBDDEV_FRONTEND
+       select INPUT_XEN_KBDDEV_FRONTEND if INPUT_MISC
        select XEN_XENBUS_FRONTEND
        default y
        help
index 9df3873..e414378 100644 (file)
@@ -171,7 +171,7 @@ obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
 
 #video output switch sysfs driver
 obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
-obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o
-obj-$(CONFIG_OF_DISPLAY_TIMING) += of_display_timing.o
-obj-$(CONFIG_VIDEOMODE) += videomode.o
-obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
+obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o
+ifeq ($(CONFIG_OF),y)
+obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o
+endif
index 7fa1bf8..77cb4ff 100644 (file)
@@ -3788,19 +3788,7 @@ static struct platform_driver amifb_driver = {
        },
 };
 
-static int __init amifb_init(void)
-{
-       return platform_driver_probe(&amifb_driver, amifb_probe);
-}
-
-module_init(amifb_init);
-
-static void __exit amifb_exit(void)
-{
-       platform_driver_unregister(&amifb_driver);
-}
-
-module_exit(amifb_exit);
+module_platform_driver_probe(amifb_driver, amifb_probe);
 
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:amiga-video");
index 025428e..98348ec 100644 (file)
@@ -1158,18 +1158,7 @@ static struct platform_driver atmel_lcdfb_driver = {
        },
 };
 
-static int __init atmel_lcdfb_init(void)
-{
-       return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);
-}
-
-static void __exit atmel_lcdfb_exit(void)
-{
-       platform_driver_unregister(&atmel_lcdfb_driver);
-}
-
-module_init(atmel_lcdfb_init);
-module_exit(atmel_lcdfb_exit);
+module_platform_driver_probe(atmel_lcdfb_driver, atmel_lcdfb_probe);
 
 MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
 MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
index 1a9ac6e..f5b668e 100644 (file)
 
 static void auok1900_init(struct auok190xfb_par *par)
 {
+       struct device *dev = par->info->device;
        struct auok190x_board *board = par->board;
        u16 init_param = 0;
 
+       pm_runtime_get_sync(dev);
+
        init_param |= AUOK1900_INIT_TEMP_AVERAGE;
        init_param |= AUOK1900_INIT_ROTATE(par->rotation);
        init_param |= AUOK190X_INIT_INVERSE_WHITE;
@@ -74,6 +77,9 @@ static void auok1900_init(struct auok190xfb_par *par)
 
        /* let the controller finish */
        board->wait_for_rdy(par);
+
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
 }
 
 static void auok1900_update_region(struct auok190xfb_par *par, int mode,
@@ -82,6 +88,7 @@ static void auok1900_update_region(struct auok190xfb_par *par, int mode,
        struct device *dev = par->info->device;
        unsigned char *buf = (unsigned char *)par->info->screen_base;
        int xres = par->info->var.xres;
+       int line_length = par->info->fix.line_length;
        u16 args[4];
 
        pm_runtime_get_sync(dev);
@@ -100,9 +107,9 @@ static void auok1900_update_region(struct auok190xfb_par *par, int mode,
        args[1] = y1 + 1;
        args[2] = xres;
        args[3] = y2 - y1;
-       buf += y1 * xres;
+       buf += y1 * line_length;
        auok190x_send_cmdargs_pixels(par, AUOK1900_CMD_PARTIALDISP, 4, args,
-                                    ((y2 - y1) * xres)/2, (u16 *) buf);
+                                    ((y2 - y1) * line_length)/2, (u16 *) buf);
        auok190x_send_command(par, AUOK190X_CMD_DATA_STOP);
 
        par->update_cnt++;
index d1db165..12b9adc 100644 (file)
 
 static void auok1901_init(struct auok190xfb_par *par)
 {
+       struct device *dev = par->info->device;
        struct auok190x_board *board = par->board;
        u16 init_param = 0;
 
+       pm_runtime_get_sync(dev);
+
        init_param |= AUOK190X_INIT_INVERSE_WHITE;
        init_param |= AUOK190X_INIT_FORMAT0;
        init_param |= AUOK1901_INIT_RESOLUTION(par->resolution);
@@ -113,6 +116,9 @@ static void auok1901_init(struct auok190xfb_par *par)
 
        /* let the controller finish */
        board->wait_for_rdy(par);
+
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
 }
 
 static void auok1901_update_region(struct auok190xfb_par *par, int mode,
@@ -121,6 +127,7 @@ static void auok1901_update_region(struct auok190xfb_par *par, int mode,
        struct device *dev = par->info->device;
        unsigned char *buf = (unsigned char *)par->info->screen_base;
        int xres = par->info->var.xres;
+       int line_length = par->info->fix.line_length;
        u16 args[5];
 
        pm_runtime_get_sync(dev);
@@ -139,9 +146,9 @@ static void auok1901_update_region(struct auok190xfb_par *par, int mode,
        args[1] = y1 + 1;
        args[2] = xres;
        args[3] = y2 - y1;
-       buf += y1 * xres;
+       buf += y1 * line_length;
        auok190x_send_cmdargs_pixels_nowait(par, AUOK1901_CMD_DMA_START, 4,
-                                           args, ((y2 - y1) * xres)/2,
+                                           args, ((y2 - y1) * line_length)/2,
                                            (u16 *) buf);
        auok190x_send_command_nowait(par, AUOK190X_CMD_DATA_STOP);
 
index 53846cb..b1f19b2 100644 (file)
@@ -40,6 +40,14 @@ static struct panel_info panel_table[] = {
                .w = 1024,
                .h = 768,
        },
+       [AUOK190X_RESOLUTION_600_800] = {
+               .w = 600,
+               .h = 800,
+       },
+       [AUOK190X_RESOLUTION_768_1024] = {
+               .w = 768,
+               .h = 1024,
+       },
 };
 
 /*
@@ -60,8 +68,48 @@ static void auok190x_issue_cmd(struct auok190xfb_par *par, u16 data)
        par->board->set_ctl(par, AUOK190X_I80_DC, 1);
 }
 
-static int auok190x_issue_pixels(struct auok190xfb_par *par, int size,
-                                u16 *data)
+/**
+ * Conversion of 16bit color to 4bit grayscale
+ * does roughly (0.3 * R + 0.6 G + 0.1 B) / 2
+ */
+static inline int rgb565_to_gray4(u16 data, struct fb_var_screeninfo *var)
+{
+       return ((((data & 0xF800) >> var->red.offset) * 77 +
+                ((data & 0x07E0) >> (var->green.offset + 1)) * 151 +
+                ((data & 0x1F) >> var->blue.offset) * 28) >> 8 >> 1);
+}
+
+static int auok190x_issue_pixels_rgb565(struct auok190xfb_par *par, int size,
+                                       u16 *data)
+{
+       struct fb_var_screeninfo *var = &par->info->var;
+       struct device *dev = par->info->device;
+       int i;
+       u16 tmp;
+
+       if (size & 7) {
+               dev_err(dev, "issue_pixels: size %d must be a multiple of 8\n",
+                       size);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < (size >> 2); i++) {
+               par->board->set_ctl(par, AUOK190X_I80_WR, 0);
+
+               tmp  = (rgb565_to_gray4(data[4*i], var) & 0x000F);
+               tmp |= (rgb565_to_gray4(data[4*i+1], var) << 4) & 0x00F0;
+               tmp |= (rgb565_to_gray4(data[4*i+2], var) << 8) & 0x0F00;
+               tmp |= (rgb565_to_gray4(data[4*i+3], var) << 12) & 0xF000;
+
+               par->board->set_hdb(par, tmp);
+               par->board->set_ctl(par, AUOK190X_I80_WR, 1);
+       }
+
+       return 0;
+}
+
+static int auok190x_issue_pixels_gray8(struct auok190xfb_par *par, int size,
+                                      u16 *data)
 {
        struct device *dev = par->info->device;
        int i;
@@ -91,6 +139,23 @@ static int auok190x_issue_pixels(struct auok190xfb_par *par, int size,
        return 0;
 }
 
+static int auok190x_issue_pixels(struct auok190xfb_par *par, int size,
+                                u16 *data)
+{
+       struct fb_info *info = par->info;
+       struct device *dev = par->info->device;
+
+       if (info->var.bits_per_pixel == 8 && info->var.grayscale)
+               auok190x_issue_pixels_gray8(par, size, data);
+       else if (info->var.bits_per_pixel == 16)
+               auok190x_issue_pixels_rgb565(par, size, data);
+       else
+               dev_err(dev, "unsupported color mode (bits: %d, gray: %d)\n",
+                       info->var.bits_per_pixel, info->var.grayscale);
+
+       return 0;
+}
+
 static u16 auok190x_read_data(struct auok190xfb_par *par)
 {
        u16 data;
@@ -224,8 +289,8 @@ static void auok190xfb_dpy_deferred_io(struct fb_info *info,
 {
        struct fb_deferred_io *fbdefio = info->fbdefio;
        struct auok190xfb_par *par = info->par;
+       u16 line_length = info->fix.line_length;
        u16 yres = info->var.yres;
-       u16 xres = info->var.xres;
        u16 y1 = 0, h = 0;
        int prev_index = -1;
        struct page *cur;
@@ -254,7 +319,7 @@ static void auok190xfb_dpy_deferred_io(struct fb_info *info,
        }
 
        /* height increment is fixed per page */
-       h_inc = DIV_ROUND_UP(PAGE_SIZE , xres);
+       h_inc = DIV_ROUND_UP(PAGE_SIZE , line_length);
 
        /* calculate number of pages from pixel height */
        threshold = par->consecutive_threshold / h_inc;
@@ -265,7 +330,7 @@ static void auok190xfb_dpy_deferred_io(struct fb_info *info,
        list_for_each_entry(cur, &fbdefio->pagelist, lru) {
                if (prev_index < 0) {
                        /* just starting so assign first page */
-                       y1 = (cur->index << PAGE_SHIFT) / xres;
+                       y1 = (cur->index << PAGE_SHIFT) / line_length;
                        h = h_inc;
                } else if ((cur->index - prev_index) <= threshold) {
                        /* page is within our threshold for single updates */
@@ -275,7 +340,7 @@ static void auok190xfb_dpy_deferred_io(struct fb_info *info,
                        par->update_partial(par, y1, y1 + h);
 
                        /* start over with our non consecutive page */
-                       y1 = (cur->index << PAGE_SHIFT) / xres;
+                       y1 = (cur->index << PAGE_SHIFT) / line_length;
                        h = h_inc;
                }
                prev_index = cur->index;
@@ -376,27 +441,127 @@ static void auok190xfb_imageblit(struct fb_info *info,
 static int auok190xfb_check_var(struct fb_var_screeninfo *var,
                                   struct fb_info *info)
 {
-       if (info->var.xres != var->xres || info->var.yres != var->yres ||
-           info->var.xres_virtual != var->xres_virtual ||
-           info->var.yres_virtual != var->yres_virtual) {
-               pr_info("%s: Resolution not supported: X%u x Y%u\n",
-                        __func__, var->xres, var->yres);
+       struct device *dev = info->device;
+       struct auok190xfb_par *par = info->par;
+       struct panel_info *panel = &panel_table[par->resolution];
+       int size;
+
+       /*
+        * Color depth
+        */
+
+       if (var->bits_per_pixel == 8 && var->grayscale == 1) {
+               /*
+                * For 8-bit grayscale, R, G, and B offset are equal.
+                */
+               var->red.length = 8;
+               var->red.offset = 0;
+               var->red.msb_right = 0;
+
+               var->green.length = 8;
+               var->green.offset = 0;
+               var->green.msb_right = 0;
+
+               var->blue.length = 8;
+               var->blue.offset = 0;
+               var->blue.msb_right = 0;
+
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               var->transp.msb_right = 0;
+       } else if (var->bits_per_pixel == 16) {
+               var->red.length = 5;
+               var->red.offset = 11;
+               var->red.msb_right = 0;
+
+               var->green.length = 6;
+               var->green.offset = 5;
+               var->green.msb_right = 0;
+
+               var->blue.length = 5;
+               var->blue.offset = 0;
+               var->blue.msb_right = 0;
+
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               var->transp.msb_right = 0;
+       } else {
+               dev_warn(dev, "unsupported color mode (bits: %d, grayscale: %d)\n",
+                       info->var.bits_per_pixel, info->var.grayscale);
                return -EINVAL;
        }
 
        /*
+        * Dimensions
+        */
+
+       switch (var->rotate) {
+       case FB_ROTATE_UR:
+       case FB_ROTATE_UD:
+               var->xres = panel->w;
+               var->yres = panel->h;
+               break;
+       case FB_ROTATE_CW:
+       case FB_ROTATE_CCW:
+               var->xres = panel->h;
+               var->yres = panel->w;
+               break;
+       default:
+               dev_dbg(dev, "Invalid rotation request\n");
+               return -EINVAL;
+       }
+
+       var->xres_virtual = var->xres;
+       var->yres_virtual = var->yres;
+
+       /*
         *  Memory limit
         */
 
-       if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) {
-               pr_info("%s: Memory Limit requested yres_virtual = %u\n",
-                        __func__, var->yres_virtual);
+       size = var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8;
+       if (size > info->fix.smem_len) {
+               dev_err(dev, "Memory limit exceeded, requested %dK\n",
+                       size >> 10);
                return -ENOMEM;
        }
 
        return 0;
 }
 
+static int auok190xfb_set_fix(struct fb_info *info)
+{
+       struct fb_fix_screeninfo *fix = &info->fix;
+       struct fb_var_screeninfo *var = &info->var;
+
+       fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+       fix->type = FB_TYPE_PACKED_PIXELS;
+       fix->accel = FB_ACCEL_NONE;
+       fix->visual = (var->grayscale) ? FB_VISUAL_STATIC_PSEUDOCOLOR
+                                      : FB_VISUAL_TRUECOLOR;
+       fix->xpanstep = 0;
+       fix->ypanstep = 0;
+       fix->ywrapstep = 0;
+
+       return 0;
+}
+
+static int auok190xfb_set_par(struct fb_info *info)
+{
+       struct auok190xfb_par *par = info->par;
+
+       par->rotation = info->var.rotate;
+       auok190xfb_set_fix(info);
+
+       /* reinit the controller to honor the rotation */
+       par->init(par);
+
+       /* wait for init to complete */
+       par->board->wait_for_rdy(par);
+
+       return 0;
+}
+
 static struct fb_ops auok190xfb_ops = {
        .owner          = THIS_MODULE,
        .fb_read        = fb_sys_read,
@@ -405,6 +570,7 @@ static struct fb_ops auok190xfb_ops = {
        .fb_copyarea    = auok190xfb_copyarea,
        .fb_imageblit   = auok190xfb_imageblit,
        .fb_check_var   = auok190xfb_check_var,
+       .fb_set_par     = auok190xfb_set_par,
 };
 
 /*
@@ -588,10 +754,16 @@ static int auok190x_power(struct auok190xfb_par *par, bool on)
 
 static void auok190x_recover(struct auok190xfb_par *par)
 {
+       struct device *dev = par->info->device;
+
        auok190x_power(par, 0);
        msleep(100);
        auok190x_power(par, 1);
 
+       /* after powercycling the device, it's always active */
+       pm_runtime_set_active(dev);
+       par->standby = 0;
+
        par->init(par);
 
        /* wait for init to complete */
@@ -875,42 +1047,17 @@ int auok190x_common_probe(struct platform_device *pdev,
        /* initialise fix, var, resolution and rotation */
 
        strlcpy(info->fix.id, init->id, 16);
-       info->fix.type = FB_TYPE_PACKED_PIXELS;
-       info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
-       info->fix.xpanstep = 0;
-       info->fix.ypanstep = 0;
-       info->fix.ywrapstep = 0;
-       info->fix.accel = FB_ACCEL_NONE;
-
        info->var.bits_per_pixel = 8;
        info->var.grayscale = 1;
-       info->var.red.length = 8;
-       info->var.green.length = 8;
-       info->var.blue.length = 8;
 
        panel = &panel_table[board->resolution];
 
-       /* if 90 degree rotation, switch width and height */
-       if (board->rotation & 1) {
-               info->var.xres = panel->h;
-               info->var.yres = panel->w;
-               info->var.xres_virtual = panel->h;
-               info->var.yres_virtual = panel->w;
-               info->fix.line_length = panel->h;
-       } else {
-               info->var.xres = panel->w;
-               info->var.yres = panel->h;
-               info->var.xres_virtual = panel->w;
-               info->var.yres_virtual = panel->h;
-               info->fix.line_length = panel->w;
-       }
-
        par->resolution = board->resolution;
-       par->rotation = board->rotation;
+       par->rotation = 0;
 
        /* videomemory handling */
 
-       videomemorysize = roundup((panel->w * panel->h), PAGE_SIZE);
+       videomemorysize = roundup((panel->w * panel->h) * 2, PAGE_SIZE);
        videomemory = vmalloc(videomemorysize);
        if (!videomemory) {
                ret = -ENOMEM;
@@ -924,6 +1071,12 @@ int auok190x_common_probe(struct platform_device *pdev,
        info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
        info->fbops = &auok190xfb_ops;
 
+       ret = auok190xfb_check_var(&info->var, info);
+       if (ret)
+               goto err_defio;
+
+       auok190xfb_set_fix(info);
+
        /* deferred io init */
 
        info->fbdefio = devm_kzalloc(info->device,
index 0c189b3..67b77b4 100644 (file)
@@ -285,36 +285,26 @@ static int controlfb_pan_display(struct fb_var_screeninfo *var,
 static int controlfb_mmap(struct fb_info *info,
                        struct vm_area_struct *vma)
 {
-       unsigned long off, start;
-       u32 len;
-
-       off = vma->vm_pgoff << PAGE_SHIFT;
-
-       /* frame buffer memory */
-       start = info->fix.smem_start;
-       len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.smem_len);
-       if (off >= len) {
-               /* memory mapped io */
-               off -= len;
-               if (info->var.accel_flags)
-                       return -EINVAL;
-               start = info->fix.mmio_start;
-               len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.mmio_len);
-              vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-       } else {
-               /* framebuffer */
-              vma->vm_page_prot = pgprot_cached_wthru(vma->vm_page_prot);
-       }
-       start &= PAGE_MASK;
-       if ((vma->vm_end - vma->vm_start + off) > len)
-                       return -EINVAL;
-       off += start;
-       vma->vm_pgoff = off >> PAGE_SHIFT;
-       if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
-           vma->vm_end - vma->vm_start, vma->vm_page_prot))
-               return -EAGAIN;
-
-       return 0;
+       unsigned long mmio_pgoff;
+       unsigned long start;
+       u32 len;
+
+       start = info->fix.smem_start;
+       len = info->fix.smem_len;
+       mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT;
+       if (vma->vm_pgoff >= mmio_pgoff) {
+               if (info->var.accel_flags)
+                       return -EINVAL;
+               vma->vm_pgoff -= mmio_pgoff;
+               start = info->fix.mmio_start;
+               len = info->fix.mmio_len;
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       } else {
+               /* framebuffer */
+               vma->vm_page_prot = pgprot_cached_wthru(vma->vm_page_prot);
+       }
+
+       return vm_iomap_memory(vma, start, len);
 }
 
 static int controlfb_blank(int blank_mode, struct fb_info *info)
index fac7df6..3dd43ca 100644 (file)
@@ -35,8 +35,6 @@
 
 #include <video/exynos_mipi_dsim.h>
 
-#include <plat/fb.h>
-
 #include "exynos_mipi_dsi_common.h"
 #include "exynos_mipi_dsi_lowlevel.h"
 
index c70cb89..520fc9b 100644 (file)
@@ -31,8 +31,6 @@
 #include <video/mipi_display.h>
 #include <video/exynos_mipi_dsim.h>
 
-#include <mach/map.h>
-
 #include "exynos_mipi_dsi_regs.h"
 #include "exynos_mipi_dsi_lowlevel.h"
 #include "exynos_mipi_dsi_common.h"
index 95cb99a..15c5abd 100644 (file)
@@ -26,8 +26,6 @@
 
 #include <video/exynos_mipi_dsim.h>
 
-#include <mach/map.h>
-
 #include "exynos_mipi_dsi_regs.h"
 
 void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim)
index 7d106f1..27fc956 100644 (file)
@@ -640,21 +640,9 @@ static int unifb_pan_display(struct fb_var_screeninfo *var,
 int unifb_mmap(struct fb_info *info,
                    struct vm_area_struct *vma)
 {
-       unsigned long size = vma->vm_end - vma->vm_start;
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-       unsigned long pos = info->fix.smem_start + offset;
-
-       if (offset + size > info->fix.smem_len)
-               return -EINVAL;
-
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-       if (io_remap_pfn_range(vma, vma->vm_start, pos >> PAGE_SHIFT, size,
-                               vma->vm_page_prot))
-               return -EAGAIN;
-
-       /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
-       return 0;
+       return vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len);
 }
 
 static struct fb_ops unifb_ops = {
index 7c25408..dcb669e 100644 (file)
@@ -1373,15 +1373,12 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
 {
        struct fb_info *info = file_fb_info(file);
        struct fb_ops *fb;
-       unsigned long off;
+       unsigned long mmio_pgoff;
        unsigned long start;
        u32 len;
 
        if (!info)
                return -ENODEV;
-       if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
-               return -EINVAL;
-       off = vma->vm_pgoff << PAGE_SHIFT;
        fb = info->fbops;
        if (!fb)
                return -ENODEV;
@@ -1393,32 +1390,29 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
                return res;
        }
 
-       /* frame buffer memory */
+       /*
+        * Ugh. This can be either the frame buffer mapping, or
+        * if pgoff points past it, the mmio mapping.
+        */
        start = info->fix.smem_start;
-       len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
-       if (off >= len) {
-               /* memory mapped io */
-               off -= len;
+       len = info->fix.smem_len;
+       mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT;
+       if (vma->vm_pgoff >= mmio_pgoff) {
                if (info->var.accel_flags) {
                        mutex_unlock(&info->mm_lock);
                        return -EINVAL;
                }
+
+               vma->vm_pgoff -= mmio_pgoff;
                start = info->fix.mmio_start;
-               len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
+               len = info->fix.mmio_len;
        }
        mutex_unlock(&info->mm_lock);
-       start &= PAGE_MASK;
-       if ((vma->vm_end - vma->vm_start + off) > len)
-               return -EINVAL;
-       off += start;
-       vma->vm_pgoff = off >> PAGE_SHIFT;
-       /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by io_remap_pfn_range()*/
+
        vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
-       fb_pgprotect(file, vma, off);
-       if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
-                            vma->vm_end - vma->vm_start, vma->vm_page_prot))
-               return -EAGAIN;
-       return 0;
+       fb_pgprotect(file, vma, start);
+
+       return vm_iomap_memory(vma, start, len);
 }
 
 static int
index 7f67099..6103fa6 100644 (file)
@@ -1376,7 +1376,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
        return err;
 }
 
-#if IS_ENABLED(CONFIG_VIDEOMODE)
+#ifdef CONFIG_VIDEOMODE_HELPERS
 int fb_videomode_from_videomode(const struct videomode *vm,
                                struct fb_videomode *fbmode)
 {
@@ -1398,13 +1398,13 @@ int fb_videomode_from_videomode(const struct videomode *vm,
 
        fbmode->sync = 0;
        fbmode->vmode = 0;
-       if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH)
+       if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
                fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
-       if (vm->dmt_flags & VESA_DMT_VSYNC_HIGH)
+       if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
                fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
-       if (vm->data_flags & DISPLAY_FLAGS_INTERLACED)
+       if (vm->flags & DISPLAY_FLAGS_INTERLACED)
                fbmode->vmode |= FB_VMODE_INTERLACED;
-       if (vm->data_flags & DISPLAY_FLAGS_DOUBLESCAN)
+       if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
                fbmode->vmode |= FB_VMODE_DOUBLE;
        fbmode->flag = 0;
 
@@ -1424,9 +1424,8 @@ int fb_videomode_from_videomode(const struct videomode *vm,
        return 0;
 }
 EXPORT_SYMBOL_GPL(fb_videomode_from_videomode);
-#endif
 
-#if IS_ENABLED(CONFIG_OF_VIDEOMODE)
+#ifdef CONFIG_OF
 static inline void dump_fb_videomode(const struct fb_videomode *m)
 {
        pr_debug("fb_videomode = %ux%u@%uHz (%ukHz) %u %u %u %u %u %u %u %u %u\n",
@@ -1465,7 +1464,8 @@ int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fb,
        return 0;
 }
 EXPORT_SYMBOL_GPL(of_get_fb_videomode);
-#endif
+#endif /* CONFIG_OF */
+#endif /* CONFIG_VIDEOMODE_HELPERS */
 
 #else
 int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
index 41fbd94..6c27805 100644 (file)
@@ -375,7 +375,10 @@ struct fsl_diu_data {
        struct diu_ad dummy_ad __aligned(8);
        struct diu_ad ad[NUM_AOIS] __aligned(8);
        u8 gamma[256 * 3] __aligned(32);
-       u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32);
+       /* It's easier to parse the cursor data as little-endian */
+       __le16 cursor[MAX_CURS * MAX_CURS] __aligned(32);
+       /* Blank cursor data -- used to hide the cursor */
+       __le16 blank_cursor[MAX_CURS * MAX_CURS] __aligned(32);
        uint8_t edid_data[EDID_LENGTH];
        bool has_edid;
 } __aligned(32);
@@ -824,7 +827,6 @@ static void update_lcdc(struct fb_info *info)
        /* Program DIU registers */
 
        out_be32(&hw->gamma, DMA_ADDR(data, gamma));
-       out_be32(&hw->cursor, DMA_ADDR(data, cursor));
 
        out_be32(&hw->bgnd, 0x007F7F7F); /* Set background to grey */
        out_be32(&hw->disp_size, (var->yres << 16) | var->xres);
@@ -968,6 +970,156 @@ static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel)
 }
 
 /*
+ * Copies a cursor image from user space to the proper place in driver
+ * memory so that the hardware can display the cursor image.
+ *
+ * Cursor data is represented as a sequence of 'width' bits packed into bytes.
+ * That is, the first 8 bits are in the first byte, the second 8 bits in the
+ * second byte, and so on.  Therefore, the each row of the cursor is (width +
+ * 7) / 8 bytes of 'data'
+ *
+ * The DIU only supports cursors up to 32x32 (MAX_CURS).  We reject cursors
+ * larger than this, so we already know that 'width' <= 32.  Therefore, we can
+ * simplify our code by using a 32-bit big-endian integer ("line") to read in
+ * a single line of pixels, and only look at the top 'width' bits of that
+ * integer.
+ *
+ * This could result in an unaligned 32-bit read.  For example, if the cursor
+ * is 24x24, then the first three bytes of 'image' contain the pixel data for
+ * the top line of the cursor.  We do a 32-bit read of 'image', but we look
+ * only at the top 24 bits.  Then we increment 'image' by 3 bytes.  The next
+ * read is unaligned.  The only problem is that we might read past the end of
+ * 'image' by 1-3 bytes, but that should not cause any problems.
+ */
+static void fsl_diu_load_cursor_image(struct fb_info *info,
+       const void *image, uint16_t bg, uint16_t fg,
+       unsigned int width, unsigned int height)
+{
+       struct mfb_info *mfbi = info->par;
+       struct fsl_diu_data *data = mfbi->parent;
+       __le16 *cursor = data->cursor;
+       __le16 _fg = cpu_to_le16(fg);
+       __le16 _bg = cpu_to_le16(bg);
+       unsigned int h, w;
+
+       for (h = 0; h < height; h++) {
+               uint32_t mask = 1 << 31;
+               uint32_t line = be32_to_cpup(image);
+
+               for (w = 0; w < width; w++) {
+                       cursor[w] = (line & mask) ? _fg : _bg;
+                       mask >>= 1;
+               }
+
+               cursor += MAX_CURS;
+               image += DIV_ROUND_UP(width, 8);
+       }
+}
+
+/*
+ * Set a hardware cursor.  The image data for the cursor is passed via the
+ * fb_cursor object.
+ */
+static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+       struct mfb_info *mfbi = info->par;
+       struct fsl_diu_data *data = mfbi->parent;
+       struct diu __iomem *hw = data->diu_reg;
+
+       if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
+               return -EINVAL;
+
+       /* The cursor size has changed */
+       if (cursor->set & FB_CUR_SETSIZE) {
+               /*
+                * The DIU cursor is a fixed size, so when we get this
+                * message, instead of resizing the cursor, we just clear
+                * all the image data, in expectation of new data.  However,
+                * in tests this control does not appear to be normally
+                * called.
+                */
+               memset(data->cursor, 0, sizeof(data->cursor));
+       }
+
+       /* The cursor position has changed (cursor->image.dx|dy) */
+       if (cursor->set & FB_CUR_SETPOS) {
+               uint32_t xx, yy;
+
+               yy = (cursor->image.dy - info->var.yoffset) & 0x7ff;
+               xx = (cursor->image.dx - info->var.xoffset) & 0x7ff;
+
+               out_be32(&hw->curs_pos, yy << 16 | xx);
+       }
+
+       /*
+        * FB_CUR_SETIMAGE - the cursor image has changed
+        * FB_CUR_SETCMAP  - the cursor colors has changed
+        * FB_CUR_SETSHAPE - the cursor bitmask has changed
+        */
+       if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
+               unsigned int image_size =
+                       DIV_ROUND_UP(cursor->image.width, 8) * cursor->image.height;
+               unsigned int image_words =
+                       DIV_ROUND_UP(image_size, sizeof(uint32_t));
+               unsigned int bg_idx = cursor->image.bg_color;
+               unsigned int fg_idx = cursor->image.fg_color;
+               uint8_t buffer[image_size];
+               uint32_t *image, *source, *mask;
+               uint16_t fg, bg;
+               unsigned int i;
+
+               if (info->state != FBINFO_STATE_RUNNING)
+                       return 0;
+
+               /*
+                * Determine the size of the cursor image data.  Normally,
+                * it's 8x16.
+                */
+               image_size = DIV_ROUND_UP(cursor->image.width, 8) *
+                       cursor->image.height;
+
+               bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
+                    ((info->cmap.green[bg_idx] & 0xf8) << 2) |
+                    ((info->cmap.blue[bg_idx] & 0xf8) >> 3) |
+                    1 << 15;
+
+               fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
+                    ((info->cmap.green[fg_idx] & 0xf8) << 2) |
+                    ((info->cmap.blue[fg_idx] & 0xf8) >> 3) |
+                    1 << 15;
+
+               /* Use 32-bit operations on the data to improve performance */
+               image = (uint32_t *)buffer;
+               source = (uint32_t *)cursor->image.data;
+               mask = (uint32_t *)cursor->mask;
+
+               if (cursor->rop == ROP_XOR)
+                       for (i = 0; i < image_words; i++)
+                               image[i] = source[i] ^ mask[i];
+               else
+                       for (i = 0; i < image_words; i++)
+                               image[i] = source[i] & mask[i];
+
+               fsl_diu_load_cursor_image(info, image, bg, fg,
+                       cursor->image.width, cursor->image.height);
+       };
+
+       /*
+        * Show or hide the cursor.  The cursor data is always stored in the
+        * 'cursor' memory block, and the actual cursor position is always in
+        * the DIU's CURS_POS register.  To hide the cursor, we redirect the
+        * CURSOR register to a blank cursor.  The show the cursor, we
+        * redirect the CURSOR register to the real cursor data.
+        */
+       if (cursor->enable)
+               out_be32(&hw->cursor, DMA_ADDR(data, cursor));
+       else
+               out_be32(&hw->cursor, DMA_ADDR(data, blank_cursor));
+
+       return 0;
+}
+
+/*
  * Using the fb_var_screeninfo in fb_info we set the resolution of this
  * particular framebuffer. This function alters the fb_fix_screeninfo stored
  * in fb_info. It does not alter var in fb_info since we are using that
@@ -1312,6 +1464,7 @@ static struct fb_ops fsl_diu_ops = {
        .fb_ioctl = fsl_diu_ioctl,
        .fb_open = fsl_diu_open,
        .fb_release = fsl_diu_release,
+       .fb_cursor = fsl_diu_cursor,
 };
 
 static int install_fb(struct fb_info *info)
index bda5e39..ceab370 100644 (file)
@@ -1016,7 +1016,9 @@ static int gbefb_mmap(struct fb_info *info,
        /* check range */
        if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
                return -EINVAL;
-       if (offset + size > gbe_mem_size)
+       if (size > gbe_mem_size)
+               return -EINVAL;
+       if (offset > gbe_mem_size - size)
                return -EINVAL;
 
        /* remap using the fastest write-through mode on architecture */
index 9ed8341..84de263 100644 (file)
@@ -252,7 +252,5 @@ void mmp_unregister_path(struct mmp_path *path)
 
        kfree(path);
        mutex_unlock(&disp_lock);
-
-       dev_info(path->dev, "de-register %s\n", path->name);
 }
 EXPORT_SYMBOL_GPL(mmp_unregister_path);
index 13ecd98..56009bc 100644 (file)
@@ -79,25 +79,24 @@ static struct display_timing *of_get_display_timing(struct device_node *np)
        ret |= parse_timing_property(np, "vsync-len", &dt->vsync_len);
        ret |= parse_timing_property(np, "clock-frequency", &dt->pixelclock);
 
-       dt->dmt_flags = 0;
-       dt->data_flags = 0;
+       dt->flags = 0;
        if (!of_property_read_u32(np, "vsync-active", &val))
-               dt->dmt_flags |= val ? VESA_DMT_VSYNC_HIGH :
-                               VESA_DMT_VSYNC_LOW;
+               dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
+                               DISPLAY_FLAGS_VSYNC_LOW;
        if (!of_property_read_u32(np, "hsync-active", &val))
-               dt->dmt_flags |= val ? VESA_DMT_HSYNC_HIGH :
-                               VESA_DMT_HSYNC_LOW;
+               dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
+                               DISPLAY_FLAGS_HSYNC_LOW;
        if (!of_property_read_u32(np, "de-active", &val))
-               dt->data_flags |= val ? DISPLAY_FLAGS_DE_HIGH :
+               dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
                                DISPLAY_FLAGS_DE_LOW;
        if (!of_property_read_u32(np, "pixelclk-active", &val))
-               dt->data_flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
+               dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
                                DISPLAY_FLAGS_PIXDATA_NEGEDGE;
 
        if (of_property_read_bool(np, "interlaced"))
-               dt->data_flags |= DISPLAY_FLAGS_INTERLACED;
+               dt->flags |= DISPLAY_FLAGS_INTERLACED;
        if (of_property_read_bool(np, "doublescan"))
-               dt->data_flags |= DISPLAY_FLAGS_DOUBLESCAN;
+               dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
 
        if (ret) {
                pr_err("%s: error reading timing properties\n",
index 5b8066c..111c2d1 100644 (file)
@@ -43,7 +43,7 @@ int of_get_videomode(struct device_node *np, struct videomode *vm,
        if (index == OF_USE_NATIVE_MODE)
                index = disp->native_mode;
 
-       ret = videomode_from_timing(disp, vm, index);
+       ret = videomode_from_timings(disp, vm, index);
        if (ret)
                return ret;
 
index e512581..0bc3a93 100644 (file)
@@ -39,17 +39,6 @@ config FB_OMAP_LCD_MIPID
          the Mobile Industry Processor Interface DBI-C/DCS
          specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3)
 
-config FB_OMAP_CONSISTENT_DMA_SIZE
-       int "Consistent DMA memory size (MB)"
-       depends on FB_OMAP
-       range 1 14
-       default 2
-       help
-         Increase the DMA consistent memory size according to your video
-         memory needs, for example if you want to use multiple planes.
-         The size must be 2MB aligned.
-         If unsure say 1.
-
 config FB_OMAP_DMA_TUNE
         bool "Set DMA SDRAM access priority high"
         depends on FB_OMAP
index ca585ef..717f13a 100644 (file)
@@ -1101,41 +1101,25 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
        struct omapfb_info *ofbi = FB2OFB(fbi);
        struct fb_fix_screeninfo *fix = &fbi->fix;
        struct omapfb2_mem_region *rg;
-       unsigned long off;
        unsigned long start;
        u32 len;
-       int r = -EINVAL;
-
-       if (vma->vm_end - vma->vm_start == 0)
-               return 0;
-       if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
-               return -EINVAL;
-       off = vma->vm_pgoff << PAGE_SHIFT;
+       int r;
 
        rg = omapfb_get_mem_region(ofbi->region);
 
        start = omapfb_get_region_paddr(ofbi);
        len = fix->smem_len;
-       if (off >= len)
-               goto error;
-       if ((vma->vm_end - vma->vm_start + off) > len)
-               goto error;
-
-       off += start;
 
-       DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
+       DBG("user mmap region start %lx, len %d, off %lx\n", start, len,
+                       vma->vm_pgoff << PAGE_SHIFT);
 
-       vma->vm_pgoff = off >> PAGE_SHIFT;
-       /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
        vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
        vma->vm_ops = &mmap_user_ops;
        vma->vm_private_data = rg;
-       if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
-                              vma->vm_end - vma->vm_start,
-                              vma->vm_page_prot)) {
-               r = -EAGAIN;
+
+       r = vm_iomap_memory(vma, start, len);
+       if (r)
                goto error;
-       }
 
        /* vm_ops.open won't be called for mmap itself. */
        atomic_inc(&rg->map_count);
@@ -1144,7 +1128,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
 
        return 0;
 
- error:
+error:
        omapfb_put_mem_region(ofbi->region);
 
        return r;
index 10560ef..5261229 100644 (file)
@@ -397,18 +397,7 @@ static struct platform_driver vrfb_driver = {
        .remove         = __exit_p(vrfb_remove),
 };
 
-static int __init vrfb_init(void)
-{
-       return platform_driver_probe(&vrfb_driver, &vrfb_probe);
-}
-
-static void __exit vrfb_exit(void)
-{
-       platform_driver_unregister(&vrfb_driver);
-}
-
-module_init(vrfb_init);
-module_exit(vrfb_exit);
+module_platform_driver_probe(vrfb_driver, vrfb_probe);
 
 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
 MODULE_DESCRIPTION("OMAP VRFB");
index 920c27b..d9f08c6 100644 (file)
@@ -705,21 +705,15 @@ static int ps3fb_pan_display(struct fb_var_screeninfo *var,
 
 static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
-       unsigned long size, offset;
+       int r;
 
-       size = vma->vm_end - vma->vm_start;
-       offset = vma->vm_pgoff << PAGE_SHIFT;
-       if (offset + size > info->fix.smem_len)
-               return -EINVAL;
-
-       offset += info->fix.smem_start;
-       if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
-                           size, vma->vm_page_prot))
-               return -EAGAIN;
+       r = vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len);
 
        dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n",
-               offset, vma->vm_start);
-       return 0;
+               info->fix.smem_start + vma->vm_pgoff << PAGE_SHIFT,
+               vma->vm_start);
+
+       return r;
 }
 
     /*
index 968a625..2e7991c 100644 (file)
 #include <linux/uaccess.h>
 #include <linux/interrupt.h>
 #include <linux/pm_runtime.h>
+#include <linux/platform_data/video_s3c.h>
 
 #include <video/samsung_fimd.h>
-#include <mach/map.h>
-#include <plat/fb.h>
 
 /* This driver will export a number of framebuffer interfaces depending
  * on the configuration passed in via the platform data. Each fb instance
index cfbde5e..f34c858 100644 (file)
@@ -556,7 +556,7 @@ static int sa1100fb_mmap(struct fb_info *info,
                         struct vm_area_struct *vma)
 {
        struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
-       unsigned long start, len, off = vma->vm_pgoff << PAGE_SHIFT;
+       unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
 
        if (off < info->fix.smem_len) {
                vma->vm_pgoff += 1; /* skip over the palette */
@@ -564,19 +564,9 @@ static int sa1100fb_mmap(struct fb_info *info,
                                             fbi->map_dma, fbi->map_size);
        }
 
-       start = info->fix.mmio_start;
-       len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
-
-       if ((vma->vm_end - vma->vm_start + off) > len)
-               return -EINVAL;
-
-       off += start & PAGE_MASK;
-       vma->vm_pgoff = off >> PAGE_SHIFT;
-       vma->vm_flags |= VM_IO;
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-       return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
-                                  vma->vm_end - vma->vm_start,
-                                  vma->vm_page_prot);
+
+       return vm_iomap_memory(vma, info->fix.mmio_start, info->fix.mmio_len);
 }
 
 static struct fb_ops sa1100fb_ops = {
index 2331fad..b2a8912 100644 (file)
@@ -705,23 +705,17 @@ static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
 static int sgivwfb_mmap(struct fb_info *info,
                        struct vm_area_struct *vma)
 {
-       unsigned long size = vma->vm_end - vma->vm_start;
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       int r;
 
-       if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
-               return -EINVAL;
-       if (offset + size > sgivwfb_mem_size)
-               return -EINVAL;
-       offset += sgivwfb_mem_phys;
        pgprot_val(vma->vm_page_prot) =
-           pgprot_val(vma->vm_page_prot) | _PAGE_PCD;
-       vma->vm_flags |= VM_IO;
-       if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
-                                               size, vma->vm_page_prot))
-               return -EAGAIN;
+               pgprot_val(vma->vm_page_prot) | _PAGE_PCD;
+
+       r = vm_iomap_memory(vma, sgivwfb_mem_phys, sgivwfb_mem_size);
+
        printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
               offset, vma->vm_start);
-       return 0;
+
+       return r;
 }
 
 int __init sgivwfb_setup(char *options)
index 701b461..6cad530 100644 (file)
@@ -581,17 +581,7 @@ static struct platform_driver sh_mipi_driver = {
        },
 };
 
-static int __init sh_mipi_init(void)
-{
-       return platform_driver_probe(&sh_mipi_driver, sh_mipi_probe);
-}
-module_init(sh_mipi_init);
-
-static void __exit sh_mipi_exit(void)
-{
-       platform_driver_unregister(&sh_mipi_driver);
-}
-module_exit(sh_mipi_exit);
+module_platform_driver_probe(sh_mipi_driver, sh_mipi_probe);
 
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
 MODULE_DESCRIPTION("SuperH / ARM-shmobile MIPI DSI driver");
index 930e550..bfe4728 100644 (file)
@@ -1445,17 +1445,7 @@ static struct platform_driver sh_hdmi_driver = {
        },
 };
 
-static int __init sh_hdmi_init(void)
-{
-       return platform_driver_probe(&sh_hdmi_driver, sh_hdmi_probe);
-}
-module_init(sh_hdmi_init);
-
-static void __exit sh_hdmi_exit(void)
-{
-       platform_driver_unregister(&sh_hdmi_driver);
-}
-module_exit(sh_hdmi_exit);
+module_platform_driver_probe(sh_hdmi_driver, sh_hdmi_probe);
 
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
 MODULE_DESCRIPTION("SuperH / ARM-shmobile HDMI driver");
index 97bd662..b2b33fc 100644 (file)
@@ -782,7 +782,11 @@ static int ufx_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
        unsigned long page, pos;
 
-       if (offset + size > info->fix.smem_len)
+       if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+               return -EINVAL;
+       if (size > info->fix.smem_len)
+               return -EINVAL;
+       if (offset > info->fix.smem_len - size)
                return -EINVAL;
 
        pos = (unsigned long)info->fix.smem_start + offset;
index 86d449e..ec03e72 100644 (file)
@@ -324,7 +324,11 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
        unsigned long page, pos;
 
-       if (offset + size > info->fix.smem_len)
+       if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+               return -EINVAL;
+       if (size > info->fix.smem_len)
+               return -EINVAL;
+       if (offset > info->fix.smem_len - size)
                return -EINVAL;
 
        pos = (unsigned long)info->fix.smem_start + offset;
index 0aa516f..09a1366 100644 (file)
@@ -1003,24 +1003,18 @@ static int vmlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 static int vmlfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        struct vml_info *vinfo = container_of(info, struct vml_info, info);
-       unsigned long size = vma->vm_end - vma->vm_start;
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
        int ret;
 
-       if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
-               return -EINVAL;
-       if (offset + size > vinfo->vram_contig_size)
-               return -EINVAL;
        ret = vmlfb_vram_offset(vinfo, offset);
        if (ret)
                return -EINVAL;
-       offset += vinfo->vram_start;
+
        pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
        pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
-       if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
-                                               size, vma->vm_page_prot))
-               return -EAGAIN;
-       return 0;
+
+       return vm_iomap_memory(vma, vinfo->vram_start,
+                       vinfo->vram_contig_size);
 }
 
 static int vmlfb_sync(struct fb_info *info)
index 8bc1f93..ee5985e 100644 (file)
@@ -420,9 +420,12 @@ static int vfb_mmap(struct fb_info *info,
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
        unsigned long page, pos;
 
-       if (offset + size > info->fix.smem_len) {
+       if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+               return -EINVAL;
+       if (size > info->fix.smem_len)
+               return -EINVAL;
+       if (offset > info->fix.smem_len - size)
                return -EINVAL;
-       }
 
        pos = (unsigned long)info->fix.smem_start + offset;
 
index 21c47a2..df375c9 100644 (file)
 #include <video/display_timing.h>
 #include <video/videomode.h>
 
-int videomode_from_timing(const struct display_timings *disp,
+void videomode_from_timing(const struct display_timing *dt,
+                         struct videomode *vm)
+{
+       vm->pixelclock = dt->pixelclock.typ;
+       vm->hactive = dt->hactive.typ;
+       vm->hfront_porch = dt->hfront_porch.typ;
+       vm->hback_porch = dt->hback_porch.typ;
+       vm->hsync_len = dt->hsync_len.typ;
+
+       vm->vactive = dt->vactive.typ;
+       vm->vfront_porch = dt->vfront_porch.typ;
+       vm->vback_porch = dt->vback_porch.typ;
+       vm->vsync_len = dt->vsync_len.typ;
+
+       vm->flags = dt->flags;
+}
+EXPORT_SYMBOL_GPL(videomode_from_timing);
+
+int videomode_from_timings(const struct display_timings *disp,
                          struct videomode *vm, unsigned int index)
 {
        struct display_timing *dt;
@@ -20,20 +38,8 @@ int videomode_from_timing(const struct display_timings *disp,
        if (!dt)
                return -EINVAL;
 
-       vm->pixelclock = display_timing_get_value(&dt->pixelclock, TE_TYP);
-       vm->hactive = display_timing_get_value(&dt->hactive, TE_TYP);
-       vm->hfront_porch = display_timing_get_value(&dt->hfront_porch, TE_TYP);
-       vm->hback_porch = display_timing_get_value(&dt->hback_porch, TE_TYP);
-       vm->hsync_len = display_timing_get_value(&dt->hsync_len, TE_TYP);
-
-       vm->vactive = display_timing_get_value(&dt->vactive, TE_TYP);
-       vm->vfront_porch = display_timing_get_value(&dt->vfront_porch, TE_TYP);
-       vm->vback_porch = display_timing_get_value(&dt->vback_porch, TE_TYP);
-       vm->vsync_len = display_timing_get_value(&dt->vsync_len, TE_TYP);
-
-       vm->dmt_flags = dt->dmt_flags;
-       vm->data_flags = dt->data_flags;
+       videomode_from_timing(dt, vm);
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(videomode_from_timing);
+EXPORT_SYMBOL_GPL(videomode_from_timings);
index aa2579c..9547e18 100644 (file)
  * GNU General Public License for more details.
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/wait.h>
-
-#include <linux/platform_data/video-vt8500lcdfb.h>
+#include <video/of_display_timing.h>
 
 #include "vt8500lcdfb.h"
 #include "wmt_ge_rops.h"
@@ -277,11 +276,11 @@ static int vt8500lcd_probe(struct platform_device *pdev)
 {
        struct vt8500lcd_info *fbi;
        struct resource *res;
+       struct display_timings *disp_timing;
        void *addr;
        int irq, ret;
 
        struct fb_videomode     of_mode;
-       struct device_node      *np;
        u32                     bpp;
        dma_addr_t fb_mem_phys;
        unsigned long fb_mem_len;
@@ -346,32 +345,18 @@ static int vt8500lcd_probe(struct platform_device *pdev)
                goto failed_free_res;
        }
 
-       np = of_parse_phandle(pdev->dev.of_node, "default-mode", 0);
-       if (!np) {
-               pr_err("%s: No display description in Device Tree\n", __func__);
-               ret = -EINVAL;
-               goto failed_free_res;
-       }
+       disp_timing = of_get_display_timings(pdev->dev.of_node);
+       if (!disp_timing)
+               return -EINVAL;
 
-       /*
-        * This code is copied from Sascha Hauer's of_videomode helper
-        * and can be replaced with a call to the helper once mainlined
-        */
-       ret = 0;
-       ret |= of_property_read_u32(np, "hactive", &of_mode.xres);
-       ret |= of_property_read_u32(np, "vactive", &of_mode.yres);
-       ret |= of_property_read_u32(np, "hback-porch", &of_mode.left_margin);
-       ret |= of_property_read_u32(np, "hfront-porch", &of_mode.right_margin);
-       ret |= of_property_read_u32(np, "hsync-len", &of_mode.hsync_len);
-       ret |= of_property_read_u32(np, "vback-porch", &of_mode.upper_margin);
-       ret |= of_property_read_u32(np, "vfront-porch", &of_mode.lower_margin);
-       ret |= of_property_read_u32(np, "vsync-len", &of_mode.vsync_len);
-       ret |= of_property_read_u32(np, "bpp", &bpp);
-       if (ret) {
-               pr_err("%s: Unable to read display properties\n", __func__);
-               goto failed_free_res;
-       }
-       of_mode.vmode = FB_VMODE_NONINTERLACED;
+       ret = of_get_fb_videomode(pdev->dev.of_node, &of_mode,
+                                                       OF_USE_NATIVE_MODE);
+       if (ret)
+               return ret;
+
+       ret = of_property_read_u32(pdev->dev.of_node, "bits-per-pixel", &bpp);
+       if (ret)
+               return ret;
 
        /* try allocating the framebuffer */
        fb_mem_len = of_mode.xres * of_mode.yres * 2 * (bpp / 8);
index 4dd0580..01f9ace 100644 (file)
  * GNU General Public License for more details.
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/fb.h>
+#include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/wait.h>
+#include <linux/kernel.h>
+#include <linux/memblock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
-#include <linux/memblock.h>
-
-#include <linux/platform_data/video-vt8500lcdfb.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <video/of_display_timing.h>
 
 #include "wm8505fb_regs.h"
 #include "wmt_ge_rops.h"
@@ -263,26 +263,22 @@ static struct fb_ops wm8505fb_ops = {
 static int wm8505fb_probe(struct platform_device *pdev)
 {
        struct wm8505fb_info    *fbi;
-       struct resource         *res;
+       struct resource *res;
+       struct display_timings *disp_timing;
        void                    *addr;
        int ret;
 
-       struct fb_videomode     of_mode;
-       struct device_node      *np;
+       struct fb_videomode     mode;
        u32                     bpp;
        dma_addr_t fb_mem_phys;
        unsigned long fb_mem_len;
        void *fb_mem_virt;
 
-       ret = -ENOMEM;
-       fbi = NULL;
-
        fbi = devm_kzalloc(&pdev->dev, sizeof(struct wm8505fb_info) +
                        sizeof(u32) * 16, GFP_KERNEL);
        if (!fbi) {
                dev_err(&pdev->dev, "Failed to initialize framebuffer device\n");
-               ret = -ENOMEM;
-               goto failed;
+               return -ENOMEM;
        }
 
        strcpy(fbi->fb.fix.id, DRIVER_NAME);
@@ -308,54 +304,23 @@ static int wm8505fb_probe(struct platform_device *pdev)
        fbi->fb.pseudo_palette  = addr;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "no I/O memory resource defined\n");
-               ret = -ENODEV;
-               goto failed_fbi;
-       }
+       fbi->regbase = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(fbi->regbase))
+               return PTR_ERR(fbi->regbase);
 
-       res = request_mem_region(res->start, resource_size(res), DRIVER_NAME);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "failed to request I/O memory\n");
-               ret = -EBUSY;
-               goto failed_fbi;
-       }
-
-       fbi->regbase = ioremap(res->start, resource_size(res));
-       if (fbi->regbase == NULL) {
-               dev_err(&pdev->dev, "failed to map I/O memory\n");
-               ret = -EBUSY;
-               goto failed_free_res;
-       }
+       disp_timing = of_get_display_timings(pdev->dev.of_node);
+       if (!disp_timing)
+               return -EINVAL;
 
-       np = of_parse_phandle(pdev->dev.of_node, "default-mode", 0);
-       if (!np) {
-               pr_err("%s: No display description in Device Tree\n", __func__);
-               ret = -EINVAL;
-               goto failed_free_res;
-       }
+       ret = of_get_fb_videomode(pdev->dev.of_node, &mode, OF_USE_NATIVE_MODE);
+       if (ret)
+               return ret;
 
-       /*
-        * This code is copied from Sascha Hauer's of_videomode helper
-        * and can be replaced with a call to the helper once mainlined
-        */
-       ret = 0;
-       ret |= of_property_read_u32(np, "hactive", &of_mode.xres);
-       ret |= of_property_read_u32(np, "vactive", &of_mode.yres);
-       ret |= of_property_read_u32(np, "hback-porch", &of_mode.left_margin);
-       ret |= of_property_read_u32(np, "hfront-porch", &of_mode.right_margin);
-       ret |= of_property_read_u32(np, "hsync-len", &of_mode.hsync_len);
-       ret |= of_property_read_u32(np, "vback-porch", &of_mode.upper_margin);
-       ret |= of_property_read_u32(np, "vfront-porch", &of_mode.lower_margin);
-       ret |= of_property_read_u32(np, "vsync-len", &of_mode.vsync_len);
-       ret |= of_property_read_u32(np, "bpp", &bpp);
-       if (ret) {
-               pr_err("%s: Unable to read display properties\n", __func__);
-               goto failed_free_res;
-       }
+       ret = of_property_read_u32(pdev->dev.of_node, "bits-per-pixel", &bpp);
+       if (ret)
+               return ret;
 
-       of_mode.vmode = FB_VMODE_NONINTERLACED;
-       fb_videomode_to_var(&fbi->fb.var, &of_mode);
+       fb_videomode_to_var(&fbi->fb.var, &mode);
 
        fbi->fb.var.nonstd              = 0;
        fbi->fb.var.activate            = FB_ACTIVATE_NOW;
@@ -364,16 +329,16 @@ static int wm8505fb_probe(struct platform_device *pdev)
        fbi->fb.var.width               = -1;
 
        /* try allocating the framebuffer */
-       fb_mem_len = of_mode.xres * of_mode.yres * 2 * (bpp / 8);
-       fb_mem_virt = dma_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys,
+       fb_mem_len = mode.xres * mode.yres * 2 * (bpp / 8);
+       fb_mem_virt = dmam_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys,
                                GFP_KERNEL);
        if (!fb_mem_virt) {
                pr_err("%s: Failed to allocate framebuffer\n", __func__);
                return -ENOMEM;
-       };
+       }
 
-       fbi->fb.var.xres_virtual        = of_mode.xres;
-       fbi->fb.var.yres_virtual        = of_mode.yres * 2;
+       fbi->fb.var.xres_virtual        = mode.xres;
+       fbi->fb.var.yres_virtual        = mode.yres * 2;
        fbi->fb.var.bits_per_pixel      = bpp;
 
        fbi->fb.fix.smem_start          = fb_mem_phys;
@@ -381,28 +346,29 @@ static int wm8505fb_probe(struct platform_device *pdev)
        fbi->fb.screen_base             = fb_mem_virt;
        fbi->fb.screen_size             = fb_mem_len;
 
+       fbi->contrast = 0x10;
+       ret = wm8505fb_set_par(&fbi->fb);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to set parameters\n");
+               return ret;
+       }
+
        if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) {
                dev_err(&pdev->dev, "Failed to allocate color map\n");
-               ret = -ENOMEM;
-               goto failed_free_io;
+               return -ENOMEM;
        }
 
        wm8505fb_init_hw(&fbi->fb);
 
-       fbi->contrast = 0x80;
-       ret = wm8505fb_set_par(&fbi->fb);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to set parameters\n");
-               goto failed_free_cmap;
-       }
-
        platform_set_drvdata(pdev, fbi);
 
        ret = register_framebuffer(&fbi->fb);
        if (ret < 0) {
                dev_err(&pdev->dev,
                        "Failed to register framebuffer device: %d\n", ret);
-               goto failed_free_cmap;
+               if (fbi->fb.cmap.len)
+                       fb_dealloc_cmap(&fbi->fb.cmap);
+               return ret;
        }
 
        ret = device_create_file(&pdev->dev, &dev_attr_contrast);
@@ -416,25 +382,11 @@ static int wm8505fb_probe(struct platform_device *pdev)
               fbi->fb.fix.smem_start + fbi->fb.fix.smem_len - 1);
 
        return 0;
-
-failed_free_cmap:
-       if (fbi->fb.cmap.len)
-               fb_dealloc_cmap(&fbi->fb.cmap);
-failed_free_io:
-       iounmap(fbi->regbase);
-failed_free_res:
-       release_mem_region(res->start, resource_size(res));
-failed_fbi:
-       platform_set_drvdata(pdev, NULL);
-       kfree(fbi);
-failed:
-       return ret;
 }
 
 static int wm8505fb_remove(struct platform_device *pdev)
 {
        struct wm8505fb_info *fbi = platform_get_drvdata(pdev);
-       struct resource *res;
 
        device_remove_file(&pdev->dev, &dev_attr_contrast);
 
@@ -445,13 +397,6 @@ static int wm8505fb_remove(struct platform_device *pdev)
        if (fbi->fb.cmap.len)
                fb_dealloc_cmap(&fbi->fb.cmap);
 
-       iounmap(fbi->regbase);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-
-       kfree(fbi);
-
        return 0;
 }
 
index 8738075..f73ec63 100644 (file)
@@ -1,5 +1,28 @@
+#ifdef CONFIG_FB_WMT_GE_ROPS
+
 extern void wmt_ge_fillrect(struct fb_info *info,
                            const struct fb_fillrect *rect);
 extern void wmt_ge_copyarea(struct fb_info *info,
                            const struct fb_copyarea *area);
 extern int wmt_ge_sync(struct fb_info *info);
+
+#else
+
+static inline int wmt_ge_sync(struct fb_info *p)
+{
+       return 0;
+}
+
+static inline void wmt_ge_fillrect(struct fb_info *p,
+                                   const struct fb_fillrect *rect)
+{
+       sys_fillrect(p, rect);
+}
+
+static inline void wmt_ge_copyarea(struct fb_info *p,
+                                    const struct fb_copyarea *area)
+{
+       sys_copyarea(p, area);
+}
+
+#endif
index 950d354..47e12cf 100644 (file)
@@ -121,9 +121,9 @@ static int mxc_w1_probe(struct platform_device *pdev)
        mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mdev->regs = devm_request_and_ioremap(&pdev->dev, res);
-       if (!mdev->regs)
-               return -EBUSY;
+       mdev->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mdev->regs))
+               return PTR_ERR(mdev->regs);
 
        clk_prepare_enable(mdev->clk);
        __raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER);
index 762561f..5e6a3c9 100644 (file)
@@ -22,6 +22,16 @@ config W1_SLAVE_DS2408
          Say Y here if you want to use a 1-wire
          DS2408 8-Channel Addressable Switch device support
 
+config W1_SLAVE_DS2408_READBACK
+       bool "Read-back values written to DS2408's output register"
+       depends on W1_SLAVE_DS2408
+       default y
+       help
+         Enabling this will cause the driver to read back the values written
+         to the chip's output register in order to detect errors.
+
+         This is slower but useful when debugging chips and/or busses.
+
 config W1_SLAVE_DS2413
        tristate "Dual Channel Addressable Switch 0x3a family support (DS2413)"
        help
index 441ad3a..e45eca1 100644 (file)
@@ -178,6 +178,15 @@ static ssize_t w1_f29_write_output(
                w1_write_block(sl->master, w1_buf, 3);
 
                readBack = w1_read_8(sl->master);
+
+               if (readBack != W1_F29_SUCCESS_CONFIRM_BYTE) {
+                       if (w1_reset_resume_command(sl->master))
+                               goto error;
+                       /* try again, the slave is ready for a command */
+                       continue;
+               }
+
+#ifdef CONFIG_W1_SLAVE_DS2408_READBACK
                /* here the master could read another byte which
                   would be the PIO reg (the actual pin logic state)
                   since in this driver we don't know which pins are
@@ -186,11 +195,6 @@ static ssize_t w1_f29_write_output(
                if (w1_reset_resume_command(sl->master))
                        goto error;
 
-               if (readBack != 0xAA) {
-                       /* try again, the slave is ready for a command */
-                       continue;
-               }
-
                /* go read back the output latches */
                /* (the direct effect of the write above) */
                w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
@@ -198,7 +202,9 @@ static ssize_t w1_f29_write_output(
                w1_buf[2] = 0;
                w1_write_block(sl->master, w1_buf, 3);
                /* read the result of the READ_PIO_REGS command */
-               if (w1_read_8(sl->master) == *buf) {
+               if (w1_read_8(sl->master) == *buf)
+#endif
+               {
                        /* success! */
                        mutex_unlock(&sl->master->bus_mutex);
                        dev_dbg(&sl->dev,
@@ -297,8 +303,7 @@ error:
 
 
 
-#define NB_SYSFS_BIN_FILES 6
-static struct bin_attribute w1_f29_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
+static struct bin_attribute w1_f29_sysfs_bin_files[] = {
        {
                .attr = {
                        .name = "state",
@@ -357,7 +362,7 @@ static int w1_f29_add_slave(struct w1_slave *sl)
        int err = 0;
        int i;
 
-       for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
+       for (i = 0; i < ARRAY_SIZE(w1_f29_sysfs_bin_files) && !err; ++i)
                err = sysfs_create_bin_file(
                        &sl->dev.kobj,
                        &(w1_f29_sysfs_bin_files[i]));
@@ -371,7 +376,7 @@ static int w1_f29_add_slave(struct w1_slave *sl)
 static void w1_f29_remove_slave(struct w1_slave *sl)
 {
        int i;
-       for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i)
+       for (i = ARRAY_SIZE(w1_f29_sysfs_bin_files) - 1; i >= 0; --i)
                sysfs_remove_bin_file(&sl->dev.kobj,
                        &(w1_f29_sysfs_bin_files[i]));
 }
index 2647ad8..d8cc812 100644 (file)
@@ -85,8 +85,7 @@ enum xen_irq_type {
  * event channel - irq->event channel mapping
  * cpu - cpu this event channel is bound to
  * index - type-specific information:
- *    PIRQ - vector, with MSB being "needs EIO", or physical IRQ of the HVM
- *           guest, or GSI (real passthrough IRQ) of the device.
+ *    PIRQ - physical IRQ, GSI, flags, and owner domain
  *    VIRQ - virq number
  *    IPI - IPI vector
  *    EVTCHN -
@@ -105,7 +104,6 @@ struct irq_info {
                struct {
                        unsigned short pirq;
                        unsigned short gsi;
-                       unsigned char vector;
                        unsigned char flags;
                        uint16_t domid;
                } pirq;
@@ -211,7 +209,6 @@ static void xen_irq_info_pirq_init(unsigned irq,
                                   unsigned short evtchn,
                                   unsigned short pirq,
                                   unsigned short gsi,
-                                  unsigned short vector,
                                   uint16_t domid,
                                   unsigned char flags)
 {
@@ -221,7 +218,6 @@ static void xen_irq_info_pirq_init(unsigned irq,
 
        info->u.pirq.pirq = pirq;
        info->u.pirq.gsi = gsi;
-       info->u.pirq.vector = vector;
        info->u.pirq.domid = domid;
        info->u.pirq.flags = flags;
 }
@@ -519,6 +515,9 @@ static void xen_free_irq(unsigned irq)
 {
        struct irq_info *info = irq_get_handler_data(irq);
 
+       if (WARN_ON(!info))
+               return;
+
        list_del(&info->list);
 
        irq_set_handler_data(irq, NULL);
@@ -714,7 +713,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
                goto out;
        }
 
-       xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector, DOMID_SELF,
+       xen_irq_info_pirq_init(irq, 0, pirq, gsi, DOMID_SELF,
                               shareable ? PIRQ_SHAREABLE : 0);
 
        pirq_query_unmask(irq);
@@ -762,8 +761,7 @@ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc)
 }
 
 int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
-                            int pirq, int vector, const char *name,
-                            domid_t domid)
+                            int pirq, const char *name, domid_t domid)
 {
        int irq, ret;
 
@@ -776,7 +774,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
        irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_edge_irq,
                        name);
 
-       xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, domid, 0);
+       xen_irq_info_pirq_init(irq, 0, pirq, 0, domid, 0);
        ret = irq_set_msi_desc(irq, msidesc);
        if (ret < 0)
                goto error_irq;
@@ -1008,6 +1006,9 @@ static void unbind_from_irq(unsigned int irq)
        int evtchn = evtchn_from_irq(irq);
        struct irq_info *info = irq_get_handler_data(irq);
 
+       if (WARN_ON(!info))
+               return;
+
        mutex_lock(&irq_mapping_update_lock);
 
        if (info->refcnt > 0) {
@@ -1135,6 +1136,10 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
 
 void unbind_from_irqhandler(unsigned int irq, void *dev_id)
 {
+       struct irq_info *info = irq_get_handler_data(irq);
+
+       if (WARN_ON(!info))
+               return;
        free_irq(irq, dev_id);
        unbind_from_irq(irq);
 }
@@ -1457,6 +1462,9 @@ void rebind_evtchn_irq(int evtchn, int irq)
 {
        struct irq_info *info = info_for_irq(irq);
 
+       if (WARN_ON(!info))
+               return;
+
        /* Make sure the irq is masked, since the new event channel
           will also be masked. */
        disable_irq(irq);
@@ -1730,7 +1738,12 @@ void xen_poll_irq(int irq)
 int xen_test_irq_shared(int irq)
 {
        struct irq_info *info = info_for_irq(irq);
-       struct physdev_irq_status_query irq_status = { .irq = info->u.pirq.pirq };
+       struct physdev_irq_status_query irq_status;
+
+       if (WARN_ON(!info))
+               return -ENOENT;
+
+       irq_status.irq = info->u.pirq.pirq;
 
        if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status))
                return 0;
index 90e34ac..8abd7d5 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/syscore_ops.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/processor.h>
@@ -51,9 +52,9 @@ static DEFINE_MUTEX(acpi_ids_mutex);
 /* Which ACPI ID we have processed from 'struct acpi_processor'. */
 static unsigned long *acpi_ids_done;
 /* Which ACPI ID exist in the SSDT/DSDT processor definitions. */
-static unsigned long __initdata *acpi_id_present;
+static unsigned long *acpi_id_present;
 /* And if there is an _CST definition (or a PBLK) for the ACPI IDs */
-static unsigned long __initdata *acpi_id_cst_present;
+static unsigned long *acpi_id_cst_present;
 
 static int push_cxx_to_hypervisor(struct acpi_processor *_pr)
 {
@@ -329,7 +330,7 @@ static unsigned int __init get_max_acpi_id(void)
  * for_each_[present|online]_cpu macros which are banded to the virtual
  * CPU amount.
  */
-static acpi_status __init
+static acpi_status
 read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        u32 acpi_id;
@@ -384,12 +385,16 @@ read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv)
 
        return AE_OK;
 }
-static int __init check_acpi_ids(struct acpi_processor *pr_backup)
+static int check_acpi_ids(struct acpi_processor *pr_backup)
 {
 
        if (!pr_backup)
                return -ENODEV;
 
+       if (acpi_id_present && acpi_id_cst_present)
+               /* OK, done this once .. skip to uploading */
+               goto upload;
+
        /* All online CPUs have been processed at this stage. Now verify
         * whether in fact "online CPUs" == physical CPUs.
         */
@@ -408,6 +413,7 @@ static int __init check_acpi_ids(struct acpi_processor *pr_backup)
                            read_acpi_id, NULL, NULL, NULL);
        acpi_get_devices("ACPI0007", read_acpi_id, NULL, NULL);
 
+upload:
        if (!bitmap_equal(acpi_id_present, acpi_ids_done, nr_acpi_bits)) {
                unsigned int i;
                for_each_set_bit(i, acpi_id_present, nr_acpi_bits) {
@@ -417,10 +423,7 @@ static int __init check_acpi_ids(struct acpi_processor *pr_backup)
                        (void)upload_pm_data(pr_backup);
                }
        }
-       kfree(acpi_id_present);
-       acpi_id_present = NULL;
-       kfree(acpi_id_cst_present);
-       acpi_id_cst_present = NULL;
+
        return 0;
 }
 static int __init check_prereq(void)
@@ -467,10 +470,47 @@ static void free_acpi_perf_data(void)
        free_percpu(acpi_perf_data);
 }
 
-static int __init xen_acpi_processor_init(void)
+static int xen_upload_processor_pm_data(void)
 {
        struct acpi_processor *pr_backup = NULL;
        unsigned int i;
+       int rc = 0;
+
+       pr_info(DRV_NAME "Uploading Xen processor PM info\n");
+
+       for_each_possible_cpu(i) {
+               struct acpi_processor *_pr;
+               _pr = per_cpu(processors, i /* APIC ID */);
+               if (!_pr)
+                       continue;
+
+               if (!pr_backup) {
+                       pr_backup = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
+                       if (pr_backup)
+                               memcpy(pr_backup, _pr, sizeof(struct acpi_processor));
+               }
+               (void)upload_pm_data(_pr);
+       }
+
+       rc = check_acpi_ids(pr_backup);
+       kfree(pr_backup);
+
+       return rc;
+}
+
+static void xen_acpi_processor_resume(void)
+{
+       bitmap_zero(acpi_ids_done, nr_acpi_bits);
+       xen_upload_processor_pm_data();
+}
+
+static struct syscore_ops xap_syscore_ops = {
+       .resume = xen_acpi_processor_resume,
+};
+
+static int __init xen_acpi_processor_init(void)
+{
+       unsigned int i;
        int rc = check_prereq();
 
        if (rc)
@@ -514,27 +554,12 @@ static int __init xen_acpi_processor_init(void)
                        goto err_out;
        }
 
-       for_each_possible_cpu(i) {
-               struct acpi_processor *_pr;
-               _pr = per_cpu(processors, i /* APIC ID */);
-               if (!_pr)
-                       continue;
-
-               if (!pr_backup) {
-                       pr_backup = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
-                       if (pr_backup)
-                               memcpy(pr_backup, _pr, sizeof(struct acpi_processor));
-               }
-               (void)upload_pm_data(_pr);
-       }
-       rc = check_acpi_ids(pr_backup);
-
-       kfree(pr_backup);
-       pr_backup = NULL;
-
+       rc = xen_upload_processor_pm_data();
        if (rc)
                goto err_unregister;
 
+       register_syscore_ops(&xap_syscore_ops);
+
        return 0;
 err_unregister:
        for_each_possible_cpu(i) {
@@ -552,7 +577,10 @@ static void __exit xen_acpi_processor_exit(void)
 {
        int i;
 
+       unregister_syscore_ops(&xap_syscore_ops);
        kfree(acpi_ids_done);
+       kfree(acpi_id_present);
+       kfree(acpi_id_cst_present);
        for_each_possible_cpu(i) {
                struct acpi_processor_performance *perf;
                perf = per_cpu_ptr(acpi_perf_data, i);
index 3f941f2..1dc8786 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1029,9 +1029,9 @@ static int aio_read_evt(struct kioctx *ioctx, struct io_event *ent)
        spin_unlock(&info->ring_lock);
 
 out:
-       kunmap_atomic(ring);
        dprintk("leaving aio_read_evt: %d  h%lu t%lu\n", ret,
                 (unsigned long)ring->head, (unsigned long)ring->tail);
+       kunmap_atomic(ring);
        return ret;
 }
 
index 3939829..86af964 100644 (file)
@@ -1137,6 +1137,7 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma,
                        goto whole;
                if (!(vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_PRIVATE))
                        goto whole;
+               return 0;
        }
 
        /* Do not dump I/O mapped devices or special mappings */
index bb5768f..b96fc6c 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1428,8 +1428,6 @@ void bio_endio(struct bio *bio, int error)
        else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
                error = -EIO;
 
-       trace_block_bio_complete(bio, error);
-
        if (bio->bi_end_io)
                bio->bi_end_io(bio, error);
 }
index a94f0f7..fe0a762 100644 (file)
@@ -533,7 +533,7 @@ void hfsplus_file_truncate(struct inode *inode)
                struct address_space *mapping = inode->i_mapping;
                struct page *page;
                void *fsdata;
-               u32 size = inode->i_size;
+               loff_t size = inode->i_size;
 
                res = pagecache_write_begin(NULL, mapping, size, 0,
                                                AOP_FLAG_UNINTERRUPTIBLE,
index 84e3d85..523464e 100644 (file)
@@ -110,7 +110,7 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
         * way when do_mmap_pgoff unwinds (may be important on powerpc
         * and ia64).
         */
-       vma->vm_flags |= VM_HUGETLB | VM_DONTEXPAND | VM_DONTDUMP;
+       vma->vm_flags |= VM_HUGETLB | VM_DONTEXPAND;
        vma->vm_ops = &hugetlb_vm_ops;
 
        if (vma->vm_pgoff & (~huge_page_mask(h) >> PAGE_SHIFT))
index f7ed9ee..cbd0f1b 100644 (file)
@@ -143,6 +143,7 @@ static const char * const task_state_array[] = {
        "x (dead)",             /*  64 */
        "K (wakekill)",         /* 128 */
        "W (waking)",           /* 256 */
+       "P (parked)",           /* 512 */
 };
 
 static inline const char *get_task_state(struct task_struct *tsk)
index bcbdd74..03053ac 100644 (file)
@@ -152,15 +152,6 @@ void acpi_penalize_isa_irq(int irq, int active);
 
 void acpi_pci_irq_disable (struct pci_dev *dev);
 
-struct acpi_pci_driver {
-       struct list_head node;
-       int (*add)(struct acpi_pci_root *root);
-       void (*remove)(struct acpi_pci_root *root);
-};
-
-int acpi_pci_register_driver(struct acpi_pci_driver *driver);
-void acpi_pci_unregister_driver(struct acpi_pci_driver *driver);
-
 extern int ec_read(u8 addr, u8 *val);
 extern int ec_write(u8 addr, u8 val);
 extern int ec_transaction(u8 command,
index 0ea61e0..7c2e030 100644 (file)
@@ -12,7 +12,6 @@
 
 struct blk_trace {
        int trace_state;
-       bool rq_based;
        struct rchan *rchan;
        unsigned long __percpu *sequence;
        unsigned char __percpu *msg_data;
index 9bf2f1f..3d7df3d 100644 (file)
@@ -333,6 +333,7 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
                                              unsigned long count,
                                              u64 *max_size,
                                              int *reset_type);
+typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long size);
 
 /*
  *  EFI Configuration Table and GUID definitions
@@ -575,9 +576,15 @@ extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if pos
 #ifdef CONFIG_X86
 extern void efi_late_init(void);
 extern void efi_free_boot_services(void);
+extern efi_status_t efi_query_variable_store(u32 attributes, unsigned long size);
 #else
 static inline void efi_late_init(void) {}
 static inline void efi_free_boot_services(void) {}
+
+static inline efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
+{
+       return EFI_SUCCESS;
+}
 #endif
 extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
 extern u64 efi_get_iobase (void);
@@ -731,7 +738,7 @@ struct efivar_operations {
        efi_get_variable_t *get_variable;
        efi_get_next_variable_t *get_next_variable;
        efi_set_variable_t *set_variable;
-       efi_query_variable_info_t *query_variable_info;
+       efi_query_variable_store_t *query_variable_store;
 };
 
 struct efivars {
index df77ba9..95d0850 100644 (file)
 
 #include <linux/types.h>
 
+
+/*
+ * Implementation of host controlled snapshot of the guest.
+ */
+
+#define VSS_OP_REGISTER 128
+
+enum hv_vss_op {
+       VSS_OP_CREATE = 0,
+       VSS_OP_DELETE,
+       VSS_OP_HOT_BACKUP,
+       VSS_OP_GET_DM_INFO,
+       VSS_OP_BU_COMPLETE,
+       /*
+        * Following operations are only supported with IC version >= 5.0
+        */
+       VSS_OP_FREEZE, /* Freeze the file systems in the VM */
+       VSS_OP_THAW, /* Unfreeze the file systems */
+       VSS_OP_AUTO_RECOVER,
+       VSS_OP_COUNT /* Number of operations, must be last */
+};
+
+
+/*
+ * Header for all VSS messages.
+ */
+struct hv_vss_hdr {
+       __u8 operation;
+       __u8 reserved[7];
+} __attribute__((packed));
+
+
+/*
+ * Flag values for the hv_vss_check_feature. Linux supports only
+ * one value.
+ */
+#define VSS_HBU_NO_AUTO_RECOVERY       0x00000005
+
+struct hv_vss_check_feature {
+       __u32 flags;
+} __attribute__((packed));
+
+struct hv_vss_check_dm_info {
+       __u32 flags;
+} __attribute__((packed));
+
+struct hv_vss_msg {
+       union {
+               struct hv_vss_hdr vss_hdr;
+               int error;
+       };
+       union {
+               struct hv_vss_check_feature vss_cf;
+               struct hv_vss_check_dm_info dm_info;
+       };
+} __attribute__((packed));
+
 /*
  * An implementation of HyperV key value pair (KVP) functionality for Linux.
  *
@@ -1253,6 +1310,14 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver);
                }
 
 /*
+ * VSS (Backup/Restore) GUID
+ */
+#define HV_VSS_GUID \
+       .guid = { \
+                       0x29, 0x2e, 0xfa, 0x35, 0x23, 0xea, 0x36, 0x42, \
+                       0x96, 0xae, 0x3a, 0x6e, 0xba, 0xcb, 0xa4,  0x40 \
+               }
+/*
  * Common header for Hyper-V ICs
  */
 
@@ -1356,6 +1421,10 @@ int hv_kvp_init(struct hv_util_service *);
 void hv_kvp_deinit(void);
 void hv_kvp_onchannelcallback(void *);
 
+int hv_vss_init(struct hv_util_service *);
+void hv_vss_deinit(void);
+void hv_vss_onchannelcallback(void *);
+
 /*
  * Negotiated version with the Host.
  */
index fea12cb..1888e06 100644 (file)
@@ -207,19 +207,41 @@ int ipack_driver_register(struct ipack_driver *edrv, struct module *owner,
 void ipack_driver_unregister(struct ipack_driver *edrv);
 
 /**
- *     ipack_device_register -- register an IPack device with the kernel
- *     @dev: the new device to register.
+ *     ipack_device_init -- initialize an IPack device
+ * @dev: the new device to initialize.
  *
- *     Register a new IPack device ("module" in IndustryPack jargon). The call
- *     is done by the carrier driver.  The carrier should populate the fields
- *     bus and slot as well as the region array of @dev prior to calling this
- *     function.  The rest of the fields will be allocated and populated
- *     during registration.
+ * Initialize a new IPack device ("module" in IndustryPack jargon). The call
+ * is done by the carrier driver.  The carrier should populate the fields
+ * bus and slot as well as the region array of @dev prior to calling this
+ * function.  The rest of the fields will be allocated and populated
+ * during initalization.
  *
- *     Return zero on success or error code on failure.
+ * Return zero on success or error code on failure.
+ *
+ * NOTE: _Never_ directly free @dev after calling this function, even
+ * if it returned an error! Always use ipack_put_device() to give up the
+ * reference initialized in this function instead.
+ */
+int ipack_device_init(struct ipack_device *dev);
+
+/**
+ *     ipack_device_add -- Add an IPack device
+ * @dev: the new device to add.
+ *
+ * Add a new IPack device. The call is done by the carrier driver
+ * after calling ipack_device_init().
+ *
+ * Return zero on success or error code on failure.
+ *
+ * NOTE: _Never_ directly free @dev after calling this function, even
+ * if it returned an error! Always use ipack_put_device() to give up the
+ * reference initialized in this function instead.
  */
-int ipack_device_register(struct ipack_device *dev);
-void ipack_device_unregister(struct ipack_device *dev);
+int ipack_device_add(struct ipack_device *dev);
+void ipack_device_del(struct ipack_device *dev);
+
+void ipack_get_device(struct ipack_device *dev);
+void ipack_put_device(struct ipack_device *dev);
 
 /**
  * DEFINE_IPACK_DEVICE_TABLE - macro used to describe a IndustryPack table
index d2e6927..d78d28a 100644 (file)
@@ -200,6 +200,8 @@ extern size_t vmcoreinfo_max_size;
 
 int __init parse_crashkernel(char *cmdline, unsigned long long system_ram,
                unsigned long long *crash_size, unsigned long long *crash_base);
+int parse_crashkernel_high(char *cmdline, unsigned long long system_ram,
+               unsigned long long *crash_size, unsigned long long *crash_base);
 int parse_crashkernel_low(char *cmdline, unsigned long long system_ram,
                unsigned long long *crash_size, unsigned long long *crash_base);
 int crash_shrink_memory(unsigned long new_size);
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
new file mode 100644 (file)
index 0000000..d14af7b
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef _LINUX_MEI_CL_BUS_H
+#define _LINUX_MEI_CL_BUS_H
+
+#include <linux/device.h>
+#include <linux/uuid.h>
+
+struct mei_cl_device;
+
+struct mei_cl_driver {
+       struct device_driver driver;
+       const char *name;
+
+       const struct mei_cl_device_id *id_table;
+
+       int (*probe)(struct mei_cl_device *dev,
+                    const struct mei_cl_device_id *id);
+       int (*remove)(struct mei_cl_device *dev);
+};
+
+int __mei_cl_driver_register(struct mei_cl_driver *driver,
+                               struct module *owner);
+#define mei_cl_driver_register(driver)             \
+       __mei_cl_driver_register(driver, THIS_MODULE)
+
+void mei_cl_driver_unregister(struct mei_cl_driver *driver);
+
+int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length);
+int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length);
+
+typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device,
+                              u32 events, void *context);
+int mei_cl_register_event_cb(struct mei_cl_device *device,
+                         mei_cl_event_cb_t read_cb, void *context);
+
+#define MEI_CL_EVENT_RX 0
+#define MEI_CL_EVENT_TX 1
+
+void *mei_cl_get_drvdata(const struct mei_cl_device *device);
+void mei_cl_set_drvdata(struct mei_cl_device *device, void *data);
+
+int mei_cl_enable_device(struct mei_cl_device *device);
+int mei_cl_disable_device(struct mei_cl_device *device);
+
+#endif /* _LINUX_MEI_CL_BUS_H */
index a710255..cc28136 100644 (file)
@@ -100,6 +100,9 @@ struct arizona {
        struct regmap_irq_chip_data *aod_irq_chip;
        struct regmap_irq_chip_data *irq_chip;
 
+       bool hpdet_magic;
+       unsigned int hp_ena;
+
        struct mutex clk_lock;
        int clk32k_ref;
 
index 455c51d..a0f9409 100644 (file)
@@ -86,6 +86,11 @@ struct arizona_micd_config {
        bool gpio;
 };
 
+struct arizona_micd_range {
+       int max;  /** Ohms */
+       int key;  /** Key to report to input layer */
+};
+
 struct arizona_pdata {
        int reset;      /** GPIO controlling /RESET, if any */
        int ldoena;     /** GPIO controlling LODENA, if any */
@@ -117,12 +122,21 @@ struct arizona_pdata {
        /** GPIO5 is used for jack detection */
        bool jd_gpio5;
 
+       /** Internal pull on GPIO5 is disabled when used for jack detection */
+       bool jd_gpio5_nopull;
+
        /** Use the headphone detect circuit to identify the accessory */
        bool hpdet_acc_id;
 
+       /** Check for line output with HPDET method */
+       bool hpdet_acc_id_line;
+
        /** GPIO used for mic isolation with HPDET */
        int hpdet_id_gpio;
 
+       /** Extra debounce timeout used during initial mic detection (ms) */
+       int micd_detect_debounce;
+
        /** GPIO for mic detection polarity */
        int micd_pol_gpio;
 
@@ -135,9 +149,16 @@ struct arizona_pdata {
        /** Mic detect debounce level */
        int micd_dbtime;
 
+       /** Mic detect timeout (ms) */
+       int micd_timeout;
+
        /** Force MICBIAS on for mic detect */
        bool micd_force_micbias;
 
+       /** Mic detect level parameters */
+       const struct arizona_micd_range *micd_ranges;
+       int num_micd_ranges;
+
        /** Headset polarity configurations */
        struct arizona_micd_config *micd_configs;
        int num_micd_configs;
index 3403551..f43aa7c 100644 (file)
 #define ARIZONA_MIC_DETECT_1                     0x2A3
 #define ARIZONA_MIC_DETECT_2                     0x2A4
 #define ARIZONA_MIC_DETECT_3                     0x2A5
+#define ARIZONA_MIC_DETECT_LEVEL_1              0x2A6
+#define ARIZONA_MIC_DETECT_LEVEL_2              0x2A7
+#define ARIZONA_MIC_DETECT_LEVEL_3              0x2A8
+#define ARIZONA_MIC_DETECT_LEVEL_4              0x2A9
 #define ARIZONA_MIC_NOISE_MIX_CONTROL_1          0x2C3
 #define ARIZONA_ISOLATION_CONTROL                0x2CB
 #define ARIZONA_JACK_DETECT_ANALOGUE             0x2D3
index e19ff30..e2091b8 100644 (file)
@@ -1611,6 +1611,8 @@ int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
                        unsigned long pfn);
 int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
                        unsigned long pfn);
+int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len);
+
 
 struct page *follow_page_mask(struct vm_area_struct *vma,
                              unsigned long address, unsigned int foll_flags,
index 779cf7c..b508016 100644 (file)
@@ -9,6 +9,7 @@
 
 #ifdef __KERNEL__
 #include <linux/types.h>
+#include <linux/uuid.h>
 typedef unsigned long kernel_ulong_t;
 #endif
 
@@ -568,4 +569,12 @@ struct ipack_device_id {
        __u32 device;                   /* Device ID or IPACK_ANY_ID */
 };
 
+#define MEI_CL_MODULE_PREFIX "mei:"
+#define MEI_CL_NAME_SIZE 32
+
+struct mei_cl_device_id {
+       char name[MEI_CL_NAME_SIZE];
+       kernel_ulong_t driver_info;
+};
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
index ce93a34..20c2d6d 100644 (file)
@@ -13,14 +13,14 @@ struct msi_msg {
 /* Helper functions */
 struct irq_data;
 struct msi_desc;
-extern void mask_msi_irq(struct irq_data *data);
-extern void unmask_msi_irq(struct irq_data *data);
-extern void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-extern void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-extern void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
-extern void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
-extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
+void mask_msi_irq(struct irq_data *data);
+void unmask_msi_irq(struct irq_data *data);
+void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+void read_msi_msg(unsigned int irq, struct msi_msg *msg);
+void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
+void write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
 struct msi_desc {
        struct {
@@ -54,9 +54,8 @@ struct msi_desc {
  */
 int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
 void arch_teardown_msi_irq(unsigned int irq);
-extern int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
-extern void arch_teardown_msi_irqs(struct pci_dev *dev);
-extern int arch_msi_check_device(struct pci_dev* dev, int nvec, int type);
-
+int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
+void arch_teardown_msi_irqs(struct pci_dev *dev);
+int arch_msi_check_device(struct pci_dev* dev, int nvec, int type);
 
 #endif /* LINUX_MSI_H */
index 9121595..433da8a 100644 (file)
@@ -53,6 +53,9 @@ struct mutex {
 #if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
        struct task_struct      *owner;
 #endif
+#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
+       void                    *spin_mlock;    /* Spinner MCS lock */
+#endif
 #ifdef CONFIG_DEBUG_MUTEXES
        const char              *name;
        void                    *magic;
index 01d25e6..0214c4c 100644 (file)
@@ -291,6 +291,7 @@ ip_set_hash_destroy(struct ip_set *set)
 #define type_pf_data_tlist     TOKEN(TYPE, PF, _data_tlist)
 #define type_pf_data_next      TOKEN(TYPE, PF, _data_next)
 #define type_pf_data_flags     TOKEN(TYPE, PF, _data_flags)
+#define type_pf_data_reset_flags TOKEN(TYPE, PF, _data_reset_flags)
 #ifdef IP_SET_HASH_WITH_NETS
 #define type_pf_data_match     TOKEN(TYPE, PF, _data_match)
 #else
@@ -385,9 +386,9 @@ type_pf_resize(struct ip_set *set, bool retried)
        struct ip_set_hash *h = set->data;
        struct htable *t, *orig = h->table;
        u8 htable_bits = orig->htable_bits;
-       const struct type_pf_elem *data;
+       struct type_pf_elem *data;
        struct hbucket *n, *m;
-       u32 i, j;
+       u32 i, j, flags = 0;
        int ret;
 
 retry:
@@ -412,9 +413,16 @@ retry:
                n = hbucket(orig, i);
                for (j = 0; j < n->pos; j++) {
                        data = ahash_data(n, j);
+#ifdef IP_SET_HASH_WITH_NETS
+                       flags = 0;
+                       type_pf_data_reset_flags(data, &flags);
+#endif
                        m = hbucket(t, HKEY(data, h->initval, htable_bits));
-                       ret = type_pf_elem_add(m, data, AHASH_MAX(h), 0);
+                       ret = type_pf_elem_add(m, data, AHASH_MAX(h), flags);
                        if (ret < 0) {
+#ifdef IP_SET_HASH_WITH_NETS
+                               type_pf_data_flags(data, flags);
+#endif
                                read_unlock_bh(&set->lock);
                                ahash_destroy(t);
                                if (ret == -EAGAIN)
@@ -836,9 +844,9 @@ type_pf_tresize(struct ip_set *set, bool retried)
        struct ip_set_hash *h = set->data;
        struct htable *t, *orig = h->table;
        u8 htable_bits = orig->htable_bits;
-       const struct type_pf_elem *data;
+       struct type_pf_elem *data;
        struct hbucket *n, *m;
-       u32 i, j;
+       u32 i, j, flags = 0;
        int ret;
 
        /* Try to cleanup once */
@@ -873,10 +881,17 @@ retry:
                n = hbucket(orig, i);
                for (j = 0; j < n->pos; j++) {
                        data = ahash_tdata(n, j);
+#ifdef IP_SET_HASH_WITH_NETS
+                       flags = 0;
+                       type_pf_data_reset_flags(data, &flags);
+#endif
                        m = hbucket(t, HKEY(data, h->initval, htable_bits));
-                       ret = type_pf_elem_tadd(m, data, AHASH_MAX(h), 0,
-                                               ip_set_timeout_get(type_pf_data_timeout(data)));
+                       ret = type_pf_elem_tadd(m, data, AHASH_MAX(h), flags,
+                               ip_set_timeout_get(type_pf_data_timeout(data)));
                        if (ret < 0) {
+#ifdef IP_SET_HASH_WITH_NETS
+                               type_pf_data_flags(data, flags);
+#endif
                                read_unlock_bh(&set->lock);
                                ahash_destroy(t);
                                if (ret == -EAGAIN)
@@ -1187,6 +1202,7 @@ type_pf_gc_init(struct ip_set *set)
 #undef type_pf_data_tlist
 #undef type_pf_data_next
 #undef type_pf_data_flags
+#undef type_pf_data_reset_flags
 #undef type_pf_data_match
 
 #undef type_pf_elem
index 9a22b5e..81b3161 100644 (file)
@@ -41,8 +41,37 @@ static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
 
        return DEVICE_ACPI_HANDLE(dev);
 }
+
+void acpi_pci_add_bus(struct pci_bus *bus);
+void acpi_pci_remove_bus(struct pci_bus *bus);
+
+#ifdef CONFIG_ACPI_PCI_SLOT
+void acpi_pci_slot_init(void);
+void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle);
+void acpi_pci_slot_remove(struct pci_bus *bus);
+#else
+static inline void acpi_pci_slot_init(void) { }
+static inline void acpi_pci_slot_enumerate(struct pci_bus *bus,
+                                          acpi_handle handle) { }
+static inline void acpi_pci_slot_remove(struct pci_bus *bus) { }
 #endif
 
+#ifdef CONFIG_HOTPLUG_PCI_ACPI
+void acpiphp_init(void);
+void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle);
+void acpiphp_remove_slots(struct pci_bus *bus);
+#else
+static inline void acpiphp_init(void) { }
+static inline void acpiphp_enumerate_slots(struct pci_bus *bus,
+                                          acpi_handle handle) { }
+static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
+#endif
+
+#else  /* CONFIG_ACPI */
+static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
+static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
+#endif /* CONFIG_ACPI */
+
 #ifdef CONFIG_ACPI_APEI
 extern bool aer_acpi_firmware_first(void);
 #else
index c832014..8af4610 100644 (file)
 #define PCIE_LINK_STATE_CLKPM  4
 
 #ifdef CONFIG_PCIEASPM
-extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
-extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
-extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
-extern void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
-extern void pci_disable_link_state(struct pci_dev *pdev, int state);
-extern void pci_disable_link_state_locked(struct pci_dev *pdev, int state);
-extern void pcie_clear_aspm(struct pci_bus *bus);
-extern void pcie_no_aspm(void);
+void pcie_aspm_init_link_state(struct pci_dev *pdev);
+void pcie_aspm_exit_link_state(struct pci_dev *pdev);
+void pcie_aspm_pm_state_change(struct pci_dev *pdev);
+void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
+void pci_disable_link_state(struct pci_dev *pdev, int state);
+void pci_disable_link_state_locked(struct pci_dev *pdev, int state);
+void pcie_clear_aspm(struct pci_bus *bus);
+void pcie_no_aspm(void);
 #else
 static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
 {
@@ -56,8 +56,8 @@ static inline void pcie_no_aspm(void)
 #endif
 
 #ifdef CONFIG_PCIEASPM_DEBUG /* this depends on CONFIG_PCIEASPM */
-extern void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev);
-extern void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev);
+void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev);
+void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev);
 #else
 static inline void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev)
 {
index 7ef6872..68bcefd 100644 (file)
@@ -14,9 +14,9 @@ struct pci_ats {
 
 #ifdef CONFIG_PCI_ATS
 
-extern int pci_enable_ats(struct pci_dev *dev, int ps);
-extern void pci_disable_ats(struct pci_dev *dev);
-extern int pci_ats_queue_depth(struct pci_dev *dev);
+int pci_enable_ats(struct pci_dev *dev, int ps);
+void pci_disable_ats(struct pci_dev *dev);
+int pci_ats_queue_depth(struct pci_dev *dev);
 
 /**
  * pci_ats_enabled - query the ATS status
@@ -54,12 +54,12 @@ static inline int pci_ats_enabled(struct pci_dev *dev)
 
 #ifdef CONFIG_PCI_PRI
 
-extern int  pci_enable_pri(struct pci_dev *pdev, u32 reqs);
-extern void pci_disable_pri(struct pci_dev *pdev);
-extern bool pci_pri_enabled(struct pci_dev *pdev);
-extern int  pci_reset_pri(struct pci_dev *pdev);
-extern bool pci_pri_stopped(struct pci_dev *pdev);
-extern int  pci_pri_status(struct pci_dev *pdev);
+int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
+void pci_disable_pri(struct pci_dev *pdev);
+bool pci_pri_enabled(struct pci_dev *pdev);
+int pci_reset_pri(struct pci_dev *pdev);
+bool pci_pri_stopped(struct pci_dev *pdev);
+int pci_pri_status(struct pci_dev *pdev);
 
 #else /* CONFIG_PCI_PRI */
 
@@ -95,10 +95,10 @@ static inline int pci_pri_status(struct pci_dev *pdev)
 
 #ifdef CONFIG_PCI_PASID
 
-extern int pci_enable_pasid(struct pci_dev *pdev, int features);
-extern void pci_disable_pasid(struct pci_dev *pdev);
-extern int pci_pasid_features(struct pci_dev *pdev);
-extern int pci_max_pasids(struct pci_dev *pdev);
+int pci_enable_pasid(struct pci_dev *pdev, int features);
+void pci_disable_pasid(struct pci_dev *pdev);
+int pci_pasid_features(struct pci_dev *pdev);
+int pci_max_pasids(struct pci_dev *pdev);
 
 #else  /* CONFIG_PCI_PASID */
 
index 710067f..e73dfa3 100644 (file)
 /* Include the ID list */
 #include <linux/pci_ids.h>
 
+/*
+ * The PCI interface treats multi-function devices as independent
+ * devices.  The slot/function address of each device is encoded
+ * in a single byte as follows:
+ *
+ *     7:3 = slot
+ *     2:0 = function
+ * PCI_DEVFN(), PCI_SLOT(), and PCI_FUNC() are defined uapi/linux/pci.h
+ * In the interest of not exposing interfaces to user-space unnecessarily,
+ * the following kernel only defines are being added here.
+ */
+#define PCI_DEVID(bus, devfn)  ((((u16)bus) << 8) | devfn)
+/* return bus from PCI devid = ((u16)bus_number) << 8) | devfn */
+#define PCI_BUS_NUM(x) (((x) >> 8) & 0xff)
+
 /* pci_slot represents a physical slot */
 struct pci_slot {
        struct pci_bus *bus;            /* The bus this slot is on */
@@ -232,6 +247,8 @@ struct pci_dev {
        u8              revision;       /* PCI revision, low byte of class word */
        u8              hdr_type;       /* PCI header type (`multi' flag masked out) */
        u8              pcie_cap;       /* PCI-E capability offset */
+       u8              msi_cap;        /* MSI capability offset */
+       u8              msix_cap;       /* MSI-X capability offset */
        u8              pcie_mpss:3;    /* PCI-E Max Payload Size Supported */
        u8              rom_base_reg;   /* which config register controls the ROM */
        u8              pin;            /* which interrupt pin this device uses */
@@ -249,8 +266,7 @@ struct pci_dev {
        pci_power_t     current_state;  /* Current operating state. In ACPI-speak,
                                           this is D0-D3, D0 being fully functional,
                                           and D3 being off. */
-       int             pm_cap;         /* PM capability offset in the
-                                          configuration space */
+       u8              pm_cap;         /* PM capability offset */
        unsigned int    pme_support:5;  /* Bitmask of states from which PME#
                                           can be generated */
        unsigned int    pme_interrupt:1;
@@ -348,7 +364,7 @@ static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
        return dev;
 }
 
-extern struct pci_dev *alloc_pci_dev(void);
+struct pci_dev *alloc_pci_dev(void);
 
 #define        to_pci_dev(n) container_of(n, struct pci_dev, dev)
 #define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
@@ -504,10 +520,10 @@ struct pci_ops {
  * ACPI needs to be able to access PCI config space before we've done a
  * PCI bus scan and created pci_bus structures.
  */
-extern int raw_pci_read(unsigned int domain, unsigned int bus,
-                       unsigned int devfn, int reg, int len, u32 *val);
-extern int raw_pci_write(unsigned int domain, unsigned int bus,
-                       unsigned int devfn, int reg, int len, u32 val);
+int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
+                int reg, int len, u32 *val);
+int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
+                 int reg, int len, u32 val);
 
 struct pci_bus_region {
        resource_size_t start;
@@ -658,7 +674,7 @@ struct pci_driver {
 /* these external functions are only available when PCI support is enabled */
 #ifdef CONFIG_PCI
 
-extern void pcie_bus_configure_settings(struct pci_bus *bus, u8 smpss);
+void pcie_bus_configure_settings(struct pci_bus *bus, u8 smpss);
 
 enum pcie_bus_config_types {
        PCIE_BUS_TUNE_OFF,
@@ -675,9 +691,11 @@ extern struct bus_type pci_bus_type;
  * code, or pci core code. */
 extern struct list_head pci_root_buses;        /* list of all known PCI buses */
 /* Some device drivers need know if pci is initiated */
-extern int no_pci_devices(void);
+int no_pci_devices(void);
 
 void pcibios_resource_survey_bus(struct pci_bus *bus);
+void pcibios_add_bus(struct pci_bus *bus);
+void pcibios_remove_bus(struct pci_bus *bus);
 void pcibios_fixup_bus(struct pci_bus *);
 int __must_check pcibios_enable_device(struct pci_dev *, int mask);
 /* Architecture specific versions may override this (weak) */
@@ -699,7 +717,7 @@ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
 void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
                             struct pci_bus_region *region);
 void pcibios_scan_specific_bus(int busn);
-extern struct pci_bus *pci_find_bus(int domain, int busnr);
+struct pci_bus *pci_find_bus(int domain, int busnr);
 void pci_bus_add_devices(const struct pci_bus *bus);
 struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
                                      struct pci_ops *ops, void *sysdata);
@@ -732,14 +750,14 @@ struct resource *pci_find_parent_resource(const struct pci_dev *dev,
 u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin);
 int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge);
 u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp);
-extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
-extern void pci_dev_put(struct pci_dev *dev);
-extern void pci_remove_bus(struct pci_bus *b);
-extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
+struct pci_dev *pci_dev_get(struct pci_dev *dev);
+void pci_dev_put(struct pci_dev *dev);
+void pci_remove_bus(struct pci_bus *b);
+void pci_stop_and_remove_bus_device(struct pci_dev *dev);
 void pci_stop_root_bus(struct pci_bus *bus);
 void pci_remove_root_bus(struct pci_bus *bus);
 void pci_setup_cardbus(struct pci_bus *bus);
-extern void pci_sort_breadthfirst(void);
+void pci_sort_breadthfirst(void);
 #define dev_is_pci(d) ((d)->bus == &pci_bus_type)
 #define dev_is_pf(d) ((dev_is_pci(d) ? to_pci_dev(d)->is_physfn : false))
 #define dev_num_vf(d) ((dev_is_pci(d) ? pci_num_vf(to_pci_dev(d)) : 0))
@@ -1142,18 +1160,17 @@ static inline int pci_msi_enabled(void)
        return 0;
 }
 #else
-extern int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec);
-extern int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec);
-extern void pci_msi_shutdown(struct pci_dev *dev);
-extern void pci_disable_msi(struct pci_dev *dev);
-extern int pci_msix_table_size(struct pci_dev *dev);
-extern int pci_enable_msix(struct pci_dev *dev,
-       struct msix_entry *entries, int nvec);
-extern void pci_msix_shutdown(struct pci_dev *dev);
-extern void pci_disable_msix(struct pci_dev *dev);
-extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
-extern void pci_restore_msi_state(struct pci_dev *dev);
-extern int pci_msi_enabled(void);
+int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec);
+int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec);
+void pci_msi_shutdown(struct pci_dev *dev);
+void pci_disable_msi(struct pci_dev *dev);
+int pci_msix_table_size(struct pci_dev *dev);
+int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec);
+void pci_msix_shutdown(struct pci_dev *dev);
+void pci_disable_msix(struct pci_dev *dev);
+void msi_remove_pci_irq_vectors(struct pci_dev *dev);
+void pci_restore_msi_state(struct pci_dev *dev);
+int pci_msi_enabled(void);
 #endif
 
 #ifdef CONFIG_PCIEPORTBUS
@@ -1168,8 +1185,8 @@ extern bool pcie_ports_auto;
 static inline int pcie_aspm_enabled(void) { return 0; }
 static inline bool pcie_aspm_support_enabled(void) { return false; }
 #else
-extern int pcie_aspm_enabled(void);
-extern bool pcie_aspm_support_enabled(void);
+int pcie_aspm_enabled(void);
+bool pcie_aspm_support_enabled(void);
 #endif
 
 #ifdef CONFIG_PCIEAER
@@ -1187,8 +1204,8 @@ static inline void pcie_set_ecrc_checking(struct pci_dev *dev)
 }
 static inline void pcie_ecrc_get_policy(char *str) {};
 #else
-extern void pcie_set_ecrc_checking(struct pci_dev *dev);
-extern void pcie_ecrc_get_policy(char *str);
+void pcie_set_ecrc_checking(struct pci_dev *dev);
+void pcie_ecrc_get_policy(char *str);
 #endif
 
 #define pci_enable_msi(pdev)   pci_enable_msi_block(pdev, 1)
@@ -1199,9 +1216,9 @@ int  ht_create_irq(struct pci_dev *dev, int idx);
 void ht_destroy_irq(unsigned int irq);
 #endif /* CONFIG_HT_IRQ */
 
-extern void pci_cfg_access_lock(struct pci_dev *dev);
-extern bool pci_cfg_access_trylock(struct pci_dev *dev);
-extern void pci_cfg_access_unlock(struct pci_dev *dev);
+void pci_cfg_access_lock(struct pci_dev *dev);
+bool pci_cfg_access_trylock(struct pci_dev *dev);
+void pci_cfg_access_unlock(struct pci_dev *dev);
 
 /*
  * PCI domain support.  Sometimes called PCI segment (eg by ACPI),
@@ -1226,7 +1243,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
 /* some architectures require additional setup to direct VGA traffic */
 typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode,
                      unsigned int command_bits, u32 flags);
-extern void pci_register_set_vga_state(arch_set_vga_state_t func);
+void pci_register_set_vga_state(arch_set_vga_state_t func);
 
 #else /* CONFIG_PCI is not enabled */
 
@@ -1628,8 +1645,8 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev,
 int pcibios_add_device(struct pci_dev *dev);
 
 #ifdef CONFIG_PCI_MMCONFIG
-extern void __init pci_mmcfg_early_init(void);
-extern void __init pci_mmcfg_late_init(void);
+void __init pci_mmcfg_early_init(void);
+void __init pci_mmcfg_late_init(void);
 #else
 static inline void pci_mmcfg_early_init(void) { }
 static inline void pci_mmcfg_late_init(void) { }
@@ -1640,12 +1657,12 @@ int pci_ext_cfg_avail(void);
 void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar);
 
 #ifdef CONFIG_PCI_IOV
-extern int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
-extern void pci_disable_sriov(struct pci_dev *dev);
-extern irqreturn_t pci_sriov_migration(struct pci_dev *dev);
-extern int pci_num_vf(struct pci_dev *dev);
-extern int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
-extern int pci_sriov_get_totalvfs(struct pci_dev *dev);
+int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
+void pci_disable_sriov(struct pci_dev *dev);
+irqreturn_t pci_sriov_migration(struct pci_dev *dev);
+int pci_num_vf(struct pci_dev *dev);
+int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
+int pci_sriov_get_totalvfs(struct pci_dev *dev);
 #else
 static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
 {
@@ -1673,8 +1690,8 @@ static inline int pci_sriov_get_totalvfs(struct pci_dev *dev)
 #endif
 
 #if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)
-extern void pci_hp_create_module_link(struct pci_slot *pci_slot);
-extern void pci_hp_remove_module_link(struct pci_slot *pci_slot);
+void pci_hp_create_module_link(struct pci_slot *pci_slot);
+void pci_hp_remove_module_link(struct pci_slot *pci_slot);
 #endif
 
 /**
@@ -1818,13 +1835,13 @@ int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off,
 /* PCI <-> OF binding helpers */
 #ifdef CONFIG_OF
 struct device_node;
-extern void pci_set_of_node(struct pci_dev *dev);
-extern void pci_release_of_node(struct pci_dev *dev);
-extern void pci_set_bus_of_node(struct pci_bus *bus);
-extern void pci_release_bus_of_node(struct pci_bus *bus);
+void pci_set_of_node(struct pci_dev *dev);
+void pci_release_of_node(struct pci_dev *dev);
+void pci_set_bus_of_node(struct pci_bus *bus);
+void pci_release_bus_of_node(struct pci_bus *bus);
 
 /* Arch may override this (weak) */
-extern struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus);
+struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus);
 
 static inline struct device_node *
 pci_device_to_OF_node(const struct pci_dev *pdev)
index 45fc162..8db71dc 100644 (file)
@@ -125,12 +125,12 @@ static inline const char *hotplug_slot_name(const struct hotplug_slot *slot)
        return pci_slot_name(slot->pci_slot);
 }
 
-extern int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *pbus,
-                            int nr, const char *name,
-                            struct module *owner, const char *mod_name);
-extern int pci_hp_deregister(struct hotplug_slot *slot);
-extern int __must_check pci_hp_change_slot_info        (struct hotplug_slot *slot,
-                                                struct hotplug_slot_info *info);
+int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *pbus, int nr,
+                     const char *name, struct module *owner,
+                     const char *mod_name);
+int pci_hp_deregister(struct hotplug_slot *slot);
+int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
+                                        struct hotplug_slot_info *info);
 
 /* use a define to avoid include chaining to get THIS_MODULE & friends */
 #define pci_hp_register(slot, pbus, devnr, name) \
index f11c1c2..a80f9e6 100644 (file)
 #define PCI_SUBDEVICE_ID_KEYSPAN_SX2   0x5334
 
 #define PCI_VENDOR_ID_MARVELL          0x11ab
+#define PCI_VENDOR_ID_MARVELL_EXT      0x1b4b
 #define PCI_DEVICE_ID_MARVELL_GT64111  0x4146
 #define PCI_DEVICE_ID_MARVELL_GT64260  0x6430
 #define PCI_DEVICE_ID_MARVELL_MV64360  0x6460
index e6f91b1..9572669 100644 (file)
@@ -62,7 +62,7 @@ struct pcie_port_service_driver {
 #define to_service_driver(d) \
        container_of(d, struct pcie_port_service_driver, driver)
 
-extern int pcie_port_service_register(struct pcie_port_service_driver *new);
-extern void pcie_port_service_unregister(struct pcie_port_service_driver *new);
+int pcie_port_service_register(struct pcie_port_service_driver *new);
+void pcie_port_service_unregister(struct pcie_port_service_driver *new);
 
 #endif /* _PCIEPORT_IF_H_ */
index e7a7201..1ad4f31 100644 (file)
@@ -14,6 +14,8 @@
 
 #ifdef CONFIG_PINCONF
 
+#include <linux/pinctrl/machine.h>
+
 struct pinctrl_dev;
 struct seq_file;
 
@@ -28,6 +30,7 @@ struct seq_file;
  * @pin_config_set: configure an individual pin
  * @pin_config_group_get: get configurations for an entire pin group
  * @pin_config_group_set: configure all pins in a group
+ * @pin_config_group_dbg_set: optional debugfs to modify a pin configuration
  * @pin_config_dbg_show: optional debugfs display hook that will provide
  *     per-device info for a certain pin in debugfs
  * @pin_config_group_dbg_show: optional debugfs display hook that will provide
@@ -51,6 +54,9 @@ struct pinconf_ops {
        int (*pin_config_group_set) (struct pinctrl_dev *pctldev,
                                     unsigned selector,
                                     unsigned long config);
+       int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev,
+                                          const char *arg,
+                                          unsigned long *config);
        void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev,
                                     struct seq_file *s,
                                     unsigned offset);
index 778804d..2c2a9e8 100644 (file)
@@ -118,9 +118,9 @@ struct pinctrl_desc {
        const char *name;
        struct pinctrl_pin_desc const *pins;
        unsigned int npins;
-       struct pinctrl_ops *pctlops;
-       struct pinmux_ops *pmxops;
-       struct pinconf_ops *confops;
+       const struct pinctrl_ops *pctlops;
+       const struct pinmux_ops *pmxops;
+       const struct pinconf_ops *confops;
        struct module *owner;
 };
 
index 03378ca..5c19a2a 100644 (file)
@@ -40,6 +40,7 @@
 /* Custom config requests */
 #define EMIF_CUSTOM_CONFIG_LPMODE                      0x00000001
 #define EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL    0x00000002
+#define EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART          0x00000004
 
 #ifndef __ASSEMBLY__
 /**
index 88734e8..c7285b5 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef _LINUX_NTC_H
 #define _LINUX_NTC_H
 
+struct iio_channel;
+
 enum ntc_thermistor_type {
        TYPE_NCPXXWB473,
        TYPE_NCPXXWL333,
@@ -39,13 +41,17 @@ struct ntc_thermistor_platform_data {
         * described at Documentation/hwmon/ntc_thermistor
         *
         * pullup/down_ohm: 0 for infinite / not-connected
+        *
+        * chan: iio_channel pointer to communicate with the ADC which the
+        * thermistor is using for conversion of the analog values.
         */
-       int (*read_uV)(void);
-       unsigned int pullup_uV;
+       int (*read_uv)(struct ntc_thermistor_platform_data *);
+       unsigned int pullup_uv;
 
        unsigned int pullup_ohm;
        unsigned int pulldown_ohm;
        enum { NTC_CONNECTED_POSITIVE, NTC_CONNECTED_GROUND } connect;
+       struct iio_channel *chan;
 
        int (*read_ohm)(void);
 };
diff --git a/include/linux/platform_data/video-vt8500lcdfb.h b/include/linux/platform_data/video-vt8500lcdfb.h
deleted file mode 100644 (file)
index 7f399c3..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- *  VT8500/WM8505 Frame Buffer platform data definitions
- *
- *  Copyright (C) 2010 Ed Spiridonov <edo.rus@gmail.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef _VT8500FB_H
-#define _VT8500FB_H
-
-#include <linux/fb.h>
-
-struct vt8500fb_platform_data {
-       struct fb_videomode     mode;
-       u32                     xres_virtual;
-       u32                     yres_virtual;
-       u32                     bpp;
-       unsigned long           video_mem_phys;
-       void                    *video_mem_virt;
-       unsigned long           video_mem_len;
-};
-
-#endif /* _VT8500FB_H */
diff --git a/include/linux/platform_data/video_s3c.h b/include/linux/platform_data/video_s3c.h
new file mode 100644 (file)
index 0000000..4888399
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __PLATFORM_DATA_VIDEO_S3C
+#define __PLATFORM_DATA_VIDEO_S3C
+
+/* S3C_FB_MAX_WIN
+ * Set to the maximum number of windows that any of the supported hardware
+ * can use. Since the platform data uses this for an array size, having it
+ * set to the maximum of any version of the hardware can do is safe.
+ */
+#define S3C_FB_MAX_WIN (5)
+
+/**
+ * struct s3c_fb_pd_win - per window setup data
+ * @xres     : The window X size.
+ * @yres     : The window Y size.
+ * @virtual_x: The virtual X size.
+ * @virtual_y: The virtual Y size.
+ */
+struct s3c_fb_pd_win {
+       unsigned short          default_bpp;
+       unsigned short          max_bpp;
+       unsigned short          xres;
+       unsigned short          yres;
+       unsigned short          virtual_x;
+       unsigned short          virtual_y;
+};
+
+/**
+ * struct s3c_fb_platdata -  S3C driver platform specific information
+ * @setup_gpio: Setup the external GPIO pins to the right state to transfer
+ *             the data from the display system to the connected display
+ *             device.
+ * @vidcon0: The base vidcon0 values to control the panel data format.
+ * @vidcon1: The base vidcon1 values to control the panel data output.
+ * @vtiming: Video timing when connected to a RGB type panel.
+ * @win: The setup data for each hardware window, or NULL for unused.
+ * @display_mode: The LCD output display mode.
+ *
+ * The platform data supplies the video driver with all the information
+ * it requires to work with the display(s) attached to the machine. It
+ * controls the initial mode, the number of display windows (0 is always
+ * the base framebuffer) that are initialised etc.
+ *
+ */
+struct s3c_fb_platdata {
+       void    (*setup_gpio)(void);
+
+       struct s3c_fb_pd_win    *win[S3C_FB_MAX_WIN];
+       struct fb_videomode     *vtiming;
+
+       u32                      vidcon0;
+       u32                      vidcon1;
+};
+
+#endif
index d35d2b6..2d02c76 100644 (file)
@@ -163,9 +163,10 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 #define TASK_DEAD              64
 #define TASK_WAKEKILL          128
 #define TASK_WAKING            256
-#define TASK_STATE_MAX         512
+#define TASK_PARKED            512
+#define TASK_STATE_MAX         1024
 
-#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKW"
+#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKWP"
 
 extern char ___assert_task_state[1 - 2*!!(
                sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)];
@@ -320,7 +321,6 @@ extern signed long schedule_timeout_killable(signed long timeout);
 extern signed long schedule_timeout_uninterruptible(signed long timeout);
 asmlinkage void schedule(void);
 extern void schedule_preempt_disabled(void);
-extern int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner);
 
 struct nsproxy;
 struct user_namespace;
index 9e492be..6fcfe99 100644 (file)
 #define SSB_CHIPCO_PMU_CTL                     0x0600 /* PMU control */
 #define  SSB_CHIPCO_PMU_CTL_ILP_DIV            0xFFFF0000 /* ILP div mask */
 #define  SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT      16
+#define  SSB_CHIPCO_PMU_CTL_PLL_UPD            0x00000400
 #define  SSB_CHIPCO_PMU_CTL_NOILPONW           0x00000200 /* No ILP on wait */
 #define  SSB_CHIPCO_PMU_CTL_HTREQEN            0x00000100 /* HT req enable */
 #define  SSB_CHIPCO_PMU_CTL_ALPREQEN           0x00000080 /* ALP req enable */
@@ -667,5 +668,6 @@ enum ssb_pmu_ldo_volt_id {
 void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc,
                             enum ssb_pmu_ldo_volt_id id, u32 voltage);
 void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on);
+void ssb_pmu_spuravoid_pllupdate(struct ssb_chipcommon *cc, int spuravoid);
 
 #endif /* LINUX_SSB_CHIPCO_H_ */
diff --git a/include/linux/ssbi.h b/include/linux/ssbi.h
new file mode 100644 (file)
index 0000000..44ef5da
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Author: Dima Zavin <dima@android.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _LINUX_SSBI_H
+#define _LINUX_SSBI_H
+
+#include <linux/types.h>
+
+struct ssbi_slave_info {
+       const char      *name;
+       void            *platform_data;
+};
+
+enum ssbi_controller_type {
+       MSM_SBI_CTRL_SSBI = 0,
+       MSM_SBI_CTRL_SSBI2,
+       MSM_SBI_CTRL_PMIC_ARBITER,
+};
+
+struct ssbi_platform_data {
+       struct ssbi_slave_info  slave;
+       enum ssbi_controller_type controller_type;
+};
+
+int ssbi_write(struct device *dev, u16 addr, u8 *buf, int len);
+int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len);
+#endif
index 2de42f9..a5ffd32 100644 (file)
@@ -25,6 +25,7 @@ extern int swiotlb_force;
 extern void swiotlb_init(int verbose);
 int swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose);
 extern unsigned long swiotlb_nr_tbl(void);
+unsigned long swiotlb_size_or_default(void);
 extern int swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs);
 
 /*
diff --git a/include/linux/ucs2_string.h b/include/linux/ucs2_string.h
new file mode 100644 (file)
index 0000000..cbb20af
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _LINUX_UCS2_STRING_H_
+#define _LINUX_UCS2_STRING_H_
+
+#include <linux/types.h>       /* for size_t */
+#include <linux/stddef.h>      /* for NULL */
+
+typedef u16 ucs2_char_t;
+
+unsigned long ucs2_strnlen(const ucs2_char_t *s, size_t maxlength);
+unsigned long ucs2_strlen(const ucs2_char_t *s);
+unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength);
+int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len);
+
+#endif /* _LINUX_UCS2_STRING_H_ */
index 40be2a0..84a6440 100644 (file)
@@ -199,6 +199,7 @@ extern bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
 /* Device notifier */
 extern int register_inet6addr_notifier(struct notifier_block *nb);
 extern int unregister_inet6addr_notifier(struct notifier_block *nb);
+extern int inet6addr_notifier_call_chain(unsigned long val, void *v);
 
 extern void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex,
                                         struct ipv6_devconf *devconf);
index f741091..f132924 100644 (file)
@@ -256,7 +256,8 @@ static inline __u32 irlmp_get_daddr(const struct lsap_cb *self)
        return (self && self->lap) ? self->lap->daddr : 0;
 }
 
-extern const char *irlmp_reasons[];
+const char *irlmp_reason_str(LM_REASON reason);
+
 extern int sysctl_discovery_timeout;
 extern int sysctl_discovery_slots;
 extern int sysctl_discovery;
index 975cca0..b117081 100644 (file)
@@ -56,8 +56,8 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
        scm->pid  = get_pid(pid);
        scm->cred = cred ? get_cred(cred) : NULL;
        scm->creds.pid = pid_vnr(pid);
-       scm->creds.uid = cred ? cred->euid : INVALID_UID;
-       scm->creds.gid = cred ? cred->egid : INVALID_GID;
+       scm->creds.uid = cred ? cred->uid : INVALID_UID;
+       scm->creds.gid = cred ? cred->gid : INVALID_GID;
 }
 
 static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
index 3bbbd78..2d56e42 100644 (file)
@@ -65,6 +65,18 @@ struct pcmcia_driver {
 int pcmcia_register_driver(struct pcmcia_driver *driver);
 void pcmcia_unregister_driver(struct pcmcia_driver *driver);
 
+/**
+ * module_pcmcia_driver() - Helper macro for registering a pcmcia driver
+ * @__pcmcia_driver: pcmcia_driver struct
+ *
+ * Helper macro for pcmcia drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only use
+ * this macro once, and calling it replaces module_init() and module_exit().
+ */
+#define module_pcmcia_driver(__pcmcia_driver) \
+       module_driver(__pcmcia_driver, pcmcia_register_driver, \
+                       pcmcia_unregister_driver)
+
 /* for struct resource * array embedded in struct pcmcia_device */
 enum {
        PCMCIA_IOPORT_0,
index 9961726..9c14673 100644 (file)
@@ -257,6 +257,7 @@ TRACE_EVENT(block_bio_bounce,
 
 /**
  * block_bio_complete - completed all work on the block operation
+ * @q: queue holding the block operation
  * @bio: block operation completed
  * @error: io error value
  *
@@ -265,9 +266,9 @@ TRACE_EVENT(block_bio_bounce,
  */
 TRACE_EVENT(block_bio_complete,
 
-       TP_PROTO(struct bio *bio, int error),
+       TP_PROTO(struct request_queue *q, struct bio *bio, int error),
 
-       TP_ARGS(bio, error),
+       TP_ARGS(q, bio, error),
 
        TP_STRUCT__entry(
                __field( dev_t,         dev             )
@@ -278,8 +279,7 @@ TRACE_EVENT(block_bio_complete,
        ),
 
        TP_fast_assign(
-               __entry->dev            = bio->bi_bdev ?
-                                         bio->bi_bdev->bd_dev : 0;
+               __entry->dev            = bio->bi_bdev->bd_dev;
                __entry->sector         = bio->bi_sector;
                __entry->nr_sector      = bio->bi_size >> 9;
                __entry->error          = error;
index 5a8671e..e5586ca 100644 (file)
@@ -147,7 +147,7 @@ TRACE_EVENT(sched_switch,
                  __print_flags(__entry->prev_state & (TASK_STATE_MAX-1), "|",
                                { 1, "S"} , { 2, "D" }, { 4, "T" }, { 8, "t" },
                                { 16, "Z" }, { 32, "X" }, { 64, "x" },
-                               { 128, "W" }) : "R",
+                               { 128, "K" }, { 256, "W" }, { 512, "P" }) : "R",
                __entry->prev_state & TASK_STATE_MAX ? "+" : "",
                __entry->next_comm, __entry->next_pid, __entry->next_prio)
 );
index 8761a03..4cb2835 100644 (file)
 #define CN_VAL_DRBD                    0x1
 #define CN_KVP_IDX                     0x9     /* HyperV KVP */
 #define CN_KVP_VAL                     0x1     /* queries from the kernel */
+#define CN_VSS_IDX                     0xA     /* HyperV VSS */
+#define CN_VSS_VAL                     0x1     /* queries from the kernel */
 
-#define CN_NETLINK_USERS               10      /* Highest index + 1 */
+
+#define CN_NETLINK_USERS               11      /* Highest index + 1 */
 
 /*
  * Maximum connector's message size.
index 4c43b44..706d035 100644 (file)
 #ifndef _LINUX_FUSE_H
 #define _LINUX_FUSE_H
 
-#ifdef __linux__
+#ifdef __KERNEL__
 #include <linux/types.h>
 #else
 #include <stdint.h>
-#define __u64 uint64_t
-#define __s64 int64_t
-#define __u32 uint32_t
-#define __s32 int32_t
-#define __u16 uint16_t
 #endif
 
 /*
    userspace works under 64bit kernels */
 
 struct fuse_attr {
-       __u64   ino;
-       __u64   size;
-       __u64   blocks;
-       __u64   atime;
-       __u64   mtime;
-       __u64   ctime;
-       __u32   atimensec;
-       __u32   mtimensec;
-       __u32   ctimensec;
-       __u32   mode;
-       __u32   nlink;
-       __u32   uid;
-       __u32   gid;
-       __u32   rdev;
-       __u32   blksize;
-       __u32   padding;
+       uint64_t        ino;
+       uint64_t        size;
+       uint64_t        blocks;
+       uint64_t        atime;
+       uint64_t        mtime;
+       uint64_t        ctime;
+       uint32_t        atimensec;
+       uint32_t        mtimensec;
+       uint32_t        ctimensec;
+       uint32_t        mode;
+       uint32_t        nlink;
+       uint32_t        uid;
+       uint32_t        gid;
+       uint32_t        rdev;
+       uint32_t        blksize;
+       uint32_t        padding;
 };
 
 struct fuse_kstatfs {
-       __u64   blocks;
-       __u64   bfree;
-       __u64   bavail;
-       __u64   files;
-       __u64   ffree;
-       __u32   bsize;
-       __u32   namelen;
-       __u32   frsize;
-       __u32   padding;
-       __u32   spare[6];
+       uint64_t        blocks;
+       uint64_t        bfree;
+       uint64_t        bavail;
+       uint64_t        files;
+       uint64_t        ffree;
+       uint32_t        bsize;
+       uint32_t        namelen;
+       uint32_t        frsize;
+       uint32_t        padding;
+       uint32_t        spare[6];
 };
 
 struct fuse_file_lock {
-       __u64   start;
-       __u64   end;
-       __u32   type;
-       __u32   pid; /* tgid */
+       uint64_t        start;
+       uint64_t        end;
+       uint32_t        type;
+       uint32_t        pid; /* tgid */
 };
 
 /**
@@ -364,143 +359,143 @@ enum fuse_notify_code {
 #define FUSE_COMPAT_ENTRY_OUT_SIZE 120
 
 struct fuse_entry_out {
-       __u64   nodeid;         /* Inode ID */
-       __u64   generation;     /* Inode generation: nodeid:gen must
-                                  be unique for the fs's lifetime */
-       __u64   entry_valid;    /* Cache timeout for the name */
-       __u64   attr_valid;     /* Cache timeout for the attributes */
-       __u32   entry_valid_nsec;
-       __u32   attr_valid_nsec;
+       uint64_t        nodeid;         /* Inode ID */
+       uint64_t        generation;     /* Inode generation: nodeid:gen must
+                                          be unique for the fs's lifetime */
+       uint64_t        entry_valid;    /* Cache timeout for the name */
+       uint64_t        attr_valid;     /* Cache timeout for the attributes */
+       uint32_t        entry_valid_nsec;
+       uint32_t        attr_valid_nsec;
        struct fuse_attr attr;
 };
 
 struct fuse_forget_in {
-       __u64   nlookup;
+       uint64_t        nlookup;
 };
 
 struct fuse_forget_one {
-       __u64   nodeid;
-       __u64   nlookup;
+       uint64_t        nodeid;
+       uint64_t        nlookup;
 };
 
 struct fuse_batch_forget_in {
-       __u32   count;
-       __u32   dummy;
+       uint32_t        count;
+       uint32_t        dummy;
 };
 
 struct fuse_getattr_in {
-       __u32   getattr_flags;
-       __u32   dummy;
-       __u64   fh;
+       uint32_t        getattr_flags;
+       uint32_t        dummy;
+       uint64_t        fh;
 };
 
 #define FUSE_COMPAT_ATTR_OUT_SIZE 96
 
 struct fuse_attr_out {
-       __u64   attr_valid;     /* Cache timeout for the attributes */
-       __u32   attr_valid_nsec;
-       __u32   dummy;
+       uint64_t        attr_valid;     /* Cache timeout for the attributes */
+       uint32_t        attr_valid_nsec;
+       uint32_t        dummy;
        struct fuse_attr attr;
 };
 
 #define FUSE_COMPAT_MKNOD_IN_SIZE 8
 
 struct fuse_mknod_in {
-       __u32   mode;
-       __u32   rdev;
-       __u32   umask;
-       __u32   padding;
+       uint32_t        mode;
+       uint32_t        rdev;
+       uint32_t        umask;
+       uint32_t        padding;
 };
 
 struct fuse_mkdir_in {
-       __u32   mode;
-       __u32   umask;
+       uint32_t        mode;
+       uint32_t        umask;
 };
 
 struct fuse_rename_in {
-       __u64   newdir;
+       uint64_t        newdir;
 };
 
 struct fuse_link_in {
-       __u64   oldnodeid;
+       uint64_t        oldnodeid;
 };
 
 struct fuse_setattr_in {
-       __u32   valid;
-       __u32   padding;
-       __u64   fh;
-       __u64   size;
-       __u64   lock_owner;
-       __u64   atime;
-       __u64   mtime;
-       __u64   unused2;
-       __u32   atimensec;
-       __u32   mtimensec;
-       __u32   unused3;
-       __u32   mode;
-       __u32   unused4;
-       __u32   uid;
-       __u32   gid;
-       __u32   unused5;
+       uint32_t        valid;
+       uint32_t        padding;
+       uint64_t        fh;
+       uint64_t        size;
+       uint64_t        lock_owner;
+       uint64_t        atime;
+       uint64_t        mtime;
+       uint64_t        unused2;
+       uint32_t        atimensec;
+       uint32_t        mtimensec;
+       uint32_t        unused3;
+       uint32_t        mode;
+       uint32_t        unused4;
+       uint32_t        uid;
+       uint32_t        gid;
+       uint32_t        unused5;
 };
 
 struct fuse_open_in {
-       __u32   flags;
-       __u32   unused;
+       uint32_t        flags;
+       uint32_t        unused;
 };
 
 struct fuse_create_in {
-       __u32   flags;
-       __u32   mode;
-       __u32   umask;
-       __u32   padding;
+       uint32_t        flags;
+       uint32_t        mode;
+       uint32_t        umask;
+       uint32_t        padding;
 };
 
 struct fuse_open_out {
-       __u64   fh;
-       __u32   open_flags;
-       __u32   padding;
+       uint64_t        fh;
+       uint32_t        open_flags;
+       uint32_t        padding;
 };
 
 struct fuse_release_in {
-       __u64   fh;
-       __u32   flags;
-       __u32   release_flags;
-       __u64   lock_owner;
+       uint64_t        fh;
+       uint32_t        flags;
+       uint32_t        release_flags;
+       uint64_t        lock_owner;
 };
 
 struct fuse_flush_in {
-       __u64   fh;
-       __u32   unused;
-       __u32   padding;
-       __u64   lock_owner;
+       uint64_t        fh;
+       uint32_t        unused;
+       uint32_t        padding;
+       uint64_t        lock_owner;
 };
 
 struct fuse_read_in {
-       __u64   fh;
-       __u64   offset;
-       __u32   size;
-       __u32   read_flags;
-       __u64   lock_owner;
-       __u32   flags;
-       __u32   padding;
+       uint64_t        fh;
+       uint64_t        offset;
+       uint32_t        size;
+       uint32_t        read_flags;
+       uint64_t        lock_owner;
+       uint32_t        flags;
+       uint32_t        padding;
 };
 
 #define FUSE_COMPAT_WRITE_IN_SIZE 24
 
 struct fuse_write_in {
-       __u64   fh;
-       __u64   offset;
-       __u32   size;
-       __u32   write_flags;
-       __u64   lock_owner;
-       __u32   flags;
-       __u32   padding;
+       uint64_t        fh;
+       uint64_t        offset;
+       uint32_t        size;
+       uint32_t        write_flags;
+       uint64_t        lock_owner;
+       uint32_t        flags;
+       uint32_t        padding;
 };
 
 struct fuse_write_out {
-       __u32   size;
-       __u32   padding;
+       uint32_t        size;
+       uint32_t        padding;
 };
 
 #define FUSE_COMPAT_STATFS_SIZE 48
@@ -510,32 +505,32 @@ struct fuse_statfs_out {
 };
 
 struct fuse_fsync_in {
-       __u64   fh;
-       __u32   fsync_flags;
-       __u32   padding;
+       uint64_t        fh;
+       uint32_t        fsync_flags;
+       uint32_t        padding;
 };
 
 struct fuse_setxattr_in {
-       __u32   size;
-       __u32   flags;
+       uint32_t        size;
+       uint32_t        flags;
 };
 
 struct fuse_getxattr_in {
-       __u32   size;
-       __u32   padding;
+       uint32_t        size;
+       uint32_t        padding;
 };
 
 struct fuse_getxattr_out {
-       __u32   size;
-       __u32   padding;
+       uint32_t        size;
+       uint32_t        padding;
 };
 
 struct fuse_lk_in {
-       __u64   fh;
-       __u64   owner;
+       uint64_t        fh;
+       uint64_t        owner;
        struct fuse_file_lock lk;
-       __u32   lk_flags;
-       __u32   padding;
+       uint32_t        lk_flags;
+       uint32_t        padding;
 };
 
 struct fuse_lk_out {
@@ -543,134 +538,135 @@ struct fuse_lk_out {
 };
 
 struct fuse_access_in {
-       __u32   mask;
-       __u32   padding;
+       uint32_t        mask;
+       uint32_t        padding;
 };
 
 struct fuse_init_in {
-       __u32   major;
-       __u32   minor;
-       __u32   max_readahead;
-       __u32   flags;
+       uint32_t        major;
+       uint32_t        minor;
+       uint32_t        max_readahead;
+       uint32_t        flags;
 };
 
 struct fuse_init_out {
-       __u32   major;
-       __u32   minor;
-       __u32   max_readahead;
-       __u32   flags;
-       __u16   max_background;
-       __u16   congestion_threshold;
-       __u32   max_write;
+       uint32_t        major;
+       uint32_t        minor;
+       uint32_t        max_readahead;
+       uint32_t        flags;
+       uint16_t        max_background;
+       uint16_t        congestion_threshold;
+       uint32_t        max_write;
 };
 
 #define CUSE_INIT_INFO_MAX 4096
 
 struct cuse_init_in {
-       __u32   major;
-       __u32   minor;
-       __u32   unused;
-       __u32   flags;
+       uint32_t        major;
+       uint32_t        minor;
+       uint32_t        unused;
+       uint32_t        flags;
 };
 
 struct cuse_init_out {
-       __u32   major;
-       __u32   minor;
-       __u32   unused;
-       __u32   flags;
-       __u32   max_read;
-       __u32   max_write;
-       __u32   dev_major;              /* chardev major */
-       __u32   dev_minor;              /* chardev minor */
-       __u32   spare[10];
+       uint32_t        major;
+       uint32_t        minor;
+       uint32_t        unused;
+       uint32_t        flags;
+       uint32_t        max_read;
+       uint32_t        max_write;
+       uint32_t        dev_major;              /* chardev major */
+       uint32_t        dev_minor;              /* chardev minor */
+       uint32_t        spare[10];
 };
 
 struct fuse_interrupt_in {
-       __u64   unique;
+       uint64_t        unique;
 };
 
 struct fuse_bmap_in {
-       __u64   block;
-       __u32   blocksize;
-       __u32   padding;
+       uint64_t        block;
+       uint32_t        blocksize;
+       uint32_t        padding;
 };
 
 struct fuse_bmap_out {
-       __u64   block;
+       uint64_t        block;
 };
 
 struct fuse_ioctl_in {
-       __u64   fh;
-       __u32   flags;
-       __u32   cmd;
-       __u64   arg;
-       __u32   in_size;
-       __u32   out_size;
+       uint64_t        fh;
+       uint32_t        flags;
+       uint32_t        cmd;
+       uint64_t        arg;
+       uint32_t        in_size;
+       uint32_t        out_size;
 };
 
 struct fuse_ioctl_iovec {
-       __u64   base;
-       __u64   len;
+       uint64_t        base;
+       uint64_t        len;
 };
 
 struct fuse_ioctl_out {
-       __s32   result;
-       __u32   flags;
-       __u32   in_iovs;
-       __u32   out_iovs;
+       int32_t         result;
+       uint32_t        flags;
+       uint32_t        in_iovs;
+       uint32_t        out_iovs;
 };
 
 struct fuse_poll_in {
-       __u64   fh;
-       __u64   kh;
-       __u32   flags;
-       __u32   events;
+       uint64_t        fh;
+       uint64_t        kh;
+       uint32_t        flags;
+       uint32_t        events;
 };
 
 struct fuse_poll_out {
-       __u32   revents;
-       __u32   padding;
+       uint32_t        revents;
+       uint32_t        padding;
 };
 
 struct fuse_notify_poll_wakeup_out {
-       __u64   kh;
+       uint64_t        kh;
 };
 
 struct fuse_fallocate_in {
-       __u64   fh;
-       __u64   offset;
-       __u64   length;
-       __u32   mode;
-       __u32   padding;
+       uint64_t        fh;
+       uint64_t        offset;
+       uint64_t        length;
+       uint32_t        mode;
+       uint32_t        padding;
 };
 
 struct fuse_in_header {
-       __u32   len;
-       __u32   opcode;
-       __u64   unique;
-       __u64   nodeid;
-       __u32   uid;
-       __u32   gid;
-       __u32   pid;
-       __u32   padding;
+       uint32_t        len;
+       uint32_t        opcode;
+       uint64_t        unique;
+       uint64_t        nodeid;
+       uint32_t        uid;
+       uint32_t        gid;
+       uint32_t        pid;
+       uint32_t        padding;
 };
 
 struct fuse_out_header {
-       __u32   len;
-       __s32   error;
-       __u64   unique;
+       uint32_t        len;
+       int32_t         error;
+       uint64_t        unique;
 };
 
 struct fuse_dirent {
-       __u64   ino;
-       __u64   off;
-       __u32   namelen;
-       __u32   type;
+       uint64_t        ino;
+       uint64_t        off;
+       uint32_t        namelen;
+       uint32_t        type;
        char name[];
 };
 
 #define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
-#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
+#define FUSE_DIRENT_ALIGN(x) \
+       (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
 #define FUSE_DIRENT_SIZE(d) \
        FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
 
@@ -685,47 +681,47 @@ struct fuse_direntplus {
        FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen)
 
 struct fuse_notify_inval_inode_out {
-       __u64   ino;
-       __s64   off;
-       __s64   len;
+       uint64_t        ino;
+       int64_t         off;
+       int64_t         len;
 };
 
 struct fuse_notify_inval_entry_out {
-       __u64   parent;
-       __u32   namelen;
-       __u32   padding;
+       uint64_t        parent;
+       uint32_t        namelen;
+       uint32_t        padding;
 };
 
 struct fuse_notify_delete_out {
-       __u64   parent;
-       __u64   child;
-       __u32   namelen;
-       __u32   padding;
+       uint64_t        parent;
+       uint64_t        child;
+       uint32_t        namelen;
+       uint32_t        padding;
 };
 
 struct fuse_notify_store_out {
-       __u64   nodeid;
-       __u64   offset;
-       __u32   size;
-       __u32   padding;
+       uint64_t        nodeid;
+       uint64_t        offset;
+       uint32_t        size;
+       uint32_t        padding;
 };
 
 struct fuse_notify_retrieve_out {
-       __u64   notify_unique;
-       __u64   nodeid;
-       __u64   offset;
-       __u32   size;
-       __u32   padding;
+       uint64_t        notify_unique;
+       uint64_t        nodeid;
+       uint64_t        offset;
+       uint32_t        size;
+       uint32_t        padding;
 };
 
 /* Matches the size of fuse_write_in */
 struct fuse_notify_retrieve_in {
-       __u64   dummy1;
-       __u64   offset;
-       __u32   size;
-       __u32   dummy2;
-       __u64   dummy3;
-       __u64   dummy4;
+       uint64_t        dummy1;
+       uint64_t        offset;
+       uint32_t        size;
+       uint32_t        dummy2;
+       uint64_t        dummy3;
+       uint64_t        dummy4;
 };
 
 #endif /* _LINUX_FUSE_H */
index ebfadc5..864e324 100644 (file)
 
 /* Message Signalled Interrupts registers */
 
-#define PCI_MSI_FLAGS          2       /* Various flags */
-#define  PCI_MSI_FLAGS_64BIT   0x80    /* 64-bit addresses allowed */
-#define  PCI_MSI_FLAGS_QSIZE   0x70    /* Message queue size configured */
-#define  PCI_MSI_FLAGS_QMASK   0x0e    /* Maximum queue size available */
-#define  PCI_MSI_FLAGS_ENABLE  0x01    /* MSI feature enabled */
-#define  PCI_MSI_FLAGS_MASKBIT 0x100   /* 64-bit mask bits allowed */
+#define PCI_MSI_FLAGS          2       /* Message Control */
+#define  PCI_MSI_FLAGS_ENABLE  0x0001  /* MSI feature enabled */
+#define  PCI_MSI_FLAGS_QMASK   0x000e  /* Maximum queue size available */
+#define  PCI_MSI_FLAGS_QSIZE   0x0070  /* Message queue size configured */
+#define  PCI_MSI_FLAGS_64BIT   0x0080  /* 64-bit addresses allowed */
+#define  PCI_MSI_FLAGS_MASKBIT 0x0100  /* Per-vector masking capable */
 #define PCI_MSI_RFU            3       /* Rest of capability flags */
 #define PCI_MSI_ADDRESS_LO     4       /* Lower 32 bits */
 #define PCI_MSI_ADDRESS_HI     8       /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
 #define PCI_MSI_PENDING_64     20      /* Pending intrs for 64-bit devices */
 
 /* MSI-X registers */
-#define PCI_MSIX_FLAGS         2
-#define  PCI_MSIX_FLAGS_QSIZE  0x7FF
-#define  PCI_MSIX_FLAGS_ENABLE (1 << 15)
-#define  PCI_MSIX_FLAGS_MASKALL        (1 << 14)
-#define PCI_MSIX_TABLE         4
-#define PCI_MSIX_PBA           8
-#define  PCI_MSIX_FLAGS_BIRMASK        (7 << 0)
+#define PCI_MSIX_FLAGS         2       /* Message Control */
+#define  PCI_MSIX_FLAGS_QSIZE  0x07FF  /* Table size */
+#define  PCI_MSIX_FLAGS_MASKALL        0x4000  /* Mask all vectors for this function */
+#define  PCI_MSIX_FLAGS_ENABLE 0x8000  /* MSI-X enable */
+#define PCI_MSIX_TABLE         4       /* Table offset */
+#define  PCI_MSIX_TABLE_BIR    0x00000007 /* BAR index */
+#define  PCI_MSIX_TABLE_OFFSET 0xfffffff8 /* Offset into specified BAR */
+#define PCI_MSIX_PBA           8       /* Pending Bit Array offset */
+#define  PCI_MSIX_PBA_BIR      0x00000007 /* BAR index */
+#define  PCI_MSIX_PBA_OFFSET   0xfffffff8 /* Offset into specified BAR */
+#define  PCI_MSIX_FLAGS_BIRMASK        (7 << 0)   /* deprecated */
 #define PCI_CAP_MSIX_SIZEOF    12      /* size of MSIX registers */
 
 /* MSI-X entry's format */
index 609efe8..ac329ee 100644 (file)
@@ -22,6 +22,8 @@
  */
 #define AUOK190X_RESOLUTION_800_600            0
 #define AUOK190X_RESOLUTION_1024_768           1
+#define AUOK190X_RESOLUTION_600_800            4
+#define AUOK190X_RESOLUTION_768_1024           5
 
 /*
  * struct used by auok190x. board specific stuff comes from *board
@@ -98,7 +100,6 @@ struct auok190x_board {
        int gpio_nbusy;
 
        int resolution;
-       int rotation;
        int quirks;
        int fps;
 };
index 71e9a38..5d0259b 100644 (file)
 #include <linux/bitops.h>
 #include <linux/types.h>
 
-/* VESA display monitor timing parameters */
-#define VESA_DMT_HSYNC_LOW             BIT(0)
-#define VESA_DMT_HSYNC_HIGH            BIT(1)
-#define VESA_DMT_VSYNC_LOW             BIT(2)
-#define VESA_DMT_VSYNC_HIGH            BIT(3)
-
-/* display specific flags */
-#define DISPLAY_FLAGS_DE_LOW           BIT(0)  /* data enable flag */
-#define DISPLAY_FLAGS_DE_HIGH          BIT(1)
-#define DISPLAY_FLAGS_PIXDATA_POSEDGE  BIT(2)  /* drive data on pos. edge */
-#define DISPLAY_FLAGS_PIXDATA_NEGEDGE  BIT(3)  /* drive data on neg. edge */
-#define DISPLAY_FLAGS_INTERLACED       BIT(4)
-#define DISPLAY_FLAGS_DOUBLESCAN       BIT(5)
+enum display_flags {
+       DISPLAY_FLAGS_HSYNC_LOW         = BIT(0),
+       DISPLAY_FLAGS_HSYNC_HIGH        = BIT(1),
+       DISPLAY_FLAGS_VSYNC_LOW         = BIT(2),
+       DISPLAY_FLAGS_VSYNC_HIGH        = BIT(3),
+
+       /* data enable flag */
+       DISPLAY_FLAGS_DE_LOW            = BIT(4),
+       DISPLAY_FLAGS_DE_HIGH           = BIT(5),
+       /* drive data on pos. edge */
+       DISPLAY_FLAGS_PIXDATA_POSEDGE   = BIT(6),
+       /* drive data on neg. edge */
+       DISPLAY_FLAGS_PIXDATA_NEGEDGE   = BIT(7),
+       DISPLAY_FLAGS_INTERLACED        = BIT(8),
+       DISPLAY_FLAGS_DOUBLESCAN        = BIT(9),
+};
 
 /*
  * A single signal can be specified via a range of minimal and maximal values
@@ -36,12 +39,6 @@ struct timing_entry {
        u32 max;
 };
 
-enum timing_entry_index {
-       TE_MIN = 0,
-       TE_TYP = 1,
-       TE_MAX = 2,
-};
-
 /*
  * Single "mode" entry. This describes one set of signal timings a display can
  * have in one setting. This struct can later be converted to struct videomode
@@ -72,8 +69,7 @@ struct display_timing {
        struct timing_entry vback_porch;        /* ver. back porch */
        struct timing_entry vsync_len;          /* ver. sync len */
 
-       unsigned int dmt_flags;                 /* VESA DMT flags */
-       unsigned int data_flags;                /* video data flags */
+       enum display_flags flags;               /* display flags */
 };
 
 /*
@@ -89,25 +85,6 @@ struct display_timings {
        struct display_timing **timings;
 };
 
-/* get value specified by index from struct timing_entry */
-static inline u32 display_timing_get_value(const struct timing_entry *te,
-                                          enum timing_entry_index index)
-{
-       switch (index) {
-       case TE_MIN:
-               return te->min;
-               break;
-       case TE_TYP:
-               return te->typ;
-               break;
-       case TE_MAX:
-               return te->max;
-               break;
-       default:
-               return te->typ;
-       }
-}
-
 /* get one entry from struct display_timings */
 static inline struct display_timing *display_timings_get(const struct
                                                         display_timings *disp,
index a421562..3f1049d 100644 (file)
@@ -29,20 +29,30 @@ struct videomode {
        u32 vback_porch;
        u32 vsync_len;
 
-       unsigned int dmt_flags; /* VESA DMT flags */
-       unsigned int data_flags; /* video data flags */
+       enum display_flags flags; /* display flags */
 };
 
 /**
  * videomode_from_timing - convert display timing to videomode
+ * @dt: display_timing structure
+ * @vm: return value
+ *
+ * DESCRIPTION:
+ * This function converts a struct display_timing to a struct videomode.
+ */
+void videomode_from_timing(const struct display_timing *dt,
+                         struct videomode *vm);
+
+/**
+ * videomode_from_timings - convert one display timings entry to videomode
  * @disp: structure with all possible timing entries
  * @vm: return value
  * @index: index into the list of display timings in devicetree
  *
  * DESCRIPTION:
- * This function converts a struct display_timing to a struct videomode.
+ * This function converts one struct display_timing entry to a struct videomode.
  */
-int videomode_from_timing(const struct display_timings *disp,
+int videomode_from_timings(const struct display_timings *disp,
                          struct videomode *vm, unsigned int index);
 
 #endif
index c6bfe01..b2b27c6 100644 (file)
@@ -90,8 +90,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
 int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc);
 /* Bind an PSI pirq to an irq. */
 int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
-                            int pirq, int vector, const char *name,
-                            domid_t domid);
+                            int pirq, const char *name, domid_t domid);
 #endif
 
 /* De-allocates the above mentioned physical interrupt. */
index ab4f109..b3097bd 100644 (file)
@@ -4,3 +4,4 @@
 config_data.h
 config_data.gz
 timeconst.h
+hz.bc
index 7e0962e..9fcb094 100644 (file)
@@ -4596,6 +4596,7 @@ void perf_event_comm(struct task_struct *task)
        struct perf_event_context *ctx;
        int ctxn;
 
+       rcu_read_lock();
        for_each_task_context_nr(ctxn) {
                ctx = task->perf_event_ctxp[ctxn];
                if (!ctx)
@@ -4603,6 +4604,7 @@ void perf_event_comm(struct task_struct *task)
 
                perf_event_enable_on_exec(ctx);
        }
+       rcu_read_unlock();
 
        if (!atomic_read(&nr_comm_events))
                return;
@@ -5331,7 +5333,7 @@ static void sw_perf_event_destroy(struct perf_event *event)
 
 static int perf_swevent_init(struct perf_event *event)
 {
-       int event_id = event->attr.config;
+       u64 event_id = event->attr.config;
 
        if (event->attr.type != PERF_TYPE_SOFTWARE)
                return -ENOENT;
index cc47812..14be27f 100644 (file)
@@ -63,6 +63,7 @@
 DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
 {
 
+       .lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock),
        .clock_base =
        {
                {
@@ -1642,8 +1643,6 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
        struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu);
        int i;
 
-       raw_spin_lock_init(&cpu_base->lock);
-
        for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
                cpu_base->clock_base[i].cpu_base = cpu_base;
                timerqueue_init_head(&cpu_base->clock_base[i].active);
index bddd3d7..ffd4e11 100644 (file)
@@ -55,7 +55,7 @@ struct resource crashk_res = {
        .flags = IORESOURCE_BUSY | IORESOURCE_MEM
 };
 struct resource crashk_low_res = {
-       .name  = "Crash kernel low",
+       .name  = "Crash kernel",
        .start = 0,
        .end   = 0,
        .flags = IORESOURCE_BUSY | IORESOURCE_MEM
@@ -1368,35 +1368,114 @@ static int __init parse_crashkernel_simple(char                *cmdline,
        return 0;
 }
 
+#define SUFFIX_HIGH 0
+#define SUFFIX_LOW  1
+#define SUFFIX_NULL 2
+static __initdata char *suffix_tbl[] = {
+       [SUFFIX_HIGH] = ",high",
+       [SUFFIX_LOW]  = ",low",
+       [SUFFIX_NULL] = NULL,
+};
+
 /*
- * That function is the entry point for command line parsing and should be
- * called from the arch-specific code.
+ * That function parses "suffix"  crashkernel command lines like
+ *
+ *     crashkernel=size,[high|low]
+ *
+ * It returns 0 on success and -EINVAL on failure.
  */
+static int __init parse_crashkernel_suffix(char *cmdline,
+                                          unsigned long long   *crash_size,
+                                          unsigned long long   *crash_base,
+                                          const char *suffix)
+{
+       char *cur = cmdline;
+
+       *crash_size = memparse(cmdline, &cur);
+       if (cmdline == cur) {
+               pr_warn("crashkernel: memory value expected\n");
+               return -EINVAL;
+       }
+
+       /* check with suffix */
+       if (strncmp(cur, suffix, strlen(suffix))) {
+               pr_warn("crashkernel: unrecognized char\n");
+               return -EINVAL;
+       }
+       cur += strlen(suffix);
+       if (*cur != ' ' && *cur != '\0') {
+               pr_warn("crashkernel: unrecognized char\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static __init char *get_last_crashkernel(char *cmdline,
+                            const char *name,
+                            const char *suffix)
+{
+       char *p = cmdline, *ck_cmdline = NULL;
+
+       /* find crashkernel and use the last one if there are more */
+       p = strstr(p, name);
+       while (p) {
+               char *end_p = strchr(p, ' ');
+               char *q;
+
+               if (!end_p)
+                       end_p = p + strlen(p);
+
+               if (!suffix) {
+                       int i;
+
+                       /* skip the one with any known suffix */
+                       for (i = 0; suffix_tbl[i]; i++) {
+                               q = end_p - strlen(suffix_tbl[i]);
+                               if (!strncmp(q, suffix_tbl[i],
+                                            strlen(suffix_tbl[i])))
+                                       goto next;
+                       }
+                       ck_cmdline = p;
+               } else {
+                       q = end_p - strlen(suffix);
+                       if (!strncmp(q, suffix, strlen(suffix)))
+                               ck_cmdline = p;
+               }
+next:
+               p = strstr(p+1, name);
+       }
+
+       if (!ck_cmdline)
+               return NULL;
+
+       return ck_cmdline;
+}
+
 static int __init __parse_crashkernel(char *cmdline,
                             unsigned long long system_ram,
                             unsigned long long *crash_size,
                             unsigned long long *crash_base,
-                               const char *name)
+                            const char *name,
+                            const char *suffix)
 {
-       char    *p = cmdline, *ck_cmdline = NULL;
        char    *first_colon, *first_space;
+       char    *ck_cmdline;
 
        BUG_ON(!crash_size || !crash_base);
        *crash_size = 0;
        *crash_base = 0;
 
-       /* find crashkernel and use the last one if there are more */
-       p = strstr(p, name);
-       while (p) {
-               ck_cmdline = p;
-               p = strstr(p+1, name);
-       }
+       ck_cmdline = get_last_crashkernel(cmdline, name, suffix);
 
        if (!ck_cmdline)
                return -EINVAL;
 
        ck_cmdline += strlen(name);
 
+       if (suffix)
+               return parse_crashkernel_suffix(ck_cmdline, crash_size,
+                               crash_base, suffix);
        /*
         * if the commandline contains a ':', then that's the extended
         * syntax -- if not, it must be the classic syntax
@@ -1413,13 +1492,26 @@ static int __init __parse_crashkernel(char *cmdline,
        return 0;
 }
 
+/*
+ * That function is the entry point for command line parsing and should be
+ * called from the arch-specific code.
+ */
 int __init parse_crashkernel(char *cmdline,
                             unsigned long long system_ram,
                             unsigned long long *crash_size,
                             unsigned long long *crash_base)
 {
        return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
-                                       "crashkernel=");
+                                       "crashkernel=", NULL);
+}
+
+int __init parse_crashkernel_high(char *cmdline,
+                            unsigned long long system_ram,
+                            unsigned long long *crash_size,
+                            unsigned long long *crash_base)
+{
+       return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
+                               "crashkernel=", suffix_tbl[SUFFIX_HIGH]);
 }
 
 int __init parse_crashkernel_low(char *cmdline,
@@ -1428,7 +1520,7 @@ int __init parse_crashkernel_low(char *cmdline,
                             unsigned long long *crash_base)
 {
        return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
-                                       "crashkernel_low=");
+                               "crashkernel=", suffix_tbl[SUFFIX_LOW]);
 }
 
 static void update_vmcoreinfo_note(void)
index e35be53..3fed7f0 100644 (file)
@@ -794,16 +794,16 @@ out:
 }
 
 #ifdef CONFIG_SYSCTL
-/* This should be called with kprobe_mutex locked */
 static void __kprobes optimize_all_kprobes(void)
 {
        struct hlist_head *head;
        struct kprobe *p;
        unsigned int i;
 
+       mutex_lock(&kprobe_mutex);
        /* If optimization is already allowed, just return */
        if (kprobes_allow_optimization)
-               return;
+               goto out;
 
        kprobes_allow_optimization = true;
        for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
@@ -813,18 +813,22 @@ static void __kprobes optimize_all_kprobes(void)
                                optimize_kprobe(p);
        }
        printk(KERN_INFO "Kprobes globally optimized\n");
+out:
+       mutex_unlock(&kprobe_mutex);
 }
 
-/* This should be called with kprobe_mutex locked */
 static void __kprobes unoptimize_all_kprobes(void)
 {
        struct hlist_head *head;
        struct kprobe *p;
        unsigned int i;
 
+       mutex_lock(&kprobe_mutex);
        /* If optimization is already prohibited, just return */
-       if (!kprobes_allow_optimization)
+       if (!kprobes_allow_optimization) {
+               mutex_unlock(&kprobe_mutex);
                return;
+       }
 
        kprobes_allow_optimization = false;
        for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
@@ -834,11 +838,14 @@ static void __kprobes unoptimize_all_kprobes(void)
                                unoptimize_kprobe(p, false);
                }
        }
+       mutex_unlock(&kprobe_mutex);
+
        /* Wait for unoptimizing completion */
        wait_for_kprobe_optimizer();
        printk(KERN_INFO "Kprobes globally unoptimized\n");
 }
 
+static DEFINE_MUTEX(kprobe_sysctl_mutex);
 int sysctl_kprobes_optimization;
 int proc_kprobes_optimization_handler(struct ctl_table *table, int write,
                                      void __user *buffer, size_t *length,
@@ -846,7 +853,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write,
 {
        int ret;
 
-       mutex_lock(&kprobe_mutex);
+       mutex_lock(&kprobe_sysctl_mutex);
        sysctl_kprobes_optimization = kprobes_allow_optimization ? 1 : 0;
        ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
 
@@ -854,7 +861,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write,
                optimize_all_kprobes();
        else
                unoptimize_all_kprobes();
-       mutex_unlock(&kprobe_mutex);
+       mutex_unlock(&kprobe_sysctl_mutex);
 
        return ret;
 }
index 691dc2e..9eb7fed 100644 (file)
@@ -124,12 +124,12 @@ void *kthread_data(struct task_struct *task)
 
 static void __kthread_parkme(struct kthread *self)
 {
-       __set_current_state(TASK_INTERRUPTIBLE);
+       __set_current_state(TASK_PARKED);
        while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) {
                if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags))
                        complete(&self->parked);
                schedule();
-               __set_current_state(TASK_INTERRUPTIBLE);
+               __set_current_state(TASK_PARKED);
        }
        clear_bit(KTHREAD_IS_PARKED, &self->flags);
        __set_current_state(TASK_RUNNING);
@@ -256,8 +256,13 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
 }
 EXPORT_SYMBOL(kthread_create_on_node);
 
-static void __kthread_bind(struct task_struct *p, unsigned int cpu)
+static void __kthread_bind(struct task_struct *p, unsigned int cpu, long state)
 {
+       /* Must have done schedule() in kthread() before we set_task_cpu */
+       if (!wait_task_inactive(p, state)) {
+               WARN_ON(1);
+               return;
+       }
        /* It's safe because the task is inactive. */
        do_set_cpus_allowed(p, cpumask_of(cpu));
        p->flags |= PF_THREAD_BOUND;
@@ -274,12 +279,7 @@ static void __kthread_bind(struct task_struct *p, unsigned int cpu)
  */
 void kthread_bind(struct task_struct *p, unsigned int cpu)
 {
-       /* Must have done schedule() in kthread() before we set_task_cpu */
-       if (!wait_task_inactive(p, TASK_UNINTERRUPTIBLE)) {
-               WARN_ON(1);
-               return;
-       }
-       __kthread_bind(p, cpu);
+       __kthread_bind(p, cpu, TASK_UNINTERRUPTIBLE);
 }
 EXPORT_SYMBOL(kthread_bind);
 
@@ -324,6 +324,22 @@ static struct kthread *task_get_live_kthread(struct task_struct *k)
        return NULL;
 }
 
+static void __kthread_unpark(struct task_struct *k, struct kthread *kthread)
+{
+       clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
+       /*
+        * We clear the IS_PARKED bit here as we don't wait
+        * until the task has left the park code. So if we'd
+        * park before that happens we'd see the IS_PARKED bit
+        * which might be about to be cleared.
+        */
+       if (test_and_clear_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
+               if (test_bit(KTHREAD_IS_PER_CPU, &kthread->flags))
+                       __kthread_bind(k, kthread->cpu, TASK_PARKED);
+               wake_up_state(k, TASK_PARKED);
+       }
+}
+
 /**
  * kthread_unpark - unpark a thread created by kthread_create().
  * @k:         thread created by kthread_create().
@@ -336,20 +352,8 @@ void kthread_unpark(struct task_struct *k)
 {
        struct kthread *kthread = task_get_live_kthread(k);
 
-       if (kthread) {
-               clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
-               /*
-                * We clear the IS_PARKED bit here as we don't wait
-                * until the task has left the park code. So if we'd
-                * park before that happens we'd see the IS_PARKED bit
-                * which might be about to be cleared.
-                */
-               if (test_and_clear_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
-                       if (test_bit(KTHREAD_IS_PER_CPU, &kthread->flags))
-                               __kthread_bind(k, kthread->cpu);
-                       wake_up_process(k);
-               }
-       }
+       if (kthread)
+               __kthread_unpark(k, kthread);
        put_task_struct(k);
 }
 
@@ -407,7 +411,7 @@ int kthread_stop(struct task_struct *k)
        trace_sched_kthread_stop(k);
        if (kthread) {
                set_bit(KTHREAD_SHOULD_STOP, &kthread->flags);
-               clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
+               __kthread_unpark(k, kthread);
                wake_up_process(k);
                wait_for_completion(&kthread->exited);
        }
index 8a0efac..6a3bccb 100644 (file)
@@ -380,6 +380,13 @@ static int verbose(struct lock_class *class)
 unsigned long nr_stack_trace_entries;
 static unsigned long stack_trace[MAX_STACK_TRACE_ENTRIES];
 
+static void print_lockdep_off(const char *bug_msg)
+{
+       printk(KERN_DEBUG "%s\n", bug_msg);
+       printk(KERN_DEBUG "turning off the locking correctness validator.\n");
+       printk(KERN_DEBUG "Please attach the output of /proc/lock_stat to the bug report\n");
+}
+
 static int save_trace(struct stack_trace *trace)
 {
        trace->nr_entries = 0;
@@ -409,8 +416,7 @@ static int save_trace(struct stack_trace *trace)
                if (!debug_locks_off_graph_unlock())
                        return 0;
 
-               printk("BUG: MAX_STACK_TRACE_ENTRIES too low!\n");
-               printk("turning off the locking correctness validator.\n");
+               print_lockdep_off("BUG: MAX_STACK_TRACE_ENTRIES too low!");
                dump_stack();
 
                return 0;
@@ -763,8 +769,7 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
                }
                raw_local_irq_restore(flags);
 
-               printk("BUG: MAX_LOCKDEP_KEYS too low!\n");
-               printk("turning off the locking correctness validator.\n");
+               print_lockdep_off("BUG: MAX_LOCKDEP_KEYS too low!");
                dump_stack();
                return NULL;
        }
@@ -834,8 +839,7 @@ static struct lock_list *alloc_list_entry(void)
                if (!debug_locks_off_graph_unlock())
                        return NULL;
 
-               printk("BUG: MAX_LOCKDEP_ENTRIES too low!\n");
-               printk("turning off the locking correctness validator.\n");
+               print_lockdep_off("BUG: MAX_LOCKDEP_ENTRIES too low!");
                dump_stack();
                return NULL;
        }
@@ -2000,7 +2004,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,
        struct lock_class *class = hlock_class(hlock);
        struct list_head *hash_head = chainhashentry(chain_key);
        struct lock_chain *chain;
-       struct held_lock *hlock_curr, *hlock_next;
+       struct held_lock *hlock_curr;
        int i, j;
 
        /*
@@ -2048,8 +2052,7 @@ cache_hit:
                if (!debug_locks_off_graph_unlock())
                        return 0;
 
-               printk("BUG: MAX_LOCKDEP_CHAINS too low!\n");
-               printk("turning off the locking correctness validator.\n");
+               print_lockdep_off("BUG: MAX_LOCKDEP_CHAINS too low!");
                dump_stack();
                return 0;
        }
@@ -2057,12 +2060,10 @@ cache_hit:
        chain->chain_key = chain_key;
        chain->irq_context = hlock->irq_context;
        /* Find the first held_lock of current chain */
-       hlock_next = hlock;
        for (i = curr->lockdep_depth - 1; i >= 0; i--) {
                hlock_curr = curr->held_locks + i;
-               if (hlock_curr->irq_context != hlock_next->irq_context)
+               if (hlock_curr->irq_context != hlock->irq_context)
                        break;
-               hlock_next = hlock;
        }
        i++;
        chain->depth = curr->lockdep_depth + 1 - i;
@@ -3190,9 +3191,9 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 #endif
        if (unlikely(curr->lockdep_depth >= MAX_LOCK_DEPTH)) {
                debug_locks_off();
-               printk("BUG: MAX_LOCK_DEPTH too low, depth: %i  max: %lu!\n",
+               print_lockdep_off("BUG: MAX_LOCK_DEPTH too low!");
+               printk(KERN_DEBUG "depth: %i  max: %lu!\n",
                       curr->lockdep_depth, MAX_LOCK_DEPTH);
-               printk("turning off the locking correctness validator.\n");
 
                lockdep_print_held_locks(current);
                debug_show_all_locks();
index 52f2301..ad53a66 100644 (file)
 # include <asm/mutex.h>
 #endif
 
+/*
+ * A negative mutex count indicates that waiters are sleeping waiting for the
+ * mutex.
+ */
+#define        MUTEX_SHOW_NO_WAITER(mutex)     (atomic_read(&(mutex)->count) >= 0)
+
 void
 __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
 {
@@ -44,6 +50,9 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
        spin_lock_init(&lock->wait_lock);
        INIT_LIST_HEAD(&lock->wait_list);
        mutex_clear_owner(lock);
+#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
+       lock->spin_mlock = NULL;
+#endif
 
        debug_mutex_init(lock, name, key);
 }
@@ -95,6 +104,124 @@ void __sched mutex_lock(struct mutex *lock)
 EXPORT_SYMBOL(mutex_lock);
 #endif
 
+#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
+/*
+ * In order to avoid a stampede of mutex spinners from acquiring the mutex
+ * more or less simultaneously, the spinners need to acquire a MCS lock
+ * first before spinning on the owner field.
+ *
+ * We don't inline mspin_lock() so that perf can correctly account for the
+ * time spent in this lock function.
+ */
+struct mspin_node {
+       struct mspin_node *next ;
+       int               locked;       /* 1 if lock acquired */
+};
+#define        MLOCK(mutex)    ((struct mspin_node **)&((mutex)->spin_mlock))
+
+static noinline
+void mspin_lock(struct mspin_node **lock, struct mspin_node *node)
+{
+       struct mspin_node *prev;
+
+       /* Init node */
+       node->locked = 0;
+       node->next   = NULL;
+
+       prev = xchg(lock, node);
+       if (likely(prev == NULL)) {
+               /* Lock acquired */
+               node->locked = 1;
+               return;
+       }
+       ACCESS_ONCE(prev->next) = node;
+       smp_wmb();
+       /* Wait until the lock holder passes the lock down */
+       while (!ACCESS_ONCE(node->locked))
+               arch_mutex_cpu_relax();
+}
+
+static void mspin_unlock(struct mspin_node **lock, struct mspin_node *node)
+{
+       struct mspin_node *next = ACCESS_ONCE(node->next);
+
+       if (likely(!next)) {
+               /*
+                * Release the lock by setting it to NULL
+                */
+               if (cmpxchg(lock, node, NULL) == node)
+                       return;
+               /* Wait until the next pointer is set */
+               while (!(next = ACCESS_ONCE(node->next)))
+                       arch_mutex_cpu_relax();
+       }
+       ACCESS_ONCE(next->locked) = 1;
+       smp_wmb();
+}
+
+/*
+ * Mutex spinning code migrated from kernel/sched/core.c
+ */
+
+static inline bool owner_running(struct mutex *lock, struct task_struct *owner)
+{
+       if (lock->owner != owner)
+               return false;
+
+       /*
+        * Ensure we emit the owner->on_cpu, dereference _after_ checking
+        * lock->owner still matches owner, if that fails, owner might
+        * point to free()d memory, if it still matches, the rcu_read_lock()
+        * ensures the memory stays valid.
+        */
+       barrier();
+
+       return owner->on_cpu;
+}
+
+/*
+ * Look out! "owner" is an entirely speculative pointer
+ * access and not reliable.
+ */
+static noinline
+int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner)
+{
+       rcu_read_lock();
+       while (owner_running(lock, owner)) {
+               if (need_resched())
+                       break;
+
+               arch_mutex_cpu_relax();
+       }
+       rcu_read_unlock();
+
+       /*
+        * We break out the loop above on need_resched() and when the
+        * owner changed, which is a sign for heavy contention. Return
+        * success only when lock->owner is NULL.
+        */
+       return lock->owner == NULL;
+}
+
+/*
+ * Initial check for entering the mutex spinning loop
+ */
+static inline int mutex_can_spin_on_owner(struct mutex *lock)
+{
+       int retval = 1;
+
+       rcu_read_lock();
+       if (lock->owner)
+               retval = lock->owner->on_cpu;
+       rcu_read_unlock();
+       /*
+        * if lock->owner is not set, the mutex owner may have just acquired
+        * it and not set the owner yet or the mutex has been released.
+        */
+       return retval;
+}
+#endif
+
 static __used noinline void __sched __mutex_unlock_slowpath(atomic_t *lock_count);
 
 /**
@@ -158,25 +285,39 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
         *
         * We can't do this for DEBUG_MUTEXES because that relies on wait_lock
         * to serialize everything.
+        *
+        * The mutex spinners are queued up using MCS lock so that only one
+        * spinner can compete for the mutex. However, if mutex spinning isn't
+        * going to happen, there is no point in going through the lock/unlock
+        * overhead.
         */
+       if (!mutex_can_spin_on_owner(lock))
+               goto slowpath;
 
        for (;;) {
                struct task_struct *owner;
+               struct mspin_node  node;
 
                /*
                 * If there's an owner, wait for it to either
                 * release the lock or go to sleep.
                 */
+               mspin_lock(MLOCK(lock), &node);
                owner = ACCESS_ONCE(lock->owner);
-               if (owner && !mutex_spin_on_owner(lock, owner))
+               if (owner && !mutex_spin_on_owner(lock, owner)) {
+                       mspin_unlock(MLOCK(lock), &node);
                        break;
+               }
 
-               if (atomic_cmpxchg(&lock->count, 1, 0) == 1) {
+               if ((atomic_read(&lock->count) == 1) &&
+                   (atomic_cmpxchg(&lock->count, 1, 0) == 1)) {
                        lock_acquired(&lock->dep_map, ip);
                        mutex_set_owner(lock);
+                       mspin_unlock(MLOCK(lock), &node);
                        preempt_enable();
                        return 0;
                }
+               mspin_unlock(MLOCK(lock), &node);
 
                /*
                 * When there's no owner, we might have preempted between the
@@ -195,6 +336,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                 */
                arch_mutex_cpu_relax();
        }
+slowpath:
 #endif
        spin_lock_mutex(&lock->wait_lock, flags);
 
@@ -205,7 +347,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
        list_add_tail(&waiter.list, &lock->wait_list);
        waiter.task = task;
 
-       if (atomic_xchg(&lock->count, -1) == 1)
+       if (MUTEX_SHOW_NO_WAITER(lock) && (atomic_xchg(&lock->count, -1) == 1))
                goto done;
 
        lock_contended(&lock->dep_map, ip);
@@ -220,7 +362,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                 * that when we release the lock, we properly wake up the
                 * other waiters:
                 */
-               if (atomic_xchg(&lock->count, -1) == 1)
+               if (MUTEX_SHOW_NO_WAITER(lock) &&
+                  (atomic_xchg(&lock->count, -1) == 1))
                        break;
 
                /*
index 55ad765..1d96dd0 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/spinlock.h>
 #include <linux/timer.h>
 #include <linux/freezer.h>
+#include <linux/stat.h>
 
 #include "rtmutex.h"
 
@@ -366,8 +367,8 @@ static ssize_t sysfs_test_status(struct device *dev, struct device_attribute *at
        return curr - buf;
 }
 
-static DEVICE_ATTR(status, 0400, sysfs_test_status, NULL);
-static DEVICE_ATTR(command, 0200, NULL, sysfs_test_command);
+static DEVICE_ATTR(status, S_IRUSR, sysfs_test_status, NULL);
+static DEVICE_ATTR(command, S_IWUSR, NULL, sysfs_test_command);
 
 static struct bus_type rttest_subsys = {
        .name = "rttest",
index 67d0465..4205354 100644 (file)
@@ -2999,51 +2999,6 @@ void __sched schedule_preempt_disabled(void)
        preempt_disable();
 }
 
-#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
-
-static inline bool owner_running(struct mutex *lock, struct task_struct *owner)
-{
-       if (lock->owner != owner)
-               return false;
-
-       /*
-        * Ensure we emit the owner->on_cpu, dereference _after_ checking
-        * lock->owner still matches owner, if that fails, owner might
-        * point to free()d memory, if it still matches, the rcu_read_lock()
-        * ensures the memory stays valid.
-        */
-       barrier();
-
-       return owner->on_cpu;
-}
-
-/*
- * Look out! "owner" is an entirely speculative pointer
- * access and not reliable.
- */
-int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner)
-{
-       if (!sched_feat(OWNER_SPIN))
-               return 0;
-
-       rcu_read_lock();
-       while (owner_running(lock, owner)) {
-               if (need_resched())
-                       break;
-
-               arch_mutex_cpu_relax();
-       }
-       rcu_read_unlock();
-
-       /*
-        * We break out the loop above on need_resched() and when the
-        * owner changed, which is a sign for heavy contention. Return
-        * success only when lock->owner is NULL.
-        */
-       return lock->owner == NULL;
-}
-#endif
-
 #ifdef CONFIG_PREEMPT
 /*
  * this is the entry point to schedule() from in-kernel preemption
index 1ad1d2b..99399f8 100644 (file)
@@ -46,13 +46,6 @@ SCHED_FEAT(DOUBLE_TICK, false)
 SCHED_FEAT(LB_BIAS, true)
 
 /*
- * Spin-wait on mutex acquisition when the mutex owner is running on
- * another cpu -- assumes that when the owner is running, it will soon
- * release the lock. Decreases scheduling overhead.
- */
-SCHED_FEAT(OWNER_SPIN, true)
-
-/*
  * Decrement CPU power based on time not spent running tasks
  */
 SCHED_FEAT(NONTASK_POWER, true)
index dd72567..598dc06 100644 (file)
@@ -2948,7 +2948,7 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)
 
 static int do_tkill(pid_t tgid, pid_t pid, int sig)
 {
-       struct siginfo info;
+       struct siginfo info = {};
 
        info.si_signo = sig;
        info.si_errno = 0;
index 8eaed9a..02fc5c9 100644 (file)
@@ -185,8 +185,18 @@ __smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
        }
        get_task_struct(tsk);
        *per_cpu_ptr(ht->store, cpu) = tsk;
-       if (ht->create)
-               ht->create(cpu);
+       if (ht->create) {
+               /*
+                * Make sure that the task has actually scheduled out
+                * into park position, before calling the create
+                * callback. At least the migration thread callback
+                * requires that the task is off the runqueue.
+                */
+               if (!wait_task_inactive(tsk, TASK_PARKED))
+                       WARN_ON(1);
+               else
+                       ht->create(cpu);
+       }
        return 0;
 }
 
index 9e5b8c2..5a0f781 100644 (file)
@@ -739,12 +739,6 @@ static void blk_add_trace_rq_complete(void *ignore,
                                      struct request_queue *q,
                                      struct request *rq)
 {
-       struct blk_trace *bt = q->blk_trace;
-
-       /* if control ever passes through here, it's a request based driver */
-       if (unlikely(bt && !bt->rq_based))
-               bt->rq_based = true;
-
        blk_add_trace_rq(q, rq, BLK_TA_COMPLETE);
 }
 
@@ -780,24 +774,10 @@ static void blk_add_trace_bio_bounce(void *ignore,
        blk_add_trace_bio(q, bio, BLK_TA_BOUNCE, 0);
 }
 
-static void blk_add_trace_bio_complete(void *ignore, struct bio *bio, int error)
+static void blk_add_trace_bio_complete(void *ignore,
+                                      struct request_queue *q, struct bio *bio,
+                                      int error)
 {
-       struct request_queue *q;
-       struct blk_trace *bt;
-
-       if (!bio->bi_bdev)
-               return;
-
-       q = bdev_get_queue(bio->bi_bdev);
-       bt = q->blk_trace;
-
-       /*
-        * Request based drivers will generate both rq and bio completions.
-        * Ignore bio ones.
-        */
-       if (likely(!bt) || bt->rq_based)
-               return;
-
        blk_add_trace_bio(q, bio, BLK_TA_COMPLETE, error);
 }
 
index a54f26f..e134d8f 100644 (file)
@@ -25,7 +25,8 @@
 
 static struct kmem_cache *user_ns_cachep __read_mostly;
 
-static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
+static bool new_idmap_permitted(const struct file *file,
+                               struct user_namespace *ns, int cap_setid,
                                struct uid_gid_map *map);
 
 static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
@@ -612,10 +613,10 @@ static ssize_t map_write(struct file *file, const char __user *buf,
        if (map->nr_extents != 0)
                goto out;
 
-       /* Require the appropriate privilege CAP_SETUID or CAP_SETGID
-        * over the user namespace in order to set the id mapping.
+       /*
+        * Adjusting namespace settings requires capabilities on the target.
         */
-       if (cap_valid(cap_setid) && !ns_capable(ns, cap_setid))
+       if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN))
                goto out;
 
        /* Get a buffer */
@@ -700,7 +701,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
 
        ret = -EPERM;
        /* Validate the user is allowed to use user id's mapped to. */
-       if (!new_idmap_permitted(ns, cap_setid, &new_map))
+       if (!new_idmap_permitted(file, ns, cap_setid, &new_map))
                goto out;
 
        /* Map the lower ids from the parent user namespace to the
@@ -787,7 +788,8 @@ ssize_t proc_projid_map_write(struct file *file, const char __user *buf, size_t
                         &ns->projid_map, &ns->parent->projid_map);
 }
 
-static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
+static bool new_idmap_permitted(const struct file *file, 
+                               struct user_namespace *ns, int cap_setid,
                                struct uid_gid_map *new_map)
 {
        /* Allow mapping to your own filesystem ids */
@@ -795,12 +797,12 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
                u32 id = new_map->extent[0].lower_first;
                if (cap_setid == CAP_SETUID) {
                        kuid_t uid = make_kuid(ns->parent, id);
-                       if (uid_eq(uid, current_fsuid()))
+                       if (uid_eq(uid, file->f_cred->fsuid))
                                return true;
                }
                else if (cap_setid == CAP_SETGID) {
                        kgid_t gid = make_kgid(ns->parent, id);
-                       if (gid_eq(gid, current_fsgid()))
+                       if (gid_eq(gid, file->f_cred->fsgid))
                                return true;
                }
        }
@@ -811,8 +813,10 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
 
        /* Allow the specified ids if we have the appropriate capability
         * (CAP_SETUID or CAP_SETGID) over the parent user namespace.
+        * And the opener of the id file also had the approprpiate capability.
         */
-       if (ns_capable(ns->parent, cap_setid))
+       if (ns_capable(ns->parent, cap_setid) &&
+           file_ns_capable(file, ns->parent, cap_setid))
                return true;
 
        return false;
index 3958dc4..fe01d41 100644 (file)
@@ -404,4 +404,7 @@ config OID_REGISTRY
        help
          Enable fast lookup object identifier registry.
 
+config UCS2_STRING
+        tristate
+
 endmenu
index d7946ff..6e2cc56 100644 (file)
@@ -174,3 +174,5 @@ quiet_cmd_build_OID_registry = GEN     $@
       cmd_build_OID_registry = perl $(srctree)/$(src)/build_OID_registry $< $@
 
 clean-files    += oid_registry_data.c
+
+obj-$(CONFIG_UCS2_STRING) += ucs2_string.o
index bfe02b8..d23762e 100644 (file)
@@ -105,9 +105,9 @@ setup_io_tlb_npages(char *str)
        if (!strcmp(str, "force"))
                swiotlb_force = 1;
 
-       return 1;
+       return 0;
 }
-__setup("swiotlb=", setup_io_tlb_npages);
+early_param("swiotlb", setup_io_tlb_npages);
 /* make io_tlb_overflow tunable too? */
 
 unsigned long swiotlb_nr_tbl(void)
@@ -115,6 +115,18 @@ unsigned long swiotlb_nr_tbl(void)
        return io_tlb_nslabs;
 }
 EXPORT_SYMBOL_GPL(swiotlb_nr_tbl);
+
+/* default to 64MB */
+#define IO_TLB_DEFAULT_SIZE (64UL<<20)
+unsigned long swiotlb_size_or_default(void)
+{
+       unsigned long size;
+
+       size = io_tlb_nslabs << IO_TLB_SHIFT;
+
+       return size ? size : (IO_TLB_DEFAULT_SIZE);
+}
+
 /* Note that this doesn't work with highmem page */
 static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
                                      volatile void *address)
@@ -188,8 +200,7 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
 void  __init
 swiotlb_init(int verbose)
 {
-       /* default to 64MB */
-       size_t default_size = 64UL<<20;
+       size_t default_size = IO_TLB_DEFAULT_SIZE;
        unsigned char *vstart;
        unsigned long bytes;
 
diff --git a/lib/ucs2_string.c b/lib/ucs2_string.c
new file mode 100644 (file)
index 0000000..6f500ef
--- /dev/null
@@ -0,0 +1,51 @@
+#include <linux/ucs2_string.h>
+#include <linux/module.h>
+
+/* Return the number of unicode characters in data */
+unsigned long
+ucs2_strnlen(const ucs2_char_t *s, size_t maxlength)
+{
+        unsigned long length = 0;
+
+        while (*s++ != 0 && length < maxlength)
+                length++;
+        return length;
+}
+EXPORT_SYMBOL(ucs2_strnlen);
+
+unsigned long
+ucs2_strlen(const ucs2_char_t *s)
+{
+        return ucs2_strnlen(s, ~0UL);
+}
+EXPORT_SYMBOL(ucs2_strlen);
+
+/*
+ * Return the number of bytes is the length of this string
+ * Note: this is NOT the same as the number of unicode characters
+ */
+unsigned long
+ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength)
+{
+        return ucs2_strnlen(data, maxlength/sizeof(ucs2_char_t)) * sizeof(ucs2_char_t);
+}
+EXPORT_SYMBOL(ucs2_strsize);
+
+int
+ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len)
+{
+        while (1) {
+                if (len == 0)
+                        return 0;
+                if (*a < *b)
+                        return -1;
+                if (*a > *b)
+                        return 1;
+                if (*a == 0) /* implies *b == 0 */
+                        return 0;
+                a++;
+                b++;
+                len--;
+        }
+}
+EXPORT_SYMBOL(ucs2_strncmp);
index ca9a7c6..1a12f5b 100644 (file)
@@ -2961,7 +2961,17 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
                        break;
                }
 
-               if (absent ||
+               /*
+                * We need call hugetlb_fault for both hugepages under migration
+                * (in which case hugetlb_fault waits for the migration,) and
+                * hwpoisoned hugepages (in which case we need to prevent the
+                * caller from accessing to them.) In order to do this, we use
+                * here is_swap_pte instead of is_hugetlb_entry_migration and
+                * is_hugetlb_entry_hwpoisoned. This is because it simply covers
+                * both cases, and because we can't follow correct pages
+                * directly from any kind of swap entries.
+                */
+               if (absent || is_swap_pte(huge_ptep_get(pte)) ||
                    ((flags & FOLL_WRITE) && !pte_write(huge_ptep_get(pte)))) {
                        int ret;
 
index 13cbc42..ba94dec 100644 (file)
@@ -2393,6 +2393,53 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
 }
 EXPORT_SYMBOL(remap_pfn_range);
 
+/**
+ * vm_iomap_memory - remap memory to userspace
+ * @vma: user vma to map to
+ * @start: start of area
+ * @len: size of area
+ *
+ * This is a simplified io_remap_pfn_range() for common driver use. The
+ * driver just needs to give us the physical memory range to be mapped,
+ * we'll figure out the rest from the vma information.
+ *
+ * NOTE! Some drivers might want to tweak vma->vm_page_prot first to get
+ * whatever write-combining details or similar.
+ */
+int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len)
+{
+       unsigned long vm_len, pfn, pages;
+
+       /* Check that the physical memory area passed in looks valid */
+       if (start + len < start)
+               return -EINVAL;
+       /*
+        * You *really* shouldn't map things that aren't page-aligned,
+        * but we've historically allowed it because IO memory might
+        * just have smaller alignment.
+        */
+       len += start & ~PAGE_MASK;
+       pfn = start >> PAGE_SHIFT;
+       pages = (len + ~PAGE_MASK) >> PAGE_SHIFT;
+       if (pfn + pages < pfn)
+               return -EINVAL;
+
+       /* We start the mapping 'vm_pgoff' pages into the area */
+       if (vma->vm_pgoff > pages)
+               return -EINVAL;
+       pfn += vma->vm_pgoff;
+       pages -= vma->vm_pgoff;
+
+       /* Can we fit all of the mapping? */
+       vm_len = vma->vm_end - vma->vm_start;
+       if (vm_len >> PAGE_SHIFT > pages)
+               return -EINVAL;
+
+       /* Ok, let it rip */
+       return io_remap_pfn_range(vma, vma->vm_start, pfn, vm_len, vma->vm_page_prot);
+}
+EXPORT_SYMBOL(vm_iomap_memory);
+
 static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
                                     unsigned long addr, unsigned long end,
                                     pte_fn_t fn, void *data)
index 2f3ea74..e001768 100644 (file)
@@ -1838,6 +1838,16 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
 }
 EXPORT_SYMBOL(remap_pfn_range);
 
+int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len)
+{
+       unsigned long pfn = start >> PAGE_SHIFT;
+       unsigned long vm_len = vma->vm_end - vma->vm_start;
+
+       pfn += vma->vm_pgoff;
+       return io_remap_pfn_range(vma, vma->vm_start, pfn, vm_len, vma->vm_page_prot);
+}
+EXPORT_SYMBOL(vm_iomap_memory);
+
 int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
                        unsigned long pgoff)
 {
index 8fcced7..7ff1536 100644 (file)
@@ -1397,6 +1397,7 @@ void split_page(struct page *page, unsigned int order)
        for (i = 1; i < (1 << order); i++)
                set_page_refcounted(page + i);
 }
+EXPORT_SYMBOL_GPL(split_page);
 
 static int __isolate_free_page(struct page *page, unsigned int order)
 {
index 88c5fed..669fba3 100644 (file)
@@ -3188,9 +3188,9 @@ int kswapd_run(int nid)
        if (IS_ERR(pgdat->kswapd)) {
                /* failure at boot is fatal */
                BUG_ON(system_state == SYSTEM_BOOTING);
-               pgdat->kswapd = NULL;
                pr_err("Failed to start kswapd on node %d\n", nid);
                ret = PTR_ERR(pgdat->kswapd);
+               pgdat->kswapd = NULL;
        }
        return ret;
 }
index a4cc322..e085bcc 100644 (file)
@@ -870,8 +870,12 @@ void mrp_uninit_applicant(struct net_device *dev, struct mrp_application *appl)
         * all pending messages before the applicant is gone.
         */
        del_timer_sync(&app->join_timer);
+
+       spin_lock(&app->lock);
        mrp_mad_event(app, MRP_EVENT_TX);
        mrp_pdu_queue(app);
+       spin_unlock(&app->lock);
+
        mrp_queue_xmit(app);
 
        dev_mc_del(dev, appl->group_address);
index 0488d70..fa563e4 100644 (file)
@@ -169,7 +169,7 @@ void batadv_mesh_free(struct net_device *soft_iface)
        atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE);
 }
 
-int batadv_is_my_mac(const uint8_t *addr)
+int batadv_is_my_mac(struct batadv_priv *bat_priv, const uint8_t *addr)
 {
        const struct batadv_hard_iface *hard_iface;
 
@@ -178,6 +178,9 @@ int batadv_is_my_mac(const uint8_t *addr)
                if (hard_iface->if_status != BATADV_IF_ACTIVE)
                        continue;
 
+               if (hard_iface->soft_iface != bat_priv->soft_iface)
+                       continue;
+
                if (batadv_compare_eth(hard_iface->net_dev->dev_addr, addr)) {
                        rcu_read_unlock();
                        return 1;
index ced08b9..d40910d 100644 (file)
@@ -162,7 +162,7 @@ extern struct workqueue_struct *batadv_event_workqueue;
 
 int batadv_mesh_init(struct net_device *soft_iface);
 void batadv_mesh_free(struct net_device *soft_iface);
-int batadv_is_my_mac(const uint8_t *addr);
+int batadv_is_my_mac(struct batadv_priv *bat_priv, const uint8_t *addr);
 struct batadv_hard_iface *
 batadv_seq_print_text_primary_if_get(struct seq_file *seq);
 int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
index 5ee21ce..319f290 100644 (file)
@@ -402,7 +402,7 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
                goto out;
 
        /* not for me */
-       if (!batadv_is_my_mac(ethhdr->h_dest))
+       if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest))
                goto out;
 
        icmp_packet = (struct batadv_icmp_packet_rr *)skb->data;
@@ -416,7 +416,7 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
        }
 
        /* packet for me */
-       if (batadv_is_my_mac(icmp_packet->dst))
+       if (batadv_is_my_mac(bat_priv, icmp_packet->dst))
                return batadv_recv_my_icmp_packet(bat_priv, skb, hdr_size);
 
        /* TTL exceeded */
@@ -548,7 +548,8 @@ batadv_find_ifalter_router(struct batadv_orig_node *primary_orig,
        return router;
 }
 
-static int batadv_check_unicast_packet(struct sk_buff *skb, int hdr_size)
+static int batadv_check_unicast_packet(struct batadv_priv *bat_priv,
+                                      struct sk_buff *skb, int hdr_size)
 {
        struct ethhdr *ethhdr;
 
@@ -567,7 +568,7 @@ static int batadv_check_unicast_packet(struct sk_buff *skb, int hdr_size)
                return -1;
 
        /* not for me */
-       if (!batadv_is_my_mac(ethhdr->h_dest))
+       if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest))
                return -1;
 
        return 0;
@@ -582,7 +583,7 @@ int batadv_recv_tt_query(struct sk_buff *skb, struct batadv_hard_iface *recv_if)
        char tt_flag;
        size_t packet_size;
 
-       if (batadv_check_unicast_packet(skb, hdr_size) < 0)
+       if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0)
                return NET_RX_DROP;
 
        /* I could need to modify it */
@@ -614,7 +615,7 @@ int batadv_recv_tt_query(struct sk_buff *skb, struct batadv_hard_iface *recv_if)
        case BATADV_TT_RESPONSE:
                batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX);
 
-               if (batadv_is_my_mac(tt_query->dst)) {
+               if (batadv_is_my_mac(bat_priv, tt_query->dst)) {
                        /* packet needs to be linearized to access the TT
                         * changes
                         */
@@ -657,14 +658,15 @@ int batadv_recv_roam_adv(struct sk_buff *skb, struct batadv_hard_iface *recv_if)
        struct batadv_roam_adv_packet *roam_adv_packet;
        struct batadv_orig_node *orig_node;
 
-       if (batadv_check_unicast_packet(skb, sizeof(*roam_adv_packet)) < 0)
+       if (batadv_check_unicast_packet(bat_priv, skb,
+                                       sizeof(*roam_adv_packet)) < 0)
                goto out;
 
        batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX);
 
        roam_adv_packet = (struct batadv_roam_adv_packet *)skb->data;
 
-       if (!batadv_is_my_mac(roam_adv_packet->dst))
+       if (!batadv_is_my_mac(bat_priv, roam_adv_packet->dst))
                return batadv_route_unicast_packet(skb, recv_if);
 
        /* check if it is a backbone gateway. we don't accept
@@ -967,7 +969,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
         * last time) the packet had an updated information or not
         */
        curr_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn);
-       if (!batadv_is_my_mac(unicast_packet->dest)) {
+       if (!batadv_is_my_mac(bat_priv, unicast_packet->dest)) {
                orig_node = batadv_orig_hash_find(bat_priv,
                                                  unicast_packet->dest);
                /* if it is not possible to find the orig_node representing the
@@ -1044,14 +1046,14 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
        if (is4addr)
                hdr_size = sizeof(*unicast_4addr_packet);
 
-       if (batadv_check_unicast_packet(skb, hdr_size) < 0)
+       if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0)
                return NET_RX_DROP;
 
        if (!batadv_check_unicast_ttvn(bat_priv, skb))
                return NET_RX_DROP;
 
        /* packet for me */
-       if (batadv_is_my_mac(unicast_packet->dest)) {
+       if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) {
                if (is4addr) {
                        batadv_dat_inc_counter(bat_priv,
                                               unicast_4addr_packet->subtype);
@@ -1088,7 +1090,7 @@ int batadv_recv_ucast_frag_packet(struct sk_buff *skb,
        struct sk_buff *new_skb = NULL;
        int ret;
 
-       if (batadv_check_unicast_packet(skb, hdr_size) < 0)
+       if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0)
                return NET_RX_DROP;
 
        if (!batadv_check_unicast_ttvn(bat_priv, skb))
@@ -1097,7 +1099,7 @@ int batadv_recv_ucast_frag_packet(struct sk_buff *skb,
        unicast_packet = (struct batadv_unicast_frag_packet *)skb->data;
 
        /* packet for me */
-       if (batadv_is_my_mac(unicast_packet->dest)) {
+       if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) {
                ret = batadv_frag_reassemble_skb(skb, bat_priv, &new_skb);
 
                if (ret == NET_RX_DROP)
@@ -1151,13 +1153,13 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
                goto out;
 
        /* ignore broadcasts sent by myself */
-       if (batadv_is_my_mac(ethhdr->h_source))
+       if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
                goto out;
 
        bcast_packet = (struct batadv_bcast_packet *)skb->data;
 
        /* ignore broadcasts originated by myself */
-       if (batadv_is_my_mac(bcast_packet->orig))
+       if (batadv_is_my_mac(bat_priv, bcast_packet->orig))
                goto out;
 
        if (bcast_packet->header.ttl < 2)
@@ -1243,14 +1245,14 @@ int batadv_recv_vis_packet(struct sk_buff *skb,
        ethhdr = (struct ethhdr *)skb_mac_header(skb);
 
        /* not for me */
-       if (!batadv_is_my_mac(ethhdr->h_dest))
+       if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest))
                return NET_RX_DROP;
 
        /* ignore own packets */
-       if (batadv_is_my_mac(vis_packet->vis_orig))
+       if (batadv_is_my_mac(bat_priv, vis_packet->vis_orig))
                return NET_RX_DROP;
 
-       if (batadv_is_my_mac(vis_packet->sender_orig))
+       if (batadv_is_my_mac(bat_priv, vis_packet->sender_orig))
                return NET_RX_DROP;
 
        switch (vis_packet->vis_type) {
index 98a66a0..7abee19 100644 (file)
@@ -1953,7 +1953,7 @@ out:
 bool batadv_send_tt_response(struct batadv_priv *bat_priv,
                             struct batadv_tt_query_packet *tt_request)
 {
-       if (batadv_is_my_mac(tt_request->dst)) {
+       if (batadv_is_my_mac(bat_priv, tt_request->dst)) {
                /* don't answer backbone gws! */
                if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_request->src))
                        return true;
index c053244..6a1e646 100644 (file)
@@ -477,7 +477,7 @@ void batadv_receive_client_update_packet(struct batadv_priv *bat_priv,
 
        /* Are we the target for this VIS packet? */
        if (vis_server == BATADV_VIS_TYPE_SERVER_SYNC   &&
-           batadv_is_my_mac(vis_packet->target_orig))
+           batadv_is_my_mac(bat_priv, vis_packet->target_orig))
                are_target = 1;
 
        spin_lock_bh(&bat_priv->vis.hash_lock);
@@ -496,7 +496,7 @@ void batadv_receive_client_update_packet(struct batadv_priv *bat_priv,
                batadv_send_list_add(bat_priv, info);
 
                /* ... we're not the recipient (and thus need to forward). */
-       } else if (!batadv_is_my_mac(packet->target_orig)) {
+       } else if (!batadv_is_my_mac(bat_priv, packet->target_orig)) {
                batadv_send_list_add(bat_priv, info);
        }
 
index ef1b914..459dab2 100644 (file)
@@ -67,7 +67,8 @@ void br_port_carrier_check(struct net_bridge_port *p)
        struct net_device *dev = p->dev;
        struct net_bridge *br = p->br;
 
-       if (netif_running(dev) && netif_oper_up(dev))
+       if (!(p->flags & BR_ADMIN_COST) &&
+           netif_running(dev) && netif_oper_up(dev))
                p->path_cost = port_cost(dev);
 
        if (!netif_running(br->dev))
index 3cbf5be..d2c043a 100644 (file)
@@ -156,6 +156,7 @@ struct net_bridge_port
 #define BR_BPDU_GUARD           0x00000002
 #define BR_ROOT_BLOCK          0x00000004
 #define BR_MULTICAST_FAST_LEAVE        0x00000008
+#define BR_ADMIN_COST          0x00000010
 
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
        u32                             multicast_startup_queries_sent;
index 0bdb4eb..d45e760 100644 (file)
@@ -288,6 +288,7 @@ int br_stp_set_path_cost(struct net_bridge_port *p, unsigned long path_cost)
            path_cost > BR_MAX_PATH_COST)
                return -ERANGE;
 
+       p->flags |= BR_ADMIN_COST;
        p->path_cost = path_cost;
        br_configuration_update(p->br);
        br_port_state_selection(p->br);
index e7d68ed..b24ab0e 100644 (file)
@@ -2148,6 +2148,9 @@ static void skb_warn_bad_offload(const struct sk_buff *skb)
        struct net_device *dev = skb->dev;
        const char *driver = "";
 
+       if (!net_ratelimit())
+               return;
+
        if (dev && dev->dev.parent)
                driver = dev_driver_string(dev->dev.parent);
 
index 3b4f0cd..4cfe34d 100644 (file)
@@ -139,8 +139,6 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
 
        /* skb is pure payload to encrypt */
 
-       err = -ENOMEM;
-
        esp = x->data;
        aead = esp->aead;
        alen = crypto_aead_authsize(aead);
@@ -176,8 +174,10 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
        }
 
        tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen);
-       if (!tmp)
+       if (!tmp) {
+               err = -ENOMEM;
                goto error;
+       }
 
        seqhi = esp_tmp_seqhi(tmp);
        iv = esp_tmp_iv(aead, tmp, seqhilen);
index a6445b8..52c273e 100644 (file)
@@ -248,8 +248,7 @@ static void ip_expire(unsigned long arg)
                if (!head->dev)
                        goto out_rcu_unlock;
 
-               /* skb dst is stale, drop it, and perform route lookup again */
-               skb_dst_drop(head);
+               /* skb has no dst, perform route lookup again */
                iph = ip_hdr(head);
                err = ip_route_input_noref(head, iph->daddr, iph->saddr,
                                           iph->tos, head->dev);
@@ -523,9 +522,16 @@ found:
                qp->q.max_size = skb->len + ihl;
 
        if (qp->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
-           qp->q.meat == qp->q.len)
-               return ip_frag_reasm(qp, prev, dev);
+           qp->q.meat == qp->q.len) {
+               unsigned long orefdst = skb->_skb_refdst;
 
+               skb->_skb_refdst = 0UL;
+               err = ip_frag_reasm(qp, prev, dev);
+               skb->_skb_refdst = orefdst;
+               return err;
+       }
+
+       skb_dst_drop(skb);
        inet_frag_lru_move(&qp->q);
        return -EINPROGRESS;
 
index c301300..c49dcd0 100644 (file)
@@ -66,6 +66,12 @@ static bool rpfilter_lookup_reverse(struct flowi4 *fl4,
        return dev_match;
 }
 
+static bool rpfilter_is_local(const struct sk_buff *skb)
+{
+       const struct rtable *rt = skb_rtable(skb);
+       return rt && (rt->rt_flags & RTCF_LOCAL);
+}
+
 static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_rpfilter_info *info;
@@ -76,7 +82,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
        info = par->matchinfo;
        invert = info->flags & XT_RPFILTER_INVERT;
 
-       if (par->in->flags & IFF_LOOPBACK)
+       if (rpfilter_is_local(skb))
                return true ^ invert;
 
        iph = ip_hdr(skb);
index ef54377..397e0f6 100644 (file)
@@ -349,8 +349,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
         * hasn't changed since we received the original syn, but I see
         * no easy way to do this.
         */
-       flowi4_init_output(&fl4, 0, sk->sk_mark, RT_CONN_FLAGS(sk),
-                          RT_SCOPE_UNIVERSE, IPPROTO_TCP,
+       flowi4_init_output(&fl4, sk->sk_bound_dev_if, sk->sk_mark,
+                          RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, IPPROTO_TCP,
                           inet_sk_flowi_flags(sk),
                           (opt && opt->srr) ? opt->faddr : ireq->rmt_addr,
                           ireq->loc_addr, th->source, th->dest);
index 3bd55ba..13b9c08 100644 (file)
@@ -113,6 +113,7 @@ int sysctl_tcp_early_retrans __read_mostly = 2;
 #define FLAG_DSACKING_ACK      0x800 /* SACK blocks contained D-SACK info */
 #define FLAG_NONHEAD_RETRANS_ACKED     0x1000 /* Non-head rexmitted data was ACKed */
 #define FLAG_SACK_RENEGING     0x2000 /* snd_una advanced to a sacked seq */
+#define FLAG_UPDATE_TS_RECENT  0x4000 /* tcp_replace_ts_recent() */
 
 #define FLAG_ACKED             (FLAG_DATA_ACKED|FLAG_SYN_ACKED)
 #define FLAG_NOT_DUP           (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED)
@@ -3564,6 +3565,27 @@ static void tcp_send_challenge_ack(struct sock *sk)
        }
 }
 
+static void tcp_store_ts_recent(struct tcp_sock *tp)
+{
+       tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
+       tp->rx_opt.ts_recent_stamp = get_seconds();
+}
+
+static void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
+{
+       if (tp->rx_opt.saw_tstamp && !after(seq, tp->rcv_wup)) {
+               /* PAWS bug workaround wrt. ACK frames, the PAWS discard
+                * extra check below makes sure this can only happen
+                * for pure ACK frames.  -DaveM
+                *
+                * Not only, also it occurs for expired timestamps.
+                */
+
+               if (tcp_paws_check(&tp->rx_opt, 0))
+                       tcp_store_ts_recent(tp);
+       }
+}
+
 /* This routine deals with incoming acks, but not outgoing ones. */
 static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 {
@@ -3607,6 +3629,12 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
        prior_fackets = tp->fackets_out;
        prior_in_flight = tcp_packets_in_flight(tp);
 
+       /* ts_recent update must be made after we are sure that the packet
+        * is in window.
+        */
+       if (flag & FLAG_UPDATE_TS_RECENT)
+               tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
+
        if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
                /* Window is constant, pure forward advance.
                 * No more checks are required.
@@ -3927,27 +3955,6 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
 EXPORT_SYMBOL(tcp_parse_md5sig_option);
 #endif
 
-static inline void tcp_store_ts_recent(struct tcp_sock *tp)
-{
-       tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
-       tp->rx_opt.ts_recent_stamp = get_seconds();
-}
-
-static inline void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
-{
-       if (tp->rx_opt.saw_tstamp && !after(seq, tp->rcv_wup)) {
-               /* PAWS bug workaround wrt. ACK frames, the PAWS discard
-                * extra check below makes sure this can only happen
-                * for pure ACK frames.  -DaveM
-                *
-                * Not only, also it occurs for expired timestamps.
-                */
-
-               if (tcp_paws_check(&tp->rx_opt, 0))
-                       tcp_store_ts_recent(tp);
-       }
-}
-
 /* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM
  *
  * It is not fatal. If this ACK does _not_ change critical state (seqs, window)
@@ -5543,14 +5550,9 @@ slow_path:
                return 0;
 
 step5:
-       if (tcp_ack(sk, skb, FLAG_SLOWPATH) < 0)
+       if (tcp_ack(sk, skb, FLAG_SLOWPATH | FLAG_UPDATE_TS_RECENT) < 0)
                goto discard;
 
-       /* ts_recent update must be made after we are sure that the packet
-        * is in window.
-        */
-       tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
-
        tcp_rcv_rtt_measure_ts(sk, skb);
 
        /* Process urgent data. */
@@ -5986,7 +5988,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 
        /* step 5: check the ACK field */
        if (true) {
-               int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0;
+               int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH |
+                                                 FLAG_UPDATE_TS_RECENT) > 0;
 
                switch (sk->sk_state) {
                case TCP_SYN_RECV:
@@ -6137,11 +6140,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                }
        }
 
-       /* ts_recent update must be made after we are sure that the packet
-        * is in window.
-        */
-       tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
-
        /* step 6: check the URG bit */
        tcp_urg(sk, skb, th);
 
index b44cf81..509912a 100644 (file)
@@ -2388,8 +2388,12 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
         */
        TCP_SKB_CB(skb)->when = tcp_time_stamp;
 
-       /* make sure skb->data is aligned on arches that require it */
-       if (unlikely(NET_IP_ALIGN && ((unsigned long)skb->data & 3))) {
+       /* make sure skb->data is aligned on arches that require it
+        * and check if ack-trimming & collapsing extended the headroom
+        * beyond what csum_start can cover.
+        */
+       if (unlikely((NET_IP_ALIGN && ((unsigned long)skb->data & 3)) ||
+                    skb_headroom(skb) >= 0xFFFF)) {
                struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER,
                                                   GFP_ATOMIC);
                return nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
index a459c4f..dae802c 100644 (file)
@@ -168,8 +168,6 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
 static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
                               struct net_device *dev);
 
-static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
-
 static struct ipv6_devconf ipv6_devconf __read_mostly = {
        .forwarding             = 0,
        .hop_limit              = IPV6_DEFAULT_HOPLIMIT,
@@ -837,7 +835,7 @@ out2:
        rcu_read_unlock_bh();
 
        if (likely(err == 0))
-               atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);
+               inet6addr_notifier_call_chain(NETDEV_UP, ifa);
        else {
                kfree(ifa);
                ifa = ERR_PTR(err);
@@ -927,7 +925,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 
        ipv6_ifa_notify(RTM_DELADDR, ifp);
 
-       atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifp);
+       inet6addr_notifier_call_chain(NETDEV_DOWN, ifp);
 
        /*
         * Purge or update corresponding prefix
@@ -2988,7 +2986,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 
                if (state != INET6_IFADDR_STATE_DEAD) {
                        __ipv6_ifa_notify(RTM_DELADDR, ifa);
-                       atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
+                       inet6addr_notifier_call_chain(NETDEV_DOWN, ifa);
                }
                in6_ifa_put(ifa);
 
@@ -4869,22 +4867,6 @@ static struct pernet_operations addrconf_ops = {
        .exit = addrconf_exit_net,
 };
 
-/*
- *      Device notifier
- */
-
-int register_inet6addr_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&inet6addr_chain, nb);
-}
-EXPORT_SYMBOL(register_inet6addr_notifier);
-
-int unregister_inet6addr_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&inet6addr_chain, nb);
-}
-EXPORT_SYMBOL(unregister_inet6addr_notifier);
-
 static struct rtnl_af_ops inet6_ops = {
        .family           = AF_INET6,
        .fill_link_af     = inet6_fill_link_af,
index d051e5f..7210456 100644 (file)
@@ -78,3 +78,22 @@ int __ipv6_addr_type(const struct in6_addr *addr)
 }
 EXPORT_SYMBOL(__ipv6_addr_type);
 
+static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
+
+int register_inet6addr_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&inet6addr_chain, nb);
+}
+EXPORT_SYMBOL(register_inet6addr_notifier);
+
+int unregister_inet6addr_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(&inet6addr_chain, nb);
+}
+EXPORT_SYMBOL(unregister_inet6addr_notifier);
+
+int inet6addr_notifier_call_chain(unsigned long val, void *v)
+{
+       return atomic_notifier_call_chain(&inet6addr_chain, val, v);
+}
+EXPORT_SYMBOL(inet6addr_notifier_call_chain);
index 5060d54..e0983f3 100644 (file)
@@ -71,6 +71,12 @@ static bool rpfilter_lookup_reverse6(const struct sk_buff *skb,
        return ret;
 }
 
+static bool rpfilter_is_local(const struct sk_buff *skb)
+{
+       const struct rt6_info *rt = (const void *) skb_dst(skb);
+       return rt && (rt->rt6i_flags & RTF_LOCAL);
+}
+
 static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_rpfilter_info *info = par->matchinfo;
@@ -78,7 +84,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
        struct ipv6hdr *iph;
        bool invert = info->flags & XT_RPFILTER_INVERT;
 
-       if (par->in->flags & IFF_LOOPBACK)
+       if (rpfilter_is_local(skb))
                return true ^ invert;
 
        iph = ipv6_hdr(skb);
index 196ab93..0ba10e5 100644 (file)
@@ -330,9 +330,17 @@ found:
        }
 
        if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
-           fq->q.meat == fq->q.len)
-               return ip6_frag_reasm(fq, prev, dev);
+           fq->q.meat == fq->q.len) {
+               int res;
+               unsigned long orefdst = skb->_skb_refdst;
+
+               skb->_skb_refdst = 0UL;
+               res = ip6_frag_reasm(fq, prev, dev);
+               skb->_skb_refdst = orefdst;
+               return res;
+       }
 
+       skb_dst_drop(skb);
        inet_frag_lru_move(&fq->q);
        return -1;
 
index 29340a9..e1b37f5 100644 (file)
@@ -303,7 +303,8 @@ static void iriap_disconnect_indication(void *instance, void *sap,
 {
        struct iriap_cb *self;
 
-       IRDA_DEBUG(4, "%s(), reason=%s\n", __func__, irlmp_reasons[reason]);
+       IRDA_DEBUG(4, "%s(), reason=%s [%d]\n", __func__,
+                  irlmp_reason_str(reason), reason);
 
        self = instance;
 
index 6115a44..1064621 100644 (file)
@@ -66,8 +66,15 @@ const char *irlmp_reasons[] = {
        "LM_LAP_RESET",
        "LM_INIT_DISCONNECT",
        "ERROR, NOT USED",
+       "UNKNOWN",
 };
 
+const char *irlmp_reason_str(LM_REASON reason)
+{
+       reason = min_t(size_t, reason, ARRAY_SIZE(irlmp_reasons) - 1);
+       return irlmp_reasons[reason];
+}
+
 /*
  * Function irlmp_init (void)
  *
@@ -747,7 +754,8 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
 {
        struct lsap_cb *lsap;
 
-       IRDA_DEBUG(1, "%s(), reason=%s\n", __func__, irlmp_reasons[reason]);
+       IRDA_DEBUG(1, "%s(), reason=%s [%d]\n", __func__,
+                  irlmp_reason_str(reason), reason);
        IRDA_ASSERT(self != NULL, return;);
        IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
 
index 58150f8..9ed49ad 100644 (file)
@@ -78,7 +78,7 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
 }
 
-u32 ieee80211_idle_off(struct ieee80211_local *local)
+static u32 __ieee80211_idle_off(struct ieee80211_local *local)
 {
        if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
                return 0;
@@ -87,7 +87,7 @@ u32 ieee80211_idle_off(struct ieee80211_local *local)
        return IEEE80211_CONF_CHANGE_IDLE;
 }
 
-static u32 ieee80211_idle_on(struct ieee80211_local *local)
+static u32 __ieee80211_idle_on(struct ieee80211_local *local)
 {
        if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
                return 0;
@@ -98,16 +98,18 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
        return IEEE80211_CONF_CHANGE_IDLE;
 }
 
-void ieee80211_recalc_idle(struct ieee80211_local *local)
+static u32 __ieee80211_recalc_idle(struct ieee80211_local *local,
+                                  bool force_active)
 {
        bool working = false, scanning, active;
        unsigned int led_trig_start = 0, led_trig_stop = 0;
        struct ieee80211_roc_work *roc;
-       u32 change;
 
        lockdep_assert_held(&local->mtx);
 
-       active = !list_empty(&local->chanctx_list) || local->monitors;
+       active = force_active ||
+                !list_empty(&local->chanctx_list) ||
+                local->monitors;
 
        if (!local->ops->remain_on_channel) {
                list_for_each_entry(roc, &local->roc_list, list) {
@@ -132,9 +134,18 @@ void ieee80211_recalc_idle(struct ieee80211_local *local)
        ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
 
        if (working || scanning || active)
-               change = ieee80211_idle_off(local);
-       else
-               change = ieee80211_idle_on(local);
+               return __ieee80211_idle_off(local);
+       return __ieee80211_idle_on(local);
+}
+
+u32 ieee80211_idle_off(struct ieee80211_local *local)
+{
+       return __ieee80211_recalc_idle(local, true);
+}
+
+void ieee80211_recalc_idle(struct ieee80211_local *local)
+{
+       u32 change = __ieee80211_recalc_idle(local, false);
        if (change)
                ieee80211_hw_config(local, change);
 }
index 82cc303..346ad4c 100644 (file)
@@ -3964,8 +3964,16 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        /* prep auth_data so we don't go into idle on disassoc */
        ifmgd->auth_data = auth_data;
 
-       if (ifmgd->associated)
-               ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
+       if (ifmgd->associated) {
+               u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
+
+               ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
+                                      WLAN_REASON_UNSPECIFIED,
+                                      false, frame_buf);
+
+               __cfg80211_send_deauth(sdata->dev, frame_buf,
+                                      sizeof(frame_buf));
+       }
 
        sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
 
@@ -4025,8 +4033,16 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 
        mutex_lock(&ifmgd->mtx);
 
-       if (ifmgd->associated)
-               ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
+       if (ifmgd->associated) {
+               u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
+
+               ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
+                                      WLAN_REASON_UNSPECIFIED,
+                                      false, frame_buf);
+
+               __cfg80211_send_deauth(sdata->dev, frame_buf,
+                                      sizeof(frame_buf));
+       }
 
        if (ifmgd->auth_data && !ifmgd->auth_data->done) {
                err = -EBUSY;
index 0f92dc2..d7df6ac 100644 (file)
@@ -339,7 +339,11 @@ bitmap_ipmac_tlist(const struct ip_set *set,
 nla_put_failure:
        nla_nest_cancel(skb, nested);
        ipset_nest_end(skb, atd);
-       return -EMSGSIZE;
+       if (unlikely(id == first)) {
+               cb->args[2] = 0;
+               return -EMSGSIZE;
+       }
+       return 0;
 }
 
 static int
index f262722..10a30b4 100644 (file)
@@ -104,6 +104,15 @@ hash_ipportnet4_data_flags(struct hash_ipportnet4_elem *dst, u32 flags)
        dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
+static inline void
+hash_ipportnet4_data_reset_flags(struct hash_ipportnet4_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
+}
+
 static inline int
 hash_ipportnet4_data_match(const struct hash_ipportnet4_elem *elem)
 {
@@ -414,6 +423,15 @@ hash_ipportnet6_data_flags(struct hash_ipportnet6_elem *dst, u32 flags)
        dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
+static inline void
+hash_ipportnet6_data_reset_flags(struct hash_ipportnet6_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
+}
+
 static inline int
 hash_ipportnet6_data_match(const struct hash_ipportnet6_elem *elem)
 {
index 4b677cf..d6a5915 100644 (file)
@@ -87,7 +87,16 @@ hash_net4_data_copy(struct hash_net4_elem *dst,
 static inline void
 hash_net4_data_flags(struct hash_net4_elem *dst, u32 flags)
 {
-       dst->nomatch = flags & IPSET_FLAG_NOMATCH;
+       dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
+}
+
+static inline void
+hash_net4_data_reset_flags(struct hash_net4_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
 }
 
 static inline int
@@ -308,7 +317,16 @@ hash_net6_data_copy(struct hash_net6_elem *dst,
 static inline void
 hash_net6_data_flags(struct hash_net6_elem *dst, u32 flags)
 {
-       dst->nomatch = flags & IPSET_FLAG_NOMATCH;
+       dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
+}
+
+static inline void
+hash_net6_data_reset_flags(struct hash_net6_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
 }
 
 static inline int
index 6ba985f..f2b0a3c 100644 (file)
@@ -198,7 +198,16 @@ hash_netiface4_data_copy(struct hash_netiface4_elem *dst,
 static inline void
 hash_netiface4_data_flags(struct hash_netiface4_elem *dst, u32 flags)
 {
-       dst->nomatch = flags & IPSET_FLAG_NOMATCH;
+       dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
+}
+
+static inline void
+hash_netiface4_data_reset_flags(struct hash_netiface4_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
 }
 
 static inline int
@@ -494,7 +503,7 @@ hash_netiface6_data_copy(struct hash_netiface6_elem *dst,
 static inline void
 hash_netiface6_data_flags(struct hash_netiface6_elem *dst, u32 flags)
 {
-       dst->nomatch = flags & IPSET_FLAG_NOMATCH;
+       dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
 static inline int
@@ -504,6 +513,15 @@ hash_netiface6_data_match(const struct hash_netiface6_elem *elem)
 }
 
 static inline void
+hash_netiface6_data_reset_flags(struct hash_netiface6_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
+}
+
+static inline void
 hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem)
 {
        elem->elem = 0;
index af20c0c..349deb6 100644 (file)
@@ -104,6 +104,15 @@ hash_netport4_data_flags(struct hash_netport4_elem *dst, u32 flags)
        dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
+static inline void
+hash_netport4_data_reset_flags(struct hash_netport4_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
+}
+
 static inline int
 hash_netport4_data_match(const struct hash_netport4_elem *elem)
 {
@@ -375,6 +384,15 @@ hash_netport6_data_flags(struct hash_netport6_elem *dst, u32 flags)
        dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
 }
 
+static inline void
+hash_netport6_data_reset_flags(struct hash_netport6_elem *dst, u32 *flags)
+{
+       if (dst->nomatch) {
+               *flags = IPSET_FLAG_NOMATCH;
+               dst->nomatch = 0;
+       }
+}
+
 static inline int
 hash_netport6_data_match(const struct hash_netport6_elem *elem)
 {
index 8371c2b..09c744a 100644 (file)
@@ -174,9 +174,13 @@ list_set_add(struct list_set *map, u32 i, ip_set_id_t id,
 {
        const struct set_elem *e = list_set_elem(map, i);
 
-       if (i == map->size - 1 && e->id != IPSET_INVALID_ID)
-               /* Last element replaced: e.g. add new,before,last */
-               ip_set_put_byindex(e->id);
+       if (e->id != IPSET_INVALID_ID) {
+               const struct set_elem *x = list_set_elem(map, map->size - 1);
+
+               /* Last element replaced or pushed off */
+               if (x->id != IPSET_INVALID_ID)
+                       ip_set_put_byindex(x->id);
+       }
        if (with_timeout(map->timeout))
                list_elem_tadd(map, i, id, ip_set_timeout_set(timeout));
        else
index 0e7d423..e0c4373 100644 (file)
@@ -1593,10 +1593,8 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
                end += strlen("\r\n\r\n") + clen;
 
                msglen = origlen = end - dptr;
-               if (msglen > datalen) {
-                       nf_ct_helper_log(skb, ct, "incomplete/bad SIP message");
-                       return NF_DROP;
-               }
+               if (msglen > datalen)
+                       return NF_ACCEPT;
 
                ret = process_sip_msg(skb, ct, protoff, dataoff,
                                      &dptr, &msglen);
index 8d5769c..ad24be0 100644 (file)
@@ -467,33 +467,22 @@ EXPORT_SYMBOL_GPL(nf_nat_packet);
 struct nf_nat_proto_clean {
        u8      l3proto;
        u8      l4proto;
-       bool    hash;
 };
 
-/* Clear NAT section of all conntracks, in case we're loaded again. */
-static int nf_nat_proto_clean(struct nf_conn *i, void *data)
+/* kill conntracks with affected NAT section */
+static int nf_nat_proto_remove(struct nf_conn *i, void *data)
 {
        const struct nf_nat_proto_clean *clean = data;
        struct nf_conn_nat *nat = nfct_nat(i);
 
        if (!nat)
                return 0;
-       if (!(i->status & IPS_SRC_NAT_DONE))
-               return 0;
+
        if ((clean->l3proto && nf_ct_l3num(i) != clean->l3proto) ||
            (clean->l4proto && nf_ct_protonum(i) != clean->l4proto))
                return 0;
 
-       if (clean->hash) {
-               spin_lock_bh(&nf_nat_lock);
-               hlist_del_rcu(&nat->bysource);
-               spin_unlock_bh(&nf_nat_lock);
-       } else {
-               memset(nat, 0, sizeof(*nat));
-               i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK |
-                              IPS_SEQ_ADJUST);
-       }
-       return 0;
+       return i->status & IPS_NAT_MASK ? 1 : 0;
 }
 
 static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto)
@@ -505,16 +494,8 @@ static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto)
        struct net *net;
 
        rtnl_lock();
-       /* Step 1 - remove from bysource hash */
-       clean.hash = true;
        for_each_net(net)
-               nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean);
-       synchronize_rcu();
-
-       /* Step 2 - clean NAT section */
-       clean.hash = false;
-       for_each_net(net)
-               nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean);
+               nf_ct_iterate_cleanup(net, nf_nat_proto_remove, &clean);
        rtnl_unlock();
 }
 
@@ -526,16 +507,9 @@ static void nf_nat_l3proto_clean(u8 l3proto)
        struct net *net;
 
        rtnl_lock();
-       /* Step 1 - remove from bysource hash */
-       clean.hash = true;
-       for_each_net(net)
-               nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean);
-       synchronize_rcu();
 
-       /* Step 2 - clean NAT section */
-       clean.hash = false;
        for_each_net(net)
-               nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean);
+               nf_ct_iterate_cleanup(net, nf_nat_proto_remove, &clean);
        rtnl_unlock();
 }
 
@@ -773,7 +747,7 @@ static void __net_exit nf_nat_net_exit(struct net *net)
 {
        struct nf_nat_proto_clean clean = {};
 
-       nf_ct_iterate_cleanup(net, &nf_nat_proto_clean, &clean);
+       nf_ct_iterate_cleanup(net, &nf_nat_proto_remove, &clean);
        synchronize_rcu();
        nf_ct_free_hashtable(net->ct.nat_bysource, net->ct.nat_htable_size);
 }
index a4b7247..6980c3e 100644 (file)
@@ -1593,10 +1593,8 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid,
                return ERR_PTR(-ENOMEM);
 
        retval = ovs_vport_cmd_fill_info(vport, skb, portid, seq, 0, cmd);
-       if (retval < 0) {
-               kfree_skb(skb);
-               return ERR_PTR(retval);
-       }
+       BUG_ON(retval < 0);
+
        return skb;
 }
 
@@ -1726,24 +1724,32 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
            nla_get_u32(a[OVS_VPORT_ATTR_TYPE]) != vport->ops->type)
                err = -EINVAL;
 
+       reply = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!reply) {
+               err = -ENOMEM;
+               goto exit_unlock;
+       }
+
        if (!err && a[OVS_VPORT_ATTR_OPTIONS])
                err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]);
        if (err)
-               goto exit_unlock;
+               goto exit_free;
+
        if (a[OVS_VPORT_ATTR_UPCALL_PID])
                vport->upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]);
 
-       reply = ovs_vport_cmd_build_info(vport, info->snd_portid, info->snd_seq,
-                                        OVS_VPORT_CMD_NEW);
-       if (IS_ERR(reply)) {
-               netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
-                               ovs_dp_vport_multicast_group.id, PTR_ERR(reply));
-               goto exit_unlock;
-       }
+       err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
+                                     info->snd_seq, 0, OVS_VPORT_CMD_NEW);
+       BUG_ON(err < 0);
 
        genl_notify(reply, genl_info_net(info), info->snd_portid,
                    ovs_dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL);
 
+       rtnl_unlock();
+       return 0;
+
+exit_free:
+       kfree_skb(reply);
 exit_unlock:
        rtnl_unlock();
        return err;
index fe0e421..67a2b78 100644 (file)
@@ -795,9 +795,9 @@ void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow)
 
 void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow)
 {
+       BUG_ON(table->count == 0);
        hlist_del_rcu(&flow->hash_node[table->node_ver]);
        table->count--;
-       BUG_ON(table->count < 0);
 }
 
 /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute.  */
index 1135d82..9b97172 100644 (file)
@@ -204,7 +204,6 @@ fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f,
        if (err < 0)
                return err;
 
-       err = -EINVAL;
        if (tb[TCA_FW_CLASSID]) {
                f->res.classid = nla_get_u32(tb[TCA_FW_CLASSID]);
                tcf_bind_filter(tp, &f->res, base);
@@ -218,6 +217,7 @@ fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f,
        }
 #endif /* CONFIG_NET_CLS_IND */
 
+       err = -EINVAL;
        if (tb[TCA_FW_MASK]) {
                mask = nla_get_u32(tb[TCA_FW_MASK]);
                if (mask != head->mask)
index b28cc38..4de4bc4 100755 (executable)
@@ -3016,6 +3016,7 @@ sub process {
                            $dstat !~ /^'X'$/ &&                                        # character constants
                            $dstat !~ /$exceptions/ &&
                            $dstat !~ /^\.$Ident\s*=/ &&                                # .foo =
+                           $dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ &&          # stringification #foo
                            $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ &&       # do {...} while (...); // do {...} while (...)
                            $dstat !~ /^for\s*$Constant$/ &&                            # for (...)
                            $dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ &&   # for (...) bar()
index b45260b..e66d4d2 100644 (file)
@@ -174,5 +174,8 @@ int main(void)
        DEVID_FIELD(x86_cpu_id, model);
        DEVID_FIELD(x86_cpu_id, vendor);
 
+       DEVID(mei_cl_device_id);
+       DEVID_FIELD(mei_cl_device_id, name);
+
        return 0;
 }
index 771ac17..45f9a33 100644 (file)
@@ -1133,6 +1133,18 @@ static int do_x86cpu_entry(const char *filename, void *symval,
 }
 ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry);
 
+/* Looks like: mei:S */
+static int do_mei_entry(const char *filename, void *symval,
+                       char *alias)
+{
+       DEF_FIELD_ADDR(symval, mei_cl_device_id, name);
+
+       sprintf(alias, MEI_CL_MODULE_PREFIX "%s", *name);
+
+       return 1;
+}
+ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry);
+
 /* Does namelen bytes of name exactly match the symbol? */
 static bool sym_is(const char *name, unsigned namelen, const char *symbol)
 {
index 71ae86c..eb560fa 100644 (file)
@@ -3222,18 +3222,10 @@ EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap);
 int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
                           struct vm_area_struct *area)
 {
-       long size;
-       unsigned long offset;
+       struct snd_pcm_runtime *runtime = substream->runtime;;
 
        area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
-       area->vm_flags |= VM_IO;
-       size = area->vm_end - area->vm_start;
-       offset = area->vm_pgoff << PAGE_SHIFT;
-       if (io_remap_pfn_range(area, area->vm_start,
-                               (substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
-                               size, area->vm_page_prot))
-               return -EAGAIN;
-       return 0;
+       return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes);
 }
 
 EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
index f9b5229..8f489de 100644 (file)
@@ -295,18 +295,5 @@ static struct pcmcia_driver pdacf_cs_driver = {
        .suspend        = pdacf_suspend,
        .resume         = pdacf_resume,
 #endif
-
 };
-
-static int __init init_pdacf(void)
-{
-       return pcmcia_register_driver(&pdacf_cs_driver);
-}
-
-static void __exit exit_pdacf(void)
-{
-       pcmcia_unregister_driver(&pdacf_cs_driver);
-}
-
-module_init(init_pdacf);
-module_exit(exit_pdacf);
+module_pcmcia_driver(pdacf_cs_driver);
index 8f93504..d4db7ec 100644 (file)
@@ -367,16 +367,4 @@ static struct pcmcia_driver vxp_cs_driver = {
        .resume         = vxp_resume,
 #endif
 };
-
-static int __init init_vxpocket(void)
-{
-       return pcmcia_register_driver(&vxp_cs_driver);
-}
-
-static void __exit exit_vxpocket(void)
-{
-       pcmcia_unregister_driver(&vxp_cs_driver);
-}
-
-module_init(init_vxpocket);
-module_exit(exit_vxpocket);
+module_pcmcia_driver(vxp_cs_driver);
index ac948a6..e7d3471 100644 (file)
@@ -364,6 +364,39 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(arizona_out_ev);
 
+int arizona_hp_ev(struct snd_soc_dapm_widget *w,
+                  struct snd_kcontrol *kcontrol,
+                  int event)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
+       unsigned int mask = 1 << w->shift;
+       unsigned int val;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               val = mask;
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               val = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Store the desired state for the HP outputs */
+       priv->arizona->hp_ena &= ~mask;
+       priv->arizona->hp_ena |= val;
+
+       /* Force off if HPDET magic is active */
+       if (priv->arizona->hpdet_magic)
+               val = 0;
+
+       snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val);
+
+       return arizona_out_ev(w, kcontrol, event);
+}
+EXPORT_SYMBOL_GPL(arizona_hp_ev);
+
 static unsigned int arizona_sysclk_48k_rates[] = {
        6144000,
        12288000,
index 116372c..13dd291 100644 (file)
@@ -184,6 +184,9 @@ extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
 extern int arizona_out_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol,
                          int event);
+extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol,
+                        int event);
 
 extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                              int source, unsigned int freq, int dir);
index 34d0201..15bc31f 100644 (file)
@@ -1131,11 +1131,11 @@ ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
 SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
                       ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux),
 
-SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
index cdeb301..7841b42 100644 (file)
@@ -551,11 +551,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
 SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
                    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
 
-SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
index c800ea4..5a1f648 100644 (file)
@@ -102,6 +102,10 @@ static struct utsname uts_buf;
 #define MAX_FILE_NAME 100
 #define ENTRIES_PER_BLOCK 50
 
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
 struct kvp_record {
        char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
        char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
@@ -1407,7 +1411,7 @@ netlink_send(int fd, struct cn_msg *msg)
 
 int main(void)
 {
-       int fd, len, sock_opt;
+       int fd, len, nl_group;
        int error;
        struct cn_msg *message;
        struct pollfd pfd;
@@ -1443,7 +1447,7 @@ int main(void)
        addr.nl_family = AF_NETLINK;
        addr.nl_pad = 0;
        addr.nl_pid = 0;
-       addr.nl_groups = CN_KVP_IDX;
+       addr.nl_groups = 0;
 
 
        error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
@@ -1452,8 +1456,8 @@ int main(void)
                close(fd);
                exit(EXIT_FAILURE);
        }
-       sock_opt = addr.nl_groups;
-       setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
+       nl_group = CN_KVP_IDX;
+       setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group));
        /*
         * Register ourselves with the kernel.
         */
@@ -1499,6 +1503,10 @@ int main(void)
                }
 
                incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
+
+               if (incoming_msg->nlmsg_type != NLMSG_DONE)
+                       continue;
+
                incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
                hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
 
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
new file mode 100644 (file)
index 0000000..fea03a3
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * An implementation of the host initiated guest snapshot for Hyper-V.
+ *
+ *
+ * Copyright (C) 2013, Microsoft, Inc.
+ * Author : K. Y. Srinivasan <kys@microsoft.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.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ */
+
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <mntent.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <linux/fs.h>
+#include <linux/connector.h>
+#include <linux/hyperv.h>
+#include <linux/netlink.h>
+#include <syslog.h>
+
+static char vss_recv_buffer[4096];
+static char vss_send_buffer[4096];
+static struct sockaddr_nl addr;
+
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
+
+static int vss_do_freeze(char *dir, unsigned int cmd, char *fs_op)
+{
+       int ret, fd = open(dir, O_RDONLY);
+
+       if (fd < 0)
+               return 1;
+       ret = ioctl(fd, cmd, 0);
+       syslog(LOG_INFO, "VSS: %s of %s: %s\n", fs_op, dir, strerror(errno));
+       close(fd);
+       return !!ret;
+}
+
+static int vss_operate(int operation)
+{
+       char *fs_op;
+       char match[] = "/dev/";
+       FILE *mounts;
+       struct mntent *ent;
+       unsigned int cmd;
+       int error = 0, root_seen = 0;
+
+       switch (operation) {
+       case VSS_OP_FREEZE:
+               cmd = FIFREEZE;
+               fs_op = "freeze";
+               break;
+       case VSS_OP_THAW:
+               cmd = FITHAW;
+               fs_op = "thaw";
+               break;
+       default:
+               return -1;
+       }
+
+       mounts = setmntent("/proc/mounts", "r");
+       if (mounts == NULL)
+               return -1;
+
+       while ((ent = getmntent(mounts))) {
+               if (strncmp(ent->mnt_fsname, match, strlen(match)))
+                       continue;
+               if (strcmp(ent->mnt_type, "iso9660") == 0)
+                       continue;
+               if (strcmp(ent->mnt_dir, "/") == 0) {
+                       root_seen = 1;
+                       continue;
+               }
+               error |= vss_do_freeze(ent->mnt_dir, cmd, fs_op);
+       }
+       endmntent(mounts);
+
+       if (root_seen) {
+               error |= vss_do_freeze("/", cmd, fs_op);
+       }
+
+       return error;
+}
+
+static int netlink_send(int fd, struct cn_msg *msg)
+{
+       struct nlmsghdr *nlh;
+       unsigned int size;
+       struct msghdr message;
+       char buffer[64];
+       struct iovec iov[2];
+
+       size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
+
+       nlh = (struct nlmsghdr *)buffer;
+       nlh->nlmsg_seq = 0;
+       nlh->nlmsg_pid = getpid();
+       nlh->nlmsg_type = NLMSG_DONE;
+       nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
+       nlh->nlmsg_flags = 0;
+
+       iov[0].iov_base = nlh;
+       iov[0].iov_len = sizeof(*nlh);
+
+       iov[1].iov_base = msg;
+       iov[1].iov_len = size;
+
+       memset(&message, 0, sizeof(message));
+       message.msg_name = &addr;
+       message.msg_namelen = sizeof(addr);
+       message.msg_iov = iov;
+       message.msg_iovlen = 2;
+
+       return sendmsg(fd, &message, 0);
+}
+
+int main(void)
+{
+       int fd, len, nl_group;
+       int error;
+       struct cn_msg *message;
+       struct pollfd pfd;
+       struct nlmsghdr *incoming_msg;
+       struct cn_msg   *incoming_cn_msg;
+       int     op;
+       struct hv_vss_msg *vss_msg;
+
+       if (daemon(1, 0))
+               return 1;
+
+       openlog("Hyper-V VSS", 0, LOG_USER);
+       syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
+
+       fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
+       if (fd < 0) {
+               syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
+               exit(EXIT_FAILURE);
+       }
+       addr.nl_family = AF_NETLINK;
+       addr.nl_pad = 0;
+       addr.nl_pid = 0;
+       addr.nl_groups = 0;
+
+
+       error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+       if (error < 0) {
+               syslog(LOG_ERR, "bind failed; error:%d", error);
+               close(fd);
+               exit(EXIT_FAILURE);
+       }
+       nl_group = CN_VSS_IDX;
+       setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group));
+       /*
+        * Register ourselves with the kernel.
+        */
+       message = (struct cn_msg *)vss_send_buffer;
+       message->id.idx = CN_VSS_IDX;
+       message->id.val = CN_VSS_VAL;
+       message->ack = 0;
+       vss_msg = (struct hv_vss_msg *)message->data;
+       vss_msg->vss_hdr.operation = VSS_OP_REGISTER;
+
+       message->len = sizeof(struct hv_vss_msg);
+
+       len = netlink_send(fd, message);
+       if (len < 0) {
+               syslog(LOG_ERR, "netlink_send failed; error:%d", len);
+               close(fd);
+               exit(EXIT_FAILURE);
+       }
+
+       pfd.fd = fd;
+
+       while (1) {
+               struct sockaddr *addr_p = (struct sockaddr *) &addr;
+               socklen_t addr_l = sizeof(addr);
+               pfd.events = POLLIN;
+               pfd.revents = 0;
+               poll(&pfd, 1, -1);
+
+               len = recvfrom(fd, vss_recv_buffer, sizeof(vss_recv_buffer), 0,
+                               addr_p, &addr_l);
+
+               if (len < 0) {
+                       syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
+                                       addr.nl_pid, errno, strerror(errno));
+                       close(fd);
+                       return -1;
+               }
+
+               if (addr.nl_pid) {
+                       syslog(LOG_WARNING,
+                               "Received packet from untrusted pid:%u",
+                               addr.nl_pid);
+                       continue;
+               }
+
+               incoming_msg = (struct nlmsghdr *)vss_recv_buffer;
+
+               if (incoming_msg->nlmsg_type != NLMSG_DONE)
+                       continue;
+
+               incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
+               vss_msg = (struct hv_vss_msg *)incoming_cn_msg->data;
+               op = vss_msg->vss_hdr.operation;
+               error =  HV_S_OK;
+
+               switch (op) {
+               case VSS_OP_FREEZE:
+               case VSS_OP_THAW:
+                       error = vss_operate(op);
+                       if (error)
+                               error = HV_E_FAIL;
+                       break;
+               default:
+                       syslog(LOG_ERR, "Illegal op:%d\n", op);
+               }
+               vss_msg->error = error;
+               len = netlink_send(fd, incoming_cn_msg);
+               if (len < 0) {
+                       syslog(LOG_ERR, "net_link send failed; error:%d", len);
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+}
index 6f3214e..321e066 100644 (file)
@@ -1421,6 +1421,7 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
        case 0x3C:      /* HSW */
        case 0x3F:      /* HSW */
        case 0x45:      /* HSW */
+       case 0x46:      /* HSW */
                return 1;
        case 0x2E:      /* Nehalem-EX Xeon - Beckton */
        case 0x2F:      /* Westmere-EX Xeon - Eagleton */
@@ -1515,6 +1516,7 @@ void rapl_probe(unsigned int family, unsigned int model)
        case 0x3C:      /* HSW */
        case 0x3F:      /* HSW */
        case 0x45:      /* HSW */
+       case 0x46:      /* HSW */
                do_rapl = RAPL_PKG | RAPL_CORES | RAPL_GFX;
                break;
        case 0x2D:
@@ -1754,6 +1756,7 @@ int is_snb(unsigned int family, unsigned int model)
        case 0x3C:      /* HSW */
        case 0x3F:      /* HSW */
        case 0x45:      /* HSW */
+       case 0x46:      /* HSW */
                return 1;
        }
        return 0;
@@ -2276,7 +2279,7 @@ int main(int argc, char **argv)
        cmdline(argc, argv);
 
        if (verbose)
-               fprintf(stderr, "turbostat v3.2 February 11, 2013"
+               fprintf(stderr, "turbostat v3.3 March 15, 2013"
                        " - Len Brown <lenb@kernel.org>\n");
 
        turbostat_init();