Merge branch 'nomadik' into devel
authorLinus Walleij <linus.walleij@linaro.org>
Sun, 11 Nov 2012 18:12:46 +0000 (19:12 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Sun, 11 Nov 2012 18:12:46 +0000 (19:12 +0100)
468 files changed:
Documentation/arm64/memory.txt
Documentation/devicetree/bindings/gpio/gpio.txt
Documentation/devicetree/bindings/gpio/gpio_atmel.txt
Documentation/devicetree/bindings/input/touchscreen/egalax-ts.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt [new file with mode: 0644]
Documentation/gpio.txt
Documentation/hwmon/fam15h_power
Documentation/pinctrl.txt
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/at91sam9260.dtsi
arch/arm/boot/dts/at91sam9263.dtsi
arch/arm/boot/dts/at91sam9263ek.dts
arch/arm/boot/dts/at91sam9g15.dtsi [new file with mode: 0644]
arch/arm/boot/dts/at91sam9g15ek.dts [new file with mode: 0644]
arch/arm/boot/dts/at91sam9g20ek_common.dtsi
arch/arm/boot/dts/at91sam9g25.dtsi [new file with mode: 0644]
arch/arm/boot/dts/at91sam9g25ek.dts
arch/arm/boot/dts/at91sam9g35.dtsi [new file with mode: 0644]
arch/arm/boot/dts/at91sam9g35ek.dts [new file with mode: 0644]
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9m10g45ek.dts
arch/arm/boot/dts/at91sam9n12.dtsi
arch/arm/boot/dts/at91sam9x25.dtsi [new file with mode: 0644]
arch/arm/boot/dts/at91sam9x25ek.dts [new file with mode: 0644]
arch/arm/boot/dts/at91sam9x35.dtsi [new file with mode: 0644]
arch/arm/boot/dts/at91sam9x35ek.dts [new file with mode: 0644]
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/at91sam9x5ek.dtsi [new file with mode: 0644]
arch/arm/boot/dts/spear1310-evb.dts
arch/arm/boot/dts/spear1310.dtsi
arch/arm/boot/dts/spear1340-evb.dts
arch/arm/boot/dts/spear1340.dtsi
arch/arm/boot/dts/spear310.dtsi
arch/arm/boot/dts/spear320-evb.dts
arch/arm/boot/dts/spear320.dtsi
arch/arm/configs/at91_dt_defconfig
arch/arm/include/asm/io.h
arch/arm/include/asm/sched_clock.h
arch/arm/include/asm/vfpmacros.h
arch/arm/include/uapi/asm/hwcap.h
arch/arm/kernel/sched_clock.c
arch/arm/mach-at91/at91rm9200.c
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9261.c
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/at91sam9n12.c
arch/arm/mach-at91/at91sam9rl.c
arch/arm/mach-at91/at91sam9x5.c
arch/arm/mach-at91/board-dt.c
arch/arm/mach-at91/gpio.c
arch/arm/mach-at91/setup.c
arch/arm/mach-at91/soc.h
arch/arm/mach-u300/core.c
arch/arm/mach-u300/include/mach/irqs.h
arch/arm/mm/alignment.c
arch/arm/vfp/vfpmodule.c
arch/arm/xen/enlighten.c
arch/arm/xen/hypercall.S
arch/arm64/Kconfig
arch/arm64/include/asm/elf.h
arch/arm64/include/asm/fpsimd.h
arch/arm64/include/asm/io.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/unistd.h
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/process.c
arch/arm64/kernel/smp.c
arch/arm64/mm/init.c
arch/frv/Kconfig
arch/frv/boot/Makefile
arch/frv/include/asm/unistd.h
arch/frv/kernel/entry.S
arch/frv/kernel/process.c
arch/frv/mb93090-mb00/pci-dma-nommu.c
arch/h8300/include/asm/cache.h
arch/s390/include/asm/cio.h
arch/s390/include/asm/pgtable.h
arch/s390/kernel/sclp.S
arch/s390/lib/uaccess_pt.c
arch/s390/mm/gup.c
arch/sparc/Kconfig
arch/sparc/crypto/Makefile
arch/sparc/crypto/aes_glue.c
arch/sparc/crypto/camellia_glue.c
arch/sparc/crypto/crc32c_glue.c
arch/sparc/crypto/des_glue.c
arch/sparc/crypto/md5_glue.c
arch/sparc/crypto/sha1_glue.c
arch/sparc/crypto/sha256_glue.c
arch/sparc/crypto/sha512_glue.c
arch/sparc/include/asm/atomic_64.h
arch/sparc/include/asm/backoff.h
arch/sparc/include/asm/compat.h
arch/sparc/include/asm/processor_64.h
arch/sparc/include/asm/prom.h
arch/sparc/include/asm/thread_info_64.h
arch/sparc/include/asm/ttable.h
arch/sparc/include/uapi/asm/unistd.h
arch/sparc/kernel/entry.h
arch/sparc/kernel/leon_kernel.c
arch/sparc/kernel/perf_event.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/ptrace_64.c
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/kernel/systbls_32.S
arch/sparc/kernel/systbls_64.S
arch/sparc/kernel/unaligned_64.c
arch/sparc/kernel/visemul.c
arch/sparc/kernel/vmlinux.lds.S
arch/sparc/kernel/winfixup.S
arch/sparc/lib/atomic_64.S
arch/sparc/lib/ksyms.c
arch/sparc/math-emu/math_64.c
arch/x86/include/asm/xen/hypercall.h
arch/x86/include/asm/xen/hypervisor.h
arch/x86/kvm/x86.c
arch/x86/xen/mmu.c
arch/xtensa/Kconfig
arch/xtensa/include/asm/io.h
arch/xtensa/include/asm/processor.h
arch/xtensa/include/asm/syscall.h
arch/xtensa/include/asm/unistd.h
arch/xtensa/include/uapi/asm/unistd.h
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/process.c
arch/xtensa/kernel/syscall.c
arch/xtensa/kernel/xtensa_ksyms.c
block/Kconfig
block/blk-cgroup.c
block/blk-core.c
crypto/cryptd.c
drivers/acpi/video.c
drivers/base/platform.c
drivers/block/Kconfig
drivers/block/cciss.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/mtip32xx/mtip32xx.h
drivers/block/xen-blkback/common.h
drivers/block/xen-blkback/xenbus.c
drivers/cpufreq/powernow-k8.c
drivers/gpio/Kconfig
drivers/gpio/gpio-74x164.c
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-timberdale.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos_drm_connector.c
drivers/gpu/drm/exynos/exynos_drm_encoder.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sdvo_regs.h
drivers/gpu/drm/nouveau/core/core/mm.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
drivers/gpu/drm/nouveau/core/include/core/mm.h
drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drm.h
drivers/gpu/drm/nouveau/nouveau_irq.c
drivers/gpu/drm/nouveau/nv04_dac.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv04_tv.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_cs.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/radeon_atpx_handler.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/udl/udl_drv.h
drivers/gpu/drm/udl/udl_fb.c
drivers/gpu/drm/udl/udl_transfer.c
drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-microsoft.c
drivers/hid/hid-multitouch.c
drivers/hid/hidraw.c
drivers/hwmon/asb100.c
drivers/hwmon/fam15h_power.c
drivers/hwmon/gpio-fan.c
drivers/hwmon/w83627ehf.c
drivers/hwmon/w83627hf.c
drivers/hwmon/w83781d.c
drivers/hwmon/w83791d.c
drivers/hwmon/w83792d.c
drivers/hwmon/w83l786ng.c
drivers/i2c/Makefile
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-nomadik.c
drivers/i2c/busses/i2c-tegra.c
drivers/i2c/i2c-stub.c [moved from drivers/i2c/busses/i2c-stub.c with 75% similarity]
drivers/input/keyboard/Kconfig
drivers/input/keyboard/pxa27x_keypad.c
drivers/input/misc/xen-kbdfront.c
drivers/input/mouse/bcm5974.c
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/egalax_ts.c
drivers/input/touchscreen/tsc40.c
drivers/isdn/Kconfig
drivers/isdn/i4l/Kconfig
drivers/isdn/i4l/isdn_common.c
drivers/md/faulty.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/mmc/host/dw_mmc-exynos.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc-pltfm.h
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mtd/nand/atmel_nand.c
drivers/net/bonding/bond_sysfs.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/jme.c
drivers/net/ethernet/marvell/skge.c
drivers/net/ethernet/micrel/ksz884x.c
drivers/net/ethernet/nxp/lpc_eth.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/xilinx/xilinx_axienet_main.c
drivers/net/phy/mdio-bitbang.c
drivers/net/usb/cdc_eem.c
drivers/net/usb/smsc95xx.c
drivers/net/usb/usbnet.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vxlan.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/b43legacy/pio.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/pci/bus.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/proc.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/core.c
drivers/pinctrl/core.h
drivers/pinctrl/devicetree.c
drivers/pinctrl/mvebu/Kconfig [new file with mode: 0644]
drivers/pinctrl/mvebu/Makefile [new file with mode: 0644]
drivers/pinctrl/mvebu/pinctrl-armada-370.c [moved from drivers/pinctrl/pinctrl-armada-370.c with 100% similarity]
drivers/pinctrl/mvebu/pinctrl-armada-xp.c [moved from drivers/pinctrl/pinctrl-armada-xp.c with 100% similarity]
drivers/pinctrl/mvebu/pinctrl-dove.c [moved from drivers/pinctrl/pinctrl-dove.c with 100% similarity]
drivers/pinctrl/mvebu/pinctrl-kirkwood.c [moved from drivers/pinctrl/pinctrl-kirkwood.c with 100% similarity]
drivers/pinctrl/mvebu/pinctrl-mvebu.c [moved from drivers/pinctrl/pinctrl-mvebu.c with 99% similarity]
drivers/pinctrl/mvebu/pinctrl-mvebu.h [moved from drivers/pinctrl/pinctrl-mvebu.h with 100% similarity]
drivers/pinctrl/pinctrl-at91.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-coh901.c
drivers/pinctrl/pinctrl-exynos.c
drivers/pinctrl/pinctrl-sirf.c
drivers/pinctrl/pinctrl-u300.c
drivers/pinctrl/pinmux.c
drivers/pinctrl/spear/Kconfig
drivers/pinctrl/spear/Makefile
drivers/pinctrl/spear/pinctrl-plgpio.c [new file with mode: 0644]
drivers/pinctrl/spear/pinctrl-spear.c
drivers/pinctrl/spear/pinctrl-spear.h
drivers/pinctrl/spear/pinctrl-spear1310.c
drivers/pinctrl/spear/pinctrl-spear1340.c
drivers/pinctrl/spear/pinctrl-spear300.c
drivers/pinctrl/spear/pinctrl-spear310.c
drivers/pinctrl/spear/pinctrl-spear320.c
drivers/pinctrl/spear/pinctrl-spear3xx.c
drivers/pinctrl/spear/pinctrl-spear3xx.h
drivers/s390/cio/css.h
drivers/s390/cio/device.c
drivers/s390/cio/idset.c
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_target.h
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/qla2xxx/tcm_qla2xxx.h
drivers/scsi/qlogicpti.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_core.h
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_util.c
drivers/target/iscsi/iscsi_target_util.h
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_tmr.c
drivers/target/target_core_transport.c
drivers/thermal/exynos_thermal.c
drivers/thermal/rcar_thermal.c
drivers/tty/serial/atmel_serial.c
drivers/usb/gadget/u_ether.c
drivers/video/xen-fbfront.c
drivers/virtio/virtio.c
drivers/xen/Makefile
drivers/xen/events.c
drivers/xen/fallback.c [new file with mode: 0644]
drivers/xen/gntdev.c
drivers/xen/xenbus/xenbus_dev_frontend.c
fs/bio.c
fs/ceph/export.c
fs/cifs/cifsacl.c
fs/cifs/dir.c
fs/eventpoll.c
fs/ext4/ialloc.c
fs/file.c
fs/gfs2/file.c
fs/gfs2/lops.c
fs/gfs2/quota.c
fs/gfs2/rgrp.c
fs/gfs2/super.c
fs/gfs2/trans.c
fs/nfs/dns_resolve.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/mount_clnt.c
fs/nfs/namespace.c
fs/nfs/nfs4namespace.c
fs/nfs/nfs4proc.c
fs/nfs/pnfs.c
fs/nfs/super.c
fs/nfs/unlink.c
fs/notify/fanotify/fanotify.c
fs/xfs/xfs_alloc.c
fs/xfs/xfs_alloc.h
fs/xfs/xfs_alloc_btree.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_bmap.h
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_fsops.c
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log_recover.c
include/asm-generic/gpio.h
include/linux/gpio.h
include/linux/hashtable.h [new file with mode: 0644]
include/linux/kvm_host.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/sdhci.h
include/linux/of_address.h
include/linux/pinctrl/pinctrl.h
include/linux/platform_data/pinctrl-coh901.h
include/linux/ptp_clock_kernel.h
include/linux/raid/Kbuild
include/linux/raid/md_u.h
include/net/cfg80211.h
include/sound/core.h
include/trace/events/xen.h
include/uapi/linux/eventpoll.h
include/uapi/linux/raid/Kbuild
include/uapi/linux/raid/md_p.h [moved from include/linux/raid/md_p.h with 100% similarity]
include/uapi/linux/raid/md_u.h [new file with mode: 0644]
include/xen/hvm.h
init/main.c
kernel/module.c
mm/vmscan.c
net/ceph/messenger.c
net/core/dev.c
net/core/rtnetlink.c
net/ipv4/inet_diag.c
net/ipv4/netfilter/iptable_nat.c
net/ipv4/tcp_illinois.c
net/ipv4/tcp_input.c
net/ipv4/tcp_metrics.c
net/ipv6/ip6_gre.c
net/ipv6/ndisc.c
net/ipv6/netfilter/ip6table_nat.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/l2tp/l2tp_eth.c
net/mac80211/ibss.c
net/mac80211/rx.c
net/mac80211/util.c
net/netfilter/nf_conntrack_h323_main.c
net/sched/sch_qfq.c
net/sctp/socket.c
net/sunrpc/backchannel_rqst.c
net/tipc/handler.c
net/wireless/core.c
net/wireless/reg.c
net/wireless/util.c
scripts/Makefile.modinst
scripts/checkpatch.pl
sound/core/compress_offload.c
sound/core/control.c
sound/core/hwdep.c
sound/core/init.c
sound/core/oss/mixer_oss.c
sound/core/oss/pcm_oss.c
sound/core/pcm.c
sound/core/pcm_native.c
sound/core/rawmidi.c
sound/core/sound.c
sound/core/sound_oss.c
sound/i2c/other/ak4113.c
sound/i2c/other/ak4114.c
sound/i2c/other/ak4117.c
sound/pci/es1968.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/ice1724.c
sound/pci/rme9652/hdspm.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/wm8994.c
sound/soc/omap/omap-dmic.c
sound/soc/omap/zoom2.c
sound/usb/card.c
sound/usb/card.h
sound/usb/endpoint.c
sound/usb/endpoint.h
sound/usb/mixer.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
sound/usb/proc.c
sound/usb/stream.c
sound/usb/usbaudio.h
tools/testing/selftests/Makefile
tools/testing/selftests/epoll/Makefile [deleted file]
tools/testing/selftests/epoll/test_epoll.c [deleted file]

index dbbdcbb..4110cca 100644 (file)
@@ -27,17 +27,17 @@ Start                       End                     Size            Use
 -----------------------------------------------------------------------
 0000000000000000       0000007fffffffff         512GB          user
 
-ffffff8000000000       ffffffbbfffcffff        ~240GB          vmalloc
+ffffff8000000000       ffffffbbfffeffff        ~240GB          vmalloc
 
-ffffffbbfffd0000       ffffffbcfffdffff          64KB          [guard page]
+ffffffbbffff0000       ffffffbbffffffff          64KB          [guard page]
 
-ffffffbbfffe0000       ffffffbcfffeffff          64KB          PCI I/O space
+ffffffbc00000000       ffffffbdffffffff           8GB          vmemmap
 
-ffffffbbffff0000       ffffffbcffffffff          64KB          [guard page]
+ffffffbe00000000       ffffffbffbbfffff          ~8GB          [guard, future vmmemap]
 
-ffffffbc00000000       ffffffbdffffffff           8GB          vmemmap
+ffffffbffbe00000       ffffffbffbe0ffff          64KB          PCI I/O space
 
-ffffffbe00000000       ffffffbffbffffff          ~8GB          [guard, future vmmemap]
+ffffffbbffff0000       ffffffbcffffffff          ~2MB          [guard]
 
 ffffffbffc000000       ffffffbfffffffff          64MB          modules
 
index 4e16ba4..a336287 100644 (file)
@@ -75,4 +75,40 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
                gpio-controller;
        };
 
+2.1) gpio-controller and pinctrl subsystem
+------------------------------------------
 
+gpio-controller on a SOC might be tightly coupled with the pinctrl
+subsystem, in the sense that the pins can be used by other functions
+together with optional gpio feature.
+
+While the pin allocation is totally managed by the pin ctrl subsystem,
+gpio (under gpiolib) is still maintained by gpio drivers. It may happen
+that different pin ranges in a SoC is managed by different gpio drivers.
+
+This makes it logical to let gpio drivers announce their pin ranges to
+the pin ctrl subsystem and call 'pinctrl_request_gpio' in order to
+request the corresponding pin before any gpio usage.
+
+For this, the gpio controller can use a pinctrl phandle and pins to
+announce the pinrange to the pin ctrl subsystem. For example,
+
+       qe_pio_e: gpio-controller@1460 {
+               #gpio-cells = <2>;
+               compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
+               reg = <0x1460 0x18>;
+               gpio-controller;
+               gpio-ranges = <&pinctrl1 20 10>, <&pinctrl2 50 20>;
+
+    }
+
+where,
+   &pinctrl1 and &pinctrl2 is the phandle to the pinctrl DT node.
+
+   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.
+
+The pinctrl node must have "#gpio-range-cells" property to show number of
+arguments to pass with phandle from gpio controllers node.
index 66efc80..85f8c0d 100644 (file)
@@ -9,6 +9,10 @@ Required properties:
   unused).
 - gpio-controller: Marks the device node as a GPIO controller.
 
+optional properties:
+- #gpio-lines: Number of gpio if absent 32.
+
+
 Example:
        pioA: gpio@fffff200 {
                compatible = "atmel,at91rm9200-gpio";
@@ -16,5 +20,6 @@ Example:
                interrupts = <2 4>;
                #gpio-cells = <2>;
                gpio-controller;
+               #gpio-lines = <19>;
        };
 
diff --git a/Documentation/devicetree/bindings/input/touchscreen/egalax-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/egalax-ts.txt
new file mode 100644 (file)
index 0000000..df70318
--- /dev/null
@@ -0,0 +1,19 @@
+* EETI eGalax Multiple Touch Controller
+
+Required properties:
+- compatible: must be "eeti,egalax_ts"
+- reg: i2c slave address
+- interrupt-parent: the phandle for the interrupt controller
+- interrupts: touch controller interrupt
+- wakeup-gpios: the gpio pin to be used for waking up the controller
+  as well as uased as irq pin
+
+Example:
+
+       egalax_ts@04 {
+               compatible = "eeti,egalax_ts";
+               reg = <0x04>;
+               interrupt-parent = <&gpio1>;
+               interrupts = <9 2>;
+               wakeup-gpios = <&gpio1 9 0>;
+       };
diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
new file mode 100644 (file)
index 0000000..20a987e
--- /dev/null
@@ -0,0 +1,136 @@
+* Atmel AT91 Pinmux Controller
+
+The AT91 Pinmux Controler, enables the IC
+to share one PAD to several functional blocks. The sharing is done by
+multiplexing the PAD input/output signals. For each PAD there are up to
+8 muxing options (called periph modes). Since different modules require
+different PAD settings (like pull up, keeper, etc) the contoller controls
+also the PAD settings parameters.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+Atmel AT91 pin configuration node is a node of a group of pins which can be
+used for a specific device or function. This node represents both mux and config
+of the pins in that group. The 'pins' selects the function mode(also named pin
+mode) this pin can work on and the 'config' configures various pad settings
+such as pull-up, multi drive, etc.
+
+Required properties for iomux controller:
+- compatible: "atmel,at91rm9200-pinctrl"
+- atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be
+  configured in this periph mode. All the periph and bank need to be describe.
+
+How to create such array:
+
+Each column will represent the possible peripheral of the pinctrl
+Each line will represent a pio bank
+
+Take an example on the 9260
+Peripheral: 2 ( A and B)
+Bank: 3 (A, B and C)
+=>
+
+  /*    A         B     */
+  0xffffffff 0xffc00c3b  /* pioA */
+  0xffffffff 0x7fff3ccf  /* pioB */
+  0xffffffff 0x007fffff  /* pioC */
+
+For each peripheral/bank we will descibe in a u32 if a pin can can be
+configured in it by putting 1 to the pin bit (1 << pin)
+
+Let's take the pioA on peripheral B
+From the datasheet Table 10-2.
+Peripheral B
+PA0    MCDB0
+PA1    MCCDB
+PA2
+PA3    MCDB3
+PA4    MCDB2
+PA5    MCDB1
+PA6
+PA7
+PA8
+PA9
+PA10   ETX2
+PA11   ETX3
+PA12
+PA13
+PA14
+PA15
+PA16
+PA17
+PA18
+PA19
+PA20
+PA21
+PA22   ETXER
+PA23   ETX2
+PA24   ETX3
+PA25   ERX2
+PA26   ERX3
+PA27   ERXCK
+PA28   ECRS
+PA29   ECOL
+PA30   RXD4
+PA31   TXD4
+
+=> 0xffc00c3b
+
+Required properties for pin configuration node:
+- atmel,pins: 4 integers array, represents a group of pins mux and config
+  setting. The format is atmel,pins = <PIN_BANK PIN_BANK_NUM PERIPH CONFIG>.
+  The PERIPH 0 means gpio.
+
+Bits used for CONFIG:
+PULL_UP(1 << 0): indicate this pin need a pull up.
+MULTIDRIVE(1 << 1): indicate this pin need to be configured as multidrive.
+
+NOTE:
+Some requirements for using atmel,at91rm9200-pinctrl binding:
+1. We have pin function node defined under at91 controller node to represent
+   what pinmux functions this SoC supports.
+2. The driver can use the function node's name and pin configuration node's
+   name describe the pin function and group hierarchy.
+   For example, Linux at91 pinctrl driver takes the function node's name
+   as the function name and pin configuration node's name as group name to
+   create the map table.
+3. Each pin configuration node should have a phandle, devices can set pins
+   configurations by referring to the phandle of that pin configuration node.
+4. The gpio controller must be describe in the pinctrl simple-bus.
+
+Examples:
+
+pinctrl@fffff400 {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       ranges;
+       compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+       reg = <0xfffff400 0x600>;
+
+       atmel,mux-mask = <
+             /*    A         B     */
+              0xffffffff 0xffc00c3b  /* pioA */
+              0xffffffff 0x7fff3ccf  /* pioB */
+              0xffffffff 0x007fffff  /* pioC */
+             >;
+
+       /* shared pinctrl settings */
+       dbgu {
+               pinctrl_dbgu: dbgu-0 {
+                       atmel,pins =
+                               <1 14 0x1 0x0   /* PB14 periph A */
+                                1 15 0x1 0x1>; /* PB15 periph with pullup */
+               };
+       };
+};
+
+dbgu: serial@fffff200 {
+       compatible = "atmel,at91sam9260-usart";
+       reg = <0xfffff200 0x200>;
+       interrupts = <1 4 7>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_dbgu>;
+       status = "disabled";
+};
index e08a883..77a1d11 100644 (file)
@@ -439,6 +439,48 @@ slower clock delays the rising edge of SCK, and the I2C master adjusts its
 signaling rate accordingly.
 
 
+GPIO controllers and the pinctrl subsystem
+------------------------------------------
+
+A GPIO controller on a SOC might be tightly coupled with the pinctrl
+subsystem, in the sense that the pins can be used by other functions
+together with an optional gpio feature. We have already covered the
+case where e.g. a GPIO controller need to reserve a pin or set the
+direction of a pin by calling any of:
+
+pinctrl_request_gpio()
+pinctrl_free_gpio()
+pinctrl_gpio_direction_input()
+pinctrl_gpio_direction_output()
+
+But how does the pin control subsystem cross-correlate the GPIO
+numbers (which are a global business) to a certain pin on a certain
+pin controller?
+
+This is done by registering "ranges" of pins, which are essentially
+cross-reference tables. These are described in
+Documentation/pinctrl.txt
+
+While the pin allocation is totally managed by the pinctrl subsystem,
+gpio (under gpiolib) is still maintained by gpio drivers. It may happen
+that different pin ranges in a SoC is managed by different gpio drivers.
+
+This makes it logical to let gpio drivers announce their pin ranges to
+the pin ctrl subsystem before it will call 'pinctrl_request_gpio' in order
+to request the corresponding pin to be prepared by the pinctrl subsystem
+before any gpio usage.
+
+For this, the gpio controller can register its pin range with pinctrl
+subsystem. There are two ways of doing it currently: with or without DT.
+
+For with DT support refer to Documentation/devicetree/bindings/gpio/gpio.txt.
+
+For non-DT support, user can call gpiochip_add_pin_range() with appropriate
+parameters to register a range of gpio pins with a pinctrl driver. For this
+exact name string of pinctrl device has to be passed as one of the
+argument to this routine.
+
+
 What do these conventions omit?
 ===============================
 One of the biggest things these conventions omit is pin multiplexing, since
index a92918e..8065481 100644 (file)
@@ -10,7 +10,7 @@ Supported chips:
   BIOS and Kernel Developer's Guide (BKDG) For AMD Family 15h Processors
     (not yet published)
 
-Author: Andreas Herrmann <andreas.herrmann3@amd.com>
+Author: Andreas Herrmann <herrmann.der.user@googlemail.com>
 
 Description
 -----------
index 3b4ee53..da40efb 100644 (file)
@@ -364,6 +364,9 @@ will get an pin number into its handled number range. Further it is also passed
 the range ID value, so that the pin controller knows which range it should
 deal with.
 
+Calling pinctrl_add_gpio_range from pinctrl driver is DEPRECATED. Please see
+section 2.1 of Documentation/devicetree/bindings/gpio/gpio.txt on how to bind
+pinctrl and gpio drivers.
 
 PINMUX interfaces
 =================
@@ -1193,4 +1196,6 @@ foo_switch()
        ...
 }
 
-The above has to be done from process context.
+The above has to be done from process context. The reservation of the pins
+will be done when the state is activated, so in effect one specific pin
+can be used by different functions at different times on a running system.
index 1fa9074..502399e 100644 (file)
@@ -503,7 +503,7 @@ F:  include/linux/altera_uart.h
 F:     include/linux/altera_jtaguart.h
 
 AMD FAM15H PROCESSOR POWER MONITORING DRIVER
-M:     Andreas Herrmann <andreas.herrmann3@amd.com>
+M:     Andreas Herrmann <herrmann.der.user@googlemail.com>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/fam15h_power
@@ -2507,6 +2507,7 @@ M:        Joonyoung Shim <jy0922.shim@samsung.com>
 M:     Seung-Woo Kim <sw0312.kim@samsung.com>
 M:     Kyungmin Park <kyungmin.park@samsung.com>
 L:     dri-devel@lists.freedesktop.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git
 S:     Supported
 F:     drivers/gpu/drm/exynos
 F:     include/drm/exynos*
@@ -5638,6 +5639,12 @@ S:       Maintained
 F:     drivers/pinctrl/
 F:     include/linux/pinctrl/
 
+PIN CONTROLLER - ATMEL AT91
+M:     Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     drivers/pinctrl/pinctrl-at91.c
+
 PIN CONTROLLER - ST SPEAR
 M:     Viresh Kumar <viresh.linux@gmail.com>
 L:     spear-devel@list.st.com
@@ -5647,7 +5654,7 @@ S:        Maintained
 F:     drivers/pinctrl/spear/
 
 PKTCDVD DRIVER
-M:     Peter Osterlund <petero2@telia.com>
+M:     Jiri Kosina <jkosina@suse.cz>
 S:     Maintained
 F:     drivers/block/pktcdvd.c
 F:     include/linux/pktcdvd.h
index 42d0e56..6edac73 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 7
 SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc5
 NAME = Terrified Chipmunk
 
 # *DOCUMENTATION*
index ade7e92..a18cfef 100644 (file)
@@ -330,6 +330,8 @@ config ARCH_AT91
        select IRQ_DOMAIN
        select NEED_MACH_GPIO_H
        select NEED_MACH_IO_H if PCCARD
+       select PINCTRL
+       select PINCTRL_AT91 if USE_OF
        help
          This enables support for systems based on Atmel
          AT91RM9200 and AT91SAM9* processors.
index f37cf9f..4ffed9a 100644 (file)
@@ -1,21 +1,33 @@
 ifeq ($(CONFIG_OF),y)
 
-dtb-$(CONFIG_ARCH_AT91) += aks-cdu.dtb \
-       at91sam9263ek.dtb \
-       at91sam9g20ek_2mmc.dtb \
-       at91sam9g20ek.dtb \
-       at91sam9g25ek.dtb \
-       at91sam9m10g45ek.dtb \
-       at91sam9n12ek.dtb \
-       ethernut5.dtb \
-       evk-pro3.dtb \
-       kizbox.dtb \
-       tny_a9260.dtb \
-       tny_a9263.dtb \
-       tny_a9g20.dtb \
-       usb_a9260.dtb \
-       usb_a9263.dtb \
-       usb_a9g20.dtb
+# Keep at91 dtb files sorted alphabetically for each SoC
+# sam9260
+dtb-$(CONFIG_ARCH_AT91) += aks-cdu.dtb
+dtb-$(CONFIG_ARCH_AT91) += ethernut5.dtb
+dtb-$(CONFIG_ARCH_AT91) += evk-pro3.dtb
+dtb-$(CONFIG_ARCH_AT91) += tny_a9260.dtb
+dtb-$(CONFIG_ARCH_AT91) += usb_a9260.dtb
+# sam9263
+dtb-$(CONFIG_ARCH_AT91) += at91sam9263ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += tny_a9263.dtb
+dtb-$(CONFIG_ARCH_AT91) += usb_a9263.dtb
+# sam9g20
+dtb-$(CONFIG_ARCH_AT91) += at91sam9g20ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += at91sam9g20ek_2mmc.dtb
+dtb-$(CONFIG_ARCH_AT91) += kizbox.dtb
+dtb-$(CONFIG_ARCH_AT91) += tny_a9g20.dtb
+dtb-$(CONFIG_ARCH_AT91) += usb_a9g20.dtb
+# sam9g45
+dtb-$(CONFIG_ARCH_AT91) += at91sam9m10g45ek.dtb
+# sam9n12
+dtb-$(CONFIG_ARCH_AT91) += at91sam9n12ek.dtb
+# sam9x5
+dtb-$(CONFIG_ARCH_AT91) += at91sam9g15ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += at91sam9g25ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += at91sam9g35ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += at91sam9x25ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += at91sam9x35ek.dtb
+
 dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb
 dtb-$(CONFIG_ARCH_DOVE) += dove-cm-a510.dtb \
        dove-cubox.dtb \
index d410581..9a24ffb 100644 (file)
                                interrupts = <26 4 0 27 4 0 28 4 0>;
                        };
 
-                       pioA: gpio@fffff400 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffff400 0x100>;
-                               interrupts = <2 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                       pinctrl@fffff400 {
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+                               ranges = <0xfffff400 0xfffff400 0x600>;
+
+                               atmel,mux-mask = <
+                                     /*    A         B     */
+                                      0xffffffff 0xffc00c3b  /* pioA */
+                                      0xffffffff 0x7fff3ccf  /* pioB */
+                                      0xffffffff 0x007fffff  /* pioC */
+                                     >;
+
+                               /* shared pinctrl settings */
+                               dbgu {
+                                       pinctrl_dbgu: dbgu-0 {
+                                               atmel,pins =
+                                                       <1 14 0x1 0x0   /* PB14 periph A */
+                                                        1 15 0x1 0x1>; /* PB15 periph with pullup */
+                                       };
+                               };
 
-                       pioB: gpio@fffff600 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffff600 0x100>;
-                               interrupts = <3 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                               uart0 {
+                                       pinctrl_uart0: uart0-0 {
+                                               atmel,pins =
+                                                       <1 4 0x1 0x0    /* PB4 periph A */
+                                                        1 5 0x1 0x0>;  /* PB5 periph A */
+                                       };
+
+                                       pinctrl_uart0_rts_cts: uart0_rts_cts-0 {
+                                               atmel,pins =
+                                                       <1 26 0x1 0x0   /* PB26 periph A */
+                                                        1 27 0x1 0x0>; /* PB27 periph A */
+                                       };
+
+                                       pinctrl_uart0_dtr_dsr: uart0_dtr_dsr-0 {
+                                               atmel,pins =
+                                                       <1 24 0x1 0x0   /* PB24 periph A */
+                                                        1 22 0x1 0x0>; /* PB22 periph A */
+                                       };
+
+                                       pinctrl_uart0_dcd: uart0_dcd-0 {
+                                               atmel,pins =
+                                                       <1 23 0x1 0x0>; /* PB23 periph A */
+                                       };
+
+                                       pinctrl_uart0_ri: uart0_ri-0 {
+                                               atmel,pins =
+                                                       <1 25 0x1 0x0>; /* PB25 periph A */
+                                       };
+                               };
 
-                       pioC: gpio@fffff800 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffff800 0x100>;
-                               interrupts = <4 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
+                               uart1 {
+                                       pinctrl_uart1: uart1-0 {
+                                               atmel,pins =
+                                                       <2 6 0x1 0x1    /* PB6 periph A with pullup */
+                                                        2 7 0x1 0x0>;  /* PB7 periph A */
+                                       };
+
+                                       pinctrl_uart1_rts_cts: uart1_rts_cts-0 {
+                                               atmel,pins =
+                                                       <1 28 0x1 0x0   /* PB28 periph A */
+                                                        1 29 0x1 0x0>; /* PB29 periph A */
+                                       };
+                               };
+
+                               uart2 {
+                                       pinctrl_uart2: uart2-0 {
+                                               atmel,pins =
+                                                       <1 8 0x1 0x1    /* PB8 periph A with pullup */
+                                                        1 9 0x1 0x0>;  /* PB9 periph A */
+                                       };
+
+                                       pinctrl_uart2_rts_cts: uart2_rts_cts-0 {
+                                               atmel,pins =
+                                                       <0 4 0x1 0x0    /* PA4 periph A */
+                                                        0 5 0x1 0x0>;  /* PA5 periph A */
+                                       };
+                               };
+
+                               uart3 {
+                                       pinctrl_uart3: uart3-0 {
+                                               atmel,pins =
+                                                       <2 10 0x1 0x1   /* PB10 periph A with pullup */
+                                                        2 11 0x1 0x0>; /* PB11 periph A */
+                                       };
+
+                                       pinctrl_uart3_rts_cts: uart3_rts_cts-0 {
+                                               atmel,pins =
+                                                       <3 8 0x2 0x0    /* PB8 periph B */
+                                                        3 10 0x2 0x0>; /* PB10 periph B */
+                                       };
+                               };
+
+                               uart4 {
+                                       pinctrl_uart4: uart4-0 {
+                                               atmel,pins =
+                                                       <0 31 0x2 0x1   /* PA31 periph B with pullup */
+                                                        0 30 0x2 0x0>; /* PA30 periph B */
+                                       };
+                               };
+
+                               uart5 {
+                                       pinctrl_uart5: uart5-0 {
+                                               atmel,pins =
+                                                       <2 12 0x1 0x1   /* PB12 periph A with pullup */
+                                                        2 13 0x1 0x0>; /* PB13 periph A */
+                                       };
+                               };
+
+                               nand {
+                                       pinctrl_nand: nand-0 {
+                                               atmel,pins =
+                                                       <2 13 0x0 0x1   /* PC13 gpio RDY pin pull_up */
+                                                        2 14 0x0 0x1>; /* PC14 gpio enable pin pull_up */
+                                       };
+                               };
+
+                               pioA: gpio@fffff400 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff400 0x200>;
+                                       interrupts = <2 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioB: gpio@fffff600 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff600 0x200>;
+                                       interrupts = <3 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioC: gpio@fffff800 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff800 0x200>;
+                                       interrupts = <4 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
                        };
 
                        dbgu: serial@fffff200 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffff200 0x200>;
                                interrupts = <1 4 7>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_dbgu>;
                                status = "disabled";
                        };
 
                                interrupts = <6 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart0>;
                                status = "disabled";
                        };
 
                                interrupts = <7 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart1>;
                                status = "disabled";
                        };
 
                                interrupts = <8 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart2>;
                                status = "disabled";
                        };
 
                                interrupts = <23 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart3>;
                                status = "disabled";
                        };
 
                                interrupts = <24 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart4>;
                                status = "disabled";
                        };
 
                                interrupts = <25 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart5>;
                                status = "disabled";
                        };
 
                              >;
                        atmel,nand-addr-offset = <21>;
                        atmel,nand-cmd-offset = <22>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_nand>;
                        gpios = <&pioC 13 0
                                 &pioC 14 0
                                 0
index 3e6e5c1..251ccec 100644 (file)
                                reg = <0xfffffd10 0x10>;
                        };
 
-                       pioA: gpio@fffff200 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffff200 0x100>;
-                               interrupts = <2 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                       pinctrl@fffff200 {
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+                               ranges = <0xfffff200 0xfffff200 0xa00>;
 
-                       pioB: gpio@fffff400 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffff400 0x100>;
-                               interrupts = <3 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                               atmel,mux-mask = <
+                                     /*    A         B     */
+                                      0xfffffffb 0xffffe07f  /* pioA */
+                                      0x0007ffff 0x39072fff  /* pioB */
+                                      0xffffffff 0x3ffffff8  /* pioC */
+                                      0xfffffbff 0xffffffff  /* pioD */
+                                      0xffe00fff 0xfbfcff00  /* pioE */
+                                     >;
 
-                       pioC: gpio@fffff600 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffff600 0x100>;
-                               interrupts = <4 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                               /* shared pinctrl settings */
+                               dbgu {
+                                       pinctrl_dbgu: dbgu-0 {
+                                               atmel,pins =
+                                                       <2 30 0x1 0x0   /* PC30 periph A */
+                                                        2 31 0x1 0x1>; /* PC31 periph with pullup */
+                                       };
+                               };
 
-                       pioD: gpio@fffff800 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffff800 0x100>;
-                               interrupts = <4 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                               uart0 {
+                                       pinctrl_uart0: uart0-0 {
+                                               atmel,pins =
+                                                       <0 26 0x1 0x1   /* PA26 periph A with pullup */
+                                                        0 27 0x1 0x0>; /* PA27 periph A */
+                                       };
 
-                       pioE: gpio@fffffa00 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffffa00 0x100>;
-                               interrupts = <4 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
+                                       pinctrl_uart0_rts_cts: uart0_rts_cts-0 {
+                                               atmel,pins =
+                                                       <0 28 0x1 0x0   /* PA28 periph A */
+                                                        0 29 0x1 0x0>; /* PA29 periph A */
+                                       };
+                               };
+
+                               uart1 {
+                                       pinctrl_uart1: uart1-0 {
+                                               atmel,pins =
+                                                       <3 0 0x1 0x1    /* PD0 periph A with pullup */
+                                                        3 1 0x1 0x0>;  /* PD1 periph A */
+                                       };
+
+                                       pinctrl_uart1_rts_cts: uart1_rts_cts-0 {
+                                               atmel,pins =
+                                                       <3 7 0x2 0x0    /* PD7 periph B */
+                                                        3 8 0x2 0x0>;  /* PD8 periph B */
+                                       };
+                               };
+
+                               uart2 {
+                                       pinctrl_uart2: uart2-0 {
+                                               atmel,pins =
+                                                       <3 2 0x1 0x1    /* PD2 periph A with pullup */
+                                                        3 3 0x1 0x0>;  /* PD3 periph A */
+                                       };
+
+                                       pinctrl_uart2_rts_cts: uart2_rts_cts-0 {
+                                               atmel,pins =
+                                                       <3 5 0x2 0x0    /* PD5 periph B */
+                                                        4 6 0x2 0x0>;  /* PD6 periph B */
+                                       };
+                               };
+
+                               nand {
+                                       pinctrl_nand: nand-0 {
+                                               atmel,pins =
+                                                       <0 22 0x0 0x1   /* PA22 gpio RDY pin pull_up*/
+                                                        3 15 0x0 0x1>; /* PD15 gpio enable pin pull_up */
+                                       };
+                               };
+
+                               pioA: gpio@fffff200 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff200 0x200>;
+                                       interrupts = <2 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioB: gpio@fffff400 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff400 0x200>;
+                                       interrupts = <3 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioC: gpio@fffff600 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff600 0x200>;
+                                       interrupts = <4 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioD: gpio@fffff800 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff800 0x200>;
+                                       interrupts = <4 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioE: gpio@fffffa00 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffffa00 0x200>;
+                                       interrupts = <4 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
                        };
 
                        dbgu: serial@ffffee00 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xffffee00 0x200>;
                                interrupts = <1 4 7>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_dbgu>;
                                status = "disabled";
                        };
 
                                interrupts = <7 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart0>;
                                status = "disabled";
                        };
 
                                interrupts = <8 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart1>;
                                status = "disabled";
                        };
 
                                interrupts = <9 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart2>;
                                status = "disabled";
                        };
 
                              >;
                        atmel,nand-addr-offset = <21>;
                        atmel,nand-cmd-offset = <22>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_nand>;
                        gpios = <&pioA 22 0
                                 &pioD 15 0
                                 0
index f86ac4b..7cfe9d5 100644 (file)
@@ -38,6 +38,7 @@
                        };
 
                        usart0: serial@fff8c000 {
+                               pinctrl-0 = <&pinctrl_uart0 &pinctrl_uart0_rts_cts>;
                                status = "okay";
                        };
 
diff --git a/arch/arm/boot/dts/at91sam9g15.dtsi b/arch/arm/boot/dts/at91sam9g15.dtsi
new file mode 100644 (file)
index 0000000..fbe7a70
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * at91sam9g15.dtsi - Device Tree Include file for AT91SAM9G15 SoC
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/include/ "at91sam9x5.dtsi"
+
+/ {
+       model = "Atmel AT91SAM9G15 SoC";
+       compatible = "atmel, at91sam9g15, atmel,at91sam9x5";
+
+       ahb {
+               apb {
+                       pinctrl@fffff400 {
+                               atmel,mux-mask = <
+                                     /*    A         B          C     */
+                                      0xffffffff 0xffe0399f 0x00000000  /* pioA */
+                                      0x00040000 0x00047e3f 0x00000000  /* pioB */
+                                      0xfdffffff 0x00000000 0xb83fffff  /* pioC */
+                                      0x003fffff 0x003f8000 0x00000000  /* pioD */
+                                     >;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/at91sam9g15ek.dts b/arch/arm/boot/dts/at91sam9g15ek.dts
new file mode 100644 (file)
index 0000000..86dd3f6
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * at91sam9g15ek.dts - Device Tree file for AT91SAM9G15-EK board
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9g15.dtsi"
+/include/ "at91sam9x5ek.dtsi"
+
+/ {
+       model = "Atmel AT91SAM9G25-EK";
+       compatible = "atmel,at91sam9g15ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+};
index e6391a4..689323d 100644 (file)
                        };
 
                        usart0: serial@fffb0000 {
+                               pinctrl-0 =
+                                       <&pinctrl_uart0
+                                        &pinctrl_uart0_rts_cts
+                                        &pinctrl_uart0_dtr_dsr
+                                        &pinctrl_uart0_dcd
+                                        &pinctrl_uart0_ri>;
                                status = "okay";
                        };
 
diff --git a/arch/arm/boot/dts/at91sam9g25.dtsi b/arch/arm/boot/dts/at91sam9g25.dtsi
new file mode 100644 (file)
index 0000000..05a718f
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * at91sam9g25.dtsi - Device Tree Include file for AT91SAM9G25 SoC
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/include/ "at91sam9x5.dtsi"
+
+/ {
+       model = "Atmel AT91SAM9G25 SoC";
+       compatible = "atmel, at91sam9g25, atmel,at91sam9x5";
+
+       ahb {
+               apb {
+                       pinctrl@fffff400 {
+                               atmel,mux-mask = <
+                                     /*    A         B          C     */
+                                      0xffffffff 0xffe0399f 0xc000001c  /* pioA */
+                                      0x0007ffff 0x8000fe3f 0x00000000  /* pioB */
+                                      0x80000000 0x07c0ffff 0xb83fffff  /* pioC */
+                                      0x003fffff 0x003f8000 0x00000000  /* pioD */
+                                     >;
+                       };
+               };
+       };
+};
index 877c08f..c5ab16f 100644 (file)
@@ -7,55 +7,10 @@
  * Licensed under GPLv2 or later.
  */
 /dts-v1/;
-/include/ "at91sam9x5.dtsi"
-/include/ "at91sam9x5cm.dtsi"
+/include/ "at91sam9g25.dtsi"
+/include/ "at91sam9x5ek.dtsi"
 
 / {
        model = "Atmel AT91SAM9G25-EK";
        compatible = "atmel,at91sam9g25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
-
-       chosen {
-               bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
-       };
-
-       ahb {
-               apb {
-                       dbgu: serial@fffff200 {
-                               status = "okay";
-                       };
-
-                       usart0: serial@f801c000 {
-                               status = "okay";
-                       };
-
-                       macb0: ethernet@f802c000 {
-                               phy-mode = "rmii";
-                               status = "okay";
-                       };
-
-                       i2c0: i2c@f8010000 {
-                               status = "okay";
-                       };
-
-                       i2c1: i2c@f8014000 {
-                               status = "okay";
-                       };
-
-                       i2c2: i2c@f8018000 {
-                               status = "okay";
-                       };
-               };
-
-               usb0: ohci@00600000 {
-                       status = "okay";
-                       num-ports = <2>;
-                       atmel,vbus-gpio = <&pioD 19 1
-                                          &pioD 20 1
-                                         >;
-               };
-
-               usb1: ehci@00700000 {
-                       status = "okay";
-               };
-       };
 };
diff --git a/arch/arm/boot/dts/at91sam9g35.dtsi b/arch/arm/boot/dts/at91sam9g35.dtsi
new file mode 100644 (file)
index 0000000..f9d14a7
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * at91sam9g35.dtsi - Device Tree Include file for AT91SAM9G35 SoC
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/include/ "at91sam9x5.dtsi"
+
+/ {
+       model = "Atmel AT91SAM9G35 SoC";
+       compatible = "atmel, at91sam9g35, atmel,at91sam9x5";
+
+       ahb {
+               apb {
+                       pinctrl@fffff400 {
+                               atmel,mux-mask = <
+                                     /*    A         B          C     */
+                                      0xffffffff 0xffe0399f 0xc000000c  /* pioA */
+                                      0x000406ff 0x00047e3f 0x00000000  /* pioB */
+                                      0xfdffffff 0x00000000 0xb83fffff  /* pioC */
+                                      0x003fffff 0x003f8000 0x00000000  /* pioD */
+                                     >;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts
new file mode 100644 (file)
index 0000000..95944bd
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * at91sam9g35ek.dts - Device Tree file for AT91SAM9G35-EK board
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9g35.dtsi"
+/include/ "at91sam9x5ek.dtsi"
+
+/ {
+       model = "Atmel AT91SAM9G35-EK";
+       compatible = "atmel,at91sam9g35ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+};
index 3add030..c340f66 100644 (file)
                                interrupts = <21 4 0>;
                        };
 
-                       pioA: gpio@fffff200 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffff200 0x100>;
-                               interrupts = <2 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                       pinctrl@fffff200 {
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+                               ranges = <0xfffff200 0xfffff200 0xa00>;
+
+                               atmel,mux-mask = <
+                                     /*    A         B     */
+                                      0xffffffff 0xffc003ff  /* pioA */
+                                      0xffffffff 0x800f8f00  /* pioB */
+                                      0xffffffff 0x00000e00  /* pioC */
+                                      0xffffffff 0xff0c1381  /* pioD */
+                                      0xffffffff 0x81ffff81  /* pioE */
+                                     >;
+
+                               /* shared pinctrl settings */
+                               dbgu {
+                                       pinctrl_dbgu: dbgu-0 {
+                                               atmel,pins =
+                                                       <1 12 0x1 0x0   /* PB12 periph A */
+                                                        1 13 0x1 0x0>; /* PB13 periph A */
+                                       };
+                               };
 
-                       pioB: gpio@fffff400 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffff400 0x100>;
-                               interrupts = <3 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                               uart0 {
+                                       pinctrl_uart0: uart0-0 {
+                                               atmel,pins =
+                                                       <1 19 0x1 0x1   /* PB19 periph A with pullup */
+                                                        1 18 0x1 0x0>; /* PB18 periph A */
+                                       };
+
+                                       pinctrl_uart0_rts_cts: uart0_rts_cts-0 {
+                                               atmel,pins =
+                                                       <1 17 0x2 0x0   /* PB17 periph B */
+                                                        1 15 0x2 0x0>; /* PB15 periph B */
+                                       };
+                               };
 
-                       pioC: gpio@fffff600 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffff600 0x100>;
-                               interrupts = <4 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                               uart1 {
+                                       pinctrl_uart1: uart1-0 {
+                                               atmel,pins =
+                                                       <1 4 0x1 0x1    /* PB4 periph A with pullup */
+                                                        1 5 0x1 0x0>;  /* PB5 periph A */
+                                       };
+
+                                       pinctrl_uart1_rts_cts: uart1_rts_cts-0 {
+                                               atmel,pins =
+                                                       <3 16 0x1 0x0   /* PD16 periph A */
+                                                        3 17 0x1 0x0>; /* PD17 periph A */
+                                       };
+                               };
 
-                       pioD: gpio@fffff800 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffff800 0x100>;
-                               interrupts = <5 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                               uart2 {
+                                       pinctrl_uart2: uart2-0 {
+                                               atmel,pins =
+                                                       <1 6 0x1 0x1    /* PB6 periph A with pullup */
+                                                        1 7 0x1 0x0>;  /* PB7 periph A */
+                                       };
+
+                                       pinctrl_uart2_rts_cts: uart2_rts_cts-0 {
+                                               atmel,pins =
+                                                       <2 9 0x2 0x0    /* PC9 periph B */
+                                                        2 11 0x2 0x0>; /* PC11 periph B */
+                                       };
+                               };
 
-                       pioE: gpio@fffffa00 {
-                               compatible = "atmel,at91rm9200-gpio";
-                               reg = <0xfffffa00 0x100>;
-                               interrupts = <5 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
+                               uart3 {
+                                       pinctrl_uart3: uart3-0 {
+                                               atmel,pins =
+                                                       <1 8 0x1 0x1    /* PB9 periph A with pullup */
+                                                        1 9 0x1 0x0>;  /* PB8 periph A */
+                                       };
+
+                                       pinctrl_uart3_rts_cts: uart3_rts_cts-0 {
+                                               atmel,pins =
+                                                       <0 23 0x2 0x0   /* PA23 periph B */
+                                                        0 24 0x2 0x0>; /* PA24 periph B */
+                                       };
+                               };
+
+                               nand {
+                                       pinctrl_nand: nand-0 {
+                                               atmel,pins =
+                                                       <2 8 0x0 0x1    /* PC8 gpio RDY pin pull_up*/
+                                                        2 14 0x0 0x1>; /* PC14 gpio enable pin pull_up */
+                                       };
+                               };
+
+                               pioA: gpio@fffff200 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff200 0x200>;
+                                       interrupts = <2 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioB: gpio@fffff400 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff400 0x200>;
+                                       interrupts = <3 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioC: gpio@fffff600 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff600 0x200>;
+                                       interrupts = <4 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioD: gpio@fffff800 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff800 0x200>;
+                                       interrupts = <5 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioE: gpio@fffffa00 {
+                                       compatible = "atmel,at91rm9200-gpio";
+                                       reg = <0xfffffa00 0x200>;
+                                       interrupts = <5 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
                        };
 
                        dbgu: serial@ffffee00 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xffffee00 0x200>;
                                interrupts = <1 4 7>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_dbgu>;
                                status = "disabled";
                        };
 
                                interrupts = <7 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart0>;
                                status = "disabled";
                        };
 
                                interrupts = <8 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart1>;
                                status = "disabled";
                        };
 
                                interrupts = <9 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart2>;
                                status = "disabled";
                        };
 
                                interrupts = <10 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart3>;
                                status = "disabled";
                        };
 
                              >;
                        atmel,nand-addr-offset = <21>;
                        atmel,nand-cmd-offset = <22>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_nand>;
                        gpios = <&pioC 8 0
                                 &pioC 14 0
                                 0
index 15e1dd4..6aa28b9 100644 (file)
@@ -39,6 +39,7 @@
                        };
 
                        usart1: serial@fff90000 {
+                               pinctrl-0 = <&pinctrl_uart0 &pinctrl_uart1_rts_cts>;
                                status = "okay";
                        };
 
index 82508d6..7b644c5 100644 (file)
                                interrupts = <20 4 0>;
                        };
 
-                       pioA: gpio@fffff400 {
-                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-                               reg = <0xfffff400 0x100>;
-                               interrupts = <2 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                       pinctrl@fffff400 {
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
+                               ranges = <0xfffff400 0xfffff400 0x800>;
 
-                       pioB: gpio@fffff600 {
-                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-                               reg = <0xfffff600 0x100>;
-                               interrupts = <2 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                               atmel,mux-mask = <
+                                     /*    A         B          C     */
+                                      0xffffffff 0xffe07983 0x00000000  /* pioA */
+                                      0x00040000 0x00047e0f 0x00000000  /* pioB */
+                                      0xfdffffff 0x07c00000 0xb83fffff  /* pioC */
+                                      0x003fffff 0x003f8000 0x00000000  /* pioD */
+                                     >;
 
-                       pioC: gpio@fffff800 {
-                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-                               reg = <0xfffff800 0x100>;
-                               interrupts = <3 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                               /* shared pinctrl settings */
+                               dbgu {
+                                       pinctrl_dbgu: dbgu-0 {
+                                               atmel,pins =
+                                                       <0 9 0x1 0x0    /* PA9 periph A */
+                                                        0 10 0x1 0x1>; /* PA10 periph with pullup */
+                                       };
+                               };
 
-                       pioD: gpio@fffffa00 {
-                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-                               reg = <0xfffffa00 0x100>;
-                               interrupts = <3 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
+                               uart0 {
+                                       pinctrl_uart0: uart0-0 {
+                                               atmel,pins =
+                                                       <0 1 0x1 0x1    /* PA1 periph A with pullup */
+                                                        0 0 0x1 0x0>;  /* PA0 periph A */
+                                       };
+
+                                       pinctrl_uart0_rts_cts: uart0_rts_cts-0 {
+                                               atmel,pins =
+                                                       <0 2 0x1 0x0    /* PA2 periph A */
+                                                        0 3 0x1 0x0>;  /* PA3 periph A */
+                                       };
+                               };
+
+                               uart1 {
+                                       pinctrl_uart1: uart1-0 {
+                                               atmel,pins =
+                                                       <0 6 0x1 0x1    /* PA6 periph A with pullup */
+                                                        0 5 0x1 0x0>;  /* PA5 periph A */
+                                       };
+                               };
+
+                               uart2 {
+                                       pinctrl_uart2: uart2-0 {
+                                               atmel,pins =
+                                                       <0 8 0x1 0x1    /* PA8 periph A with pullup */
+                                                        0 7 0x1 0x0>;  /* PA7 periph A */
+                                       };
+
+                                       pinctrl_uart2_rts_cts: uart2_rts_cts-0 {
+                                               atmel,pins =
+                                                       <1 0 0x2 0x0    /* PB0 periph B */
+                                                        1 1 0x2 0x0>;  /* PB1 periph B */
+                                       };
+                               };
+
+                               uart3 {
+                                       pinctrl_uart3: uart3-0 {
+                                               atmel,pins =
+                                                       <2 23 0x2 0x1   /* PC23 periph B with pullup */
+                                                        2 22 0x2 0x0>; /* PC22 periph B */
+                                       };
+
+                                       pinctrl_uart3_rts_cts: uart3_rts_cts-0 {
+                                               atmel,pins =
+                                                       <2 24 0x2 0x0   /* PC24 periph B */
+                                                        2 25 0x2 0x0>; /* PC25 periph B */
+                                       };
+                               };
+
+                               usart0 {
+                                       pinctrl_usart0: usart0-0 {
+                                               atmel,pins =
+                                                       <2 9 0x3 0x1    /* PC9 periph C with pullup */
+                                                        2 8 0x3 0x0>;  /* PC8 periph C */
+                                       };
+                               };
+
+                               usart1 {
+                                       pinctrl_usart1: usart1-0 {
+                                               atmel,pins =
+                                                       <2 16 0x3 0x1   /* PC17 periph C with pullup */
+                                                        2 17 0x3 0x0>; /* PC16 periph C */
+                                       };
+                               };
+
+                               nand {
+                                       pinctrl_nand: nand-0 {
+                                               atmel,pins =
+                                                       <3 5 0x0 0x1    /* PD5 gpio RDY pin pull_up*/
+                                                        3 4 0x0 0x1>;  /* PD4 gpio enable pin pull_up */
+                                       };
+                               };
+
+                               pioA: gpio@fffff400 {
+                                       compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff400 0x200>;
+                                       interrupts = <2 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioB: gpio@fffff600 {
+                                       compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff600 0x200>;
+                                       interrupts = <2 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioC: gpio@fffff800 {
+                                       compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff800 0x200>;
+                                       interrupts = <3 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioD: gpio@fffffa00 {
+                                       compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+                                       reg = <0xfffffa00 0x200>;
+                                       interrupts = <3 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
                        };
 
                        dbgu: serial@fffff200 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffff200 0x200>;
                                interrupts = <1 4 7>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_dbgu>;
                                status = "disabled";
                        };
 
                                interrupts = <5 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart0>;
                                status = "disabled";
                        };
 
                                interrupts = <6 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart1>;
                                status = "disabled";
                        };
 
                                interrupts = <7 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart2>;
                                status = "disabled";
                        };
 
                                interrupts = <8 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart3>;
                                status = "disabled";
                        };
 
                               >;
                        atmel,nand-addr-offset = <21>;
                        atmel,nand-cmd-offset = <22>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_nand>;
                        gpios = <&pioD 5 0
                                 &pioD 4 0
                                 0
diff --git a/arch/arm/boot/dts/at91sam9x25.dtsi b/arch/arm/boot/dts/at91sam9x25.dtsi
new file mode 100644 (file)
index 0000000..956c65f
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * at91sam9x25.dtsi - Device Tree Include file for AT91SAM9X25 SoC
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/include/ "at91sam9x5.dtsi"
+
+/ {
+       model = "Atmel AT91SAM9X25 SoC";
+       compatible = "atmel, at91sam9x25, atmel,at91sam9x5";
+
+       ahb {
+               apb {
+                       pinctrl@fffff400 {
+                               atmel,mux-mask = <
+                                     /*    A         B          C     */
+                                      0xffffffff 0xffe03fff 0xc000001c  /* pioA */
+                                      0x0007ffff 0x00047e3f 0x00000000  /* pioB */
+                                      0x80000000 0xfffd0000 0xb83fffff  /* pioC */
+                                      0x003fffff 0x003f8000 0x00000000  /* pioD */
+                                     >;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/at91sam9x25ek.dts b/arch/arm/boot/dts/at91sam9x25ek.dts
new file mode 100644 (file)
index 0000000..af907ea
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * at91sam9x25ek.dts - Device Tree file for AT91SAM9X25-EK board
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9x25.dtsi"
+/include/ "at91sam9x5ek.dtsi"
+
+/ {
+       model = "Atmel AT91SAM9G25-EK";
+       compatible = "atmel,at91sam9x25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+};
diff --git a/arch/arm/boot/dts/at91sam9x35.dtsi b/arch/arm/boot/dts/at91sam9x35.dtsi
new file mode 100644 (file)
index 0000000..fb102d6
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * at91sam9x35.dtsi - Device Tree Include file for AT91SAM9X35 SoC
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/include/ "at91sam9x5.dtsi"
+
+/ {
+       model = "Atmel AT91SAM9X35 SoC";
+       compatible = "atmel, at91sam9x35, atmel,at91sam9x5";
+
+       ahb {
+               apb {
+                       pinctrl@fffff400 {
+                               atmel,mux-mask = <
+                                     /*    A         B          C     */
+                                      0xffffffff 0xffe03fff 0xc000000c  /* pioA */
+                                      0x000406ff 0x00047e3f 0x00000000  /* pioB */
+                                      0xfdffffff 0x00000000 0xb83fffff  /* pioC */
+                                      0x003fffff 0x003f8000 0x00000000  /* pioD */
+                                     >;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/at91sam9x35ek.dts b/arch/arm/boot/dts/at91sam9x35ek.dts
new file mode 100644 (file)
index 0000000..5ccb607
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * at91sam9x35ek.dts - Device Tree file for AT91SAM9X35-EK board
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9x35.dtsi"
+/include/ "at91sam9x5ek.dtsi"
+
+/ {
+       model = "Atmel AT91SAM9X35-EK";
+       compatible = "atmel,at91sam9x35ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+};
index 03fc136..6a40b77 100644 (file)
                                interrupts = <21 4 0>;
                        };
 
-                       pioA: gpio@fffff400 {
-                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-                               reg = <0xfffff400 0x100>;
-                               interrupts = <2 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                       pinctrl@fffff400 {
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
+                               ranges = <0xfffff400 0xfffff400 0x800>;
+
+                               /* shared pinctrl settings */
+                               dbgu {
+                                       pinctrl_dbgu: dbgu-0 {
+                                               atmel,pins =
+                                                       <0 9 0x1 0x0    /* PA9 periph A */
+                                                        0 10 0x1 0x1>; /* PA10 periph A with pullup */
+                                       };
+                               };
 
-                       pioB: gpio@fffff600 {
-                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-                               reg = <0xfffff600 0x100>;
-                               interrupts = <2 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                               uart0 {
+                                       pinctrl_uart0: uart0-0 {
+                                               atmel,pins =
+                                                       <0 0 0x1 0x1    /* PA0 periph A with pullup */
+                                                        0 1 0x1 0x0>;  /* PA1 periph A */
+                                       };
+
+                                       pinctrl_uart0_rts_cts: uart0_rts_cts-0 {
+                                               atmel,pins =
+                                                       <0 2 0x1 0x0    /* PA2 periph A */
+                                                        0 3 0x1 0x0>;  /* PA3 periph A */
+                                       };
+                               };
 
-                       pioC: gpio@fffff800 {
-                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-                               reg = <0xfffff800 0x100>;
-                               interrupts = <3 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
+                               uart1 {
+                                       pinctrl_uart1: uart1-0 {
+                                               atmel,pins =
+                                                       <0 5 0x1 0x1    /* PA5 periph A with pullup */
+                                                        0 6 0x1 0x0>;  /* PA6 periph A */
+                                       };
+
+                                       pinctrl_uart1_rts_cts: uart1_rts_cts-0 {
+                                               atmel,pins =
+                                                       <3 27 0x3 0x0   /* PC27 periph C */
+                                                        3 28 0x3 0x0>; /* PC28 periph C */
+                                       };
+                               };
 
-                       pioD: gpio@fffffa00 {
-                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-                               reg = <0xfffffa00 0x100>;
-                               interrupts = <3 4 1>;
-                               #gpio-cells = <2>;
-                               gpio-controller;
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
+                               uart2 {
+                                       pinctrl_uart2: uart2-0 {
+                                               atmel,pins =
+                                                       <0 7 0x1 0x1    /* PA7 periph A with pullup */
+                                                        0 8 0x1 0x0>;  /* PA8 periph A */
+                                       };
+
+                                       pinctrl_uart2_rts_cts: uart2_rts_cts-0 {
+                                               atmel,pins =
+                                                       <0 0 0x2 0x0    /* PB0 periph B */
+                                                        0 1 0x2 0x0>;  /* PB1 periph B */
+                                       };
+                               };
+
+                               uart3 {
+                                       pinctrl_uart3: uart3-0 {
+                                               atmel,pins =
+                                                       <3 23 0x2 0x1   /* PC22 periph B with pullup */
+                                                        3 23 0x2 0x0>; /* PC23 periph B */
+                                       };
+
+                                       pinctrl_uart3_rts_cts: uart3_rts_cts-0 {
+                                               atmel,pins =
+                                                       <3 24 0x2 0x0   /* PC24 periph B */
+                                                        3 25 0x2 0x0>; /* PC25 periph B */
+                                       };
+                               };
+
+                               usart0 {
+                                       pinctrl_usart0: usart0-0 {
+                                               atmel,pins =
+                                                       <3 8 0x3 0x0    /* PC8 periph C */
+                                                        3 9 0x3 0x1>;  /* PC9 periph C with pullup */
+                                       };
+                               };
+
+                               usart1 {
+                                       pinctrl_usart1: usart1-0 {
+                                               atmel,pins =
+                                                       <3 16 0x3 0x0   /* PC16 periph C */
+                                                        3 17 0x3 0x1>; /* PC17 periph C with pullup */
+                                       };
+                               };
+
+                               nand {
+                                       pinctrl_nand: nand-0 {
+                                               atmel,pins =
+                                                       <3 4 0x0 0x1    /* PD5 gpio RDY pin pull_up */
+                                                        3 5 0x0 0x1>;  /* PD4 gpio enable pin pull_up */
+                                       };
+                               };
+
+                               pioA: gpio@fffff400 {
+                                       compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff400 0x200>;
+                                       interrupts = <2 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioB: gpio@fffff600 {
+                                       compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff600 0x200>;
+                                       interrupts = <2 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       #gpio-lines = <19>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioC: gpio@fffff800 {
+                                       compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+                                       reg = <0xfffff800 0x200>;
+                                       interrupts = <3 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
+
+                               pioD: gpio@fffffa00 {
+                                       compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+                                       reg = <0xfffffa00 0x200>;
+                                       interrupts = <3 4 1>;
+                                       #gpio-cells = <2>;
+                                       gpio-controller;
+                                       #gpio-lines = <22>;
+                                       interrupt-controller;
+                                       #interrupt-cells = <2>;
+                               };
                        };
 
                        dbgu: serial@fffff200 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffff200 0x200>;
                                interrupts = <1 4 7>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_dbgu>;
                                status = "disabled";
                        };
 
                                interrupts = <5 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart0>;
                                status = "disabled";
                        };
 
                                interrupts = <6 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart1>;
                                status = "disabled";
                        };
 
                                interrupts = <7 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_uart2>;
                                status = "disabled";
                        };
 
                              >;
                        atmel,nand-addr-offset = <21>;
                        atmel,nand-cmd-offset = <22>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_nand>;
                        gpios = <&pioD 5 0
                                 &pioD 4 0
                                 0
diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi
new file mode 100644 (file)
index 0000000..cc9730c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * at91sam9x5ek.dtsi - Device Tree file for AT91SAM9x5CM Base board
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/include/ "at91sam9x5cm.dtsi"
+
+/ {
+       model = "Atmel AT91SAM9X5-EK";
+       compatible = "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+
+       chosen {
+               bootargs = "128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
+       };
+
+       ahb {
+               apb {
+                       dbgu: serial@fffff200 {
+                               status = "okay";
+                       };
+
+                       usart0: serial@f801c000 {
+                               status = "okay";
+                       };
+
+                       macb0: ethernet@f802c000 {
+                               phy-mode = "rmii";
+                               status = "okay";
+                       };
+
+                       i2c0: i2c@f8010000 {
+                               status = "okay";
+                       };
+
+                       i2c1: i2c@f8014000 {
+                               status = "okay";
+                       };
+
+                       i2c2: i2c@f8018000 {
+                               status = "okay";
+                       };
+               };
+
+               usb0: ohci@00600000 {
+                       status = "okay";
+                       num-ports = <2>;
+                       atmel,vbus-gpio = <&pioD 19 1
+                                          &pioD 20 1
+                                         >;
+               };
+
+               usb1: ehci@00700000 {
+                       status = "okay";
+               };
+       };
+};
index dd4358b..2e4c572 100644 (file)
                               status = "okay";
                        };
 
+                       gpio@d8400000 {
+                              status = "okay";
+                       };
+
                        i2c0: i2c@e0280000 {
                               status = "okay";
                        };
index 419ea74..7cd25eb 100644 (file)
                        status = "disabled";
                };
 
+               pinmux: pinmux@e0700000 {
+                       compatible = "st,spear1310-pinmux";
+                       reg = <0xe0700000 0x1000>;
+                       #gpio-range-cells = <2>;
+               };
+
                spi1: spi@5d400000 {
                        compatible = "arm,pl022", "arm,primecell";
                        reg = <0x5d400000 0x1000>;
                        thermal@e07008c4 {
                                st,thermal-flags = <0x7000>;
                        };
+
+                       gpiopinctrl: gpio@d8400000 {
+                               compatible = "st,spear-plgpio";
+                               reg = <0xd8400000 0x1000>;
+                               interrupts = <0 100 0x4>;
+                               #interrupt-cells = <1>;
+                               interrupt-controller;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               gpio-ranges = <&pinmux 0 246>;
+                               status = "disabled";
+
+                               st-plgpio,ngpio = <246>;
+                               st-plgpio,enb-reg = <0xd0>;
+                               st-plgpio,wdata-reg = <0x90>;
+                               st-plgpio,dir-reg = <0xb0>;
+                               st-plgpio,ie-reg = <0x30>;
+                               st-plgpio,rdata-reg = <0x70>;
+                               st-plgpio,mis-reg = <0x10>;
+                               st-plgpio,eit-reg = <0x50>;
+                       };
                };
        };
 };
index c9a54e0..045f712 100644 (file)
                               status = "okay";
                        };
 
+                       gpio@e2800000 {
+                              status = "okay";
+                       };
+
                        i2c0: i2c@e0280000 {
                               status = "okay";
                        };
index d71fe2a..6c09eb0 100644 (file)
                        status = "disabled";
                };
 
+               pinmux: pinmux@e0700000 {
+                       compatible = "st,spear1340-pinmux";
+                       reg = <0xe0700000 0x1000>;
+                       #gpio-range-cells = <2>;
+               };
+
                spi1: spi@5d400000 {
                        compatible = "arm,pl022", "arm,primecell";
                        reg = <0x5d400000 0x1000>;
                        thermal@e07008c4 {
                                st,thermal-flags = <0x2a00>;
                        };
+
+                       gpiopinctrl: gpio@e2800000 {
+                               compatible = "st,spear-plgpio";
+                               reg = <0xe2800000 0x1000>;
+                               interrupts = <0 107 0x4>;
+                               #interrupt-cells = <1>;
+                               interrupt-controller;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               gpio-ranges = <&pinmux 0 252>;
+                               status = "disabled";
+
+                               st-plgpio,ngpio = <250>;
+                               st-plgpio,wdata-reg = <0x40>;
+                               st-plgpio,dir-reg = <0x00>;
+                               st-plgpio,ie-reg = <0x80>;
+                               st-plgpio,rdata-reg = <0x20>;
+                               st-plgpio,mis-reg = <0xa0>;
+                               st-plgpio,eit-reg = <0x60>;
+                       };
                };
        };
 };
index 62fc4fb..930303e 100644 (file)
                          0xb0000000 0xb0000000 0x10000000
                          0xd0000000 0xd0000000 0x30000000>;
 
-               pinmux@b4000000 {
+               pinmux: pinmux@b4000000 {
                        compatible = "st,spear310-pinmux";
                        reg = <0xb4000000 0x1000>;
+                       #gpio-range-cells = <2>;
                };
 
                fsmc: flash@44000000 {
                                reg = <0xb2200000 0x1000>;
                                status = "disabled";
                        };
+
+                       gpiopinctrl: gpio@b4000000 {
+                               compatible = "st,spear-plgpio";
+                               reg = <0xb4000000 0x1000>;
+                               #interrupt-cells = <1>;
+                               interrupt-controller;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               gpio-ranges = <&pinmux 0 102>;
+                               status = "disabled";
+
+                               st-plgpio,ngpio = <102>;
+                               st-plgpio,enb-reg = <0x10>;
+                               st-plgpio,wdata-reg = <0x20>;
+                               st-plgpio,dir-reg = <0x30>;
+                               st-plgpio,ie-reg = <0x50>;
+                               st-plgpio,rdata-reg = <0x40>;
+                               st-plgpio,mis-reg = <0x60>;
+                       };
                };
        };
 };
index 082328b..ad4bfc6 100644 (file)
                               status = "okay";
                        };
 
+                       gpio@b3000000 {
+                              status = "okay";
+                       };
+
                        i2c0: i2c@d0180000 {
                               status = "okay";
                        };
index 1f49d69..67d7ada 100644 (file)
                ranges = <0x40000000 0x40000000 0x80000000
                          0xd0000000 0xd0000000 0x30000000>;
 
-               pinmux@b3000000 {
+               pinmux: pinmux@b3000000 {
                        compatible = "st,spear320-pinmux";
                        reg = <0xb3000000 0x1000>;
+                       #gpio-range-cells = <2>;
                };
 
                clcd@90000000 {
                                reg = <0xa4000000 0x1000>;
                                status = "disabled";
                        };
+
+                       gpiopinctrl: gpio@b3000000 {
+                               compatible = "st,spear-plgpio";
+                               reg = <0xb3000000 0x1000>;
+                               #interrupt-cells = <1>;
+                               interrupt-controller;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               gpio-ranges = <&pinmux 0 102>;
+                               status = "disabled";
+
+                               st-plgpio,ngpio = <102>;
+                               st-plgpio,enb-reg = <0x24>;
+                               st-plgpio,wdata-reg = <0x34>;
+                               st-plgpio,dir-reg = <0x44>;
+                               st-plgpio,ie-reg = <0x64>;
+                               st-plgpio,rdata-reg = <0x54>;
+                               st-plgpio,mis-reg = <0x84>;
+                               st-plgpio,eit-reg = <0x94>;
+                       };
                };
        };
 };
index 67bc571..b175577 100644 (file)
@@ -111,6 +111,7 @@ CONFIG_I2C=y
 CONFIG_I2C_GPIO=y
 CONFIG_SPI=y
 CONFIG_SPI_ATMEL=y
+CONFIG_PINCTRL_AT91=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_AT91SAM9X_WATCHDOG=y
index 35c1ed8..42f042e 100644 (file)
@@ -64,7 +64,7 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
 static inline void __raw_writew(u16 val, volatile void __iomem *addr)
 {
        asm volatile("strh %1, %0"
-                    : "+Qo" (*(volatile u16 __force *)addr)
+                    : "+Q" (*(volatile u16 __force *)addr)
                     : "r" (val));
 }
 
@@ -72,7 +72,7 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
 {
        u16 val;
        asm volatile("ldrh %1, %0"
-                    : "+Qo" (*(volatile u16 __force *)addr),
+                    : "+Q" (*(volatile u16 __force *)addr),
                       "=r" (val));
        return val;
 }
index 05b8e82..e3f7572 100644 (file)
@@ -10,7 +10,5 @@
 
 extern void sched_clock_postinit(void);
 extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate);
-extern void setup_sched_clock_needs_suspend(u32 (*read)(void), int bits,
-               unsigned long rate);
 
 #endif
index 6a6f1e4..301c1db 100644 (file)
@@ -27,9 +27,9 @@
 #if __LINUX_ARM_ARCH__ <= 6
        ldr     \tmp, =elf_hwcap                    @ may not have MVFR regs
        ldr     \tmp, [\tmp, #0]
-       tst     \tmp, #HWCAP_VFPv3D16
-       ldceql  p11, cr0, [\base],#32*4             @ FLDMIAD \base!, {d16-d31}
-       addne   \base, \base, #32*4                 @ step over unused register space
+       tst     \tmp, #HWCAP_VFPD32
+       ldcnel  p11, cr0, [\base],#32*4             @ FLDMIAD \base!, {d16-d31}
+       addeq   \base, \base, #32*4                 @ step over unused register space
 #else
        VFPFMRX \tmp, MVFR0                         @ Media and VFP Feature Register 0
        and     \tmp, \tmp, #MVFR0_A_SIMD_MASK      @ A_SIMD field
@@ -51,9 +51,9 @@
 #if __LINUX_ARM_ARCH__ <= 6
        ldr     \tmp, =elf_hwcap                    @ may not have MVFR regs
        ldr     \tmp, [\tmp, #0]
-       tst     \tmp, #HWCAP_VFPv3D16
-       stceql  p11, cr0, [\base],#32*4             @ FSTMIAD \base!, {d16-d31}
-       addne   \base, \base, #32*4                 @ step over unused register space
+       tst     \tmp, #HWCAP_VFPD32
+       stcnel  p11, cr0, [\base],#32*4             @ FSTMIAD \base!, {d16-d31}
+       addeq   \base, \base, #32*4                 @ step over unused register space
 #else
        VFPFMRX \tmp, MVFR0                         @ Media and VFP Feature Register 0
        and     \tmp, \tmp, #MVFR0_A_SIMD_MASK      @ A_SIMD field
index f254f65..3688fd1 100644 (file)
 #define HWCAP_THUMBEE  (1 << 11)
 #define HWCAP_NEON     (1 << 12)
 #define HWCAP_VFPv3    (1 << 13)
-#define HWCAP_VFPv3D16 (1 << 14)
+#define HWCAP_VFPv3D16 (1 << 14)       /* also set for VFPv4-D16 */
 #define HWCAP_TLS      (1 << 15)
 #define HWCAP_VFPv4    (1 << 16)
 #define HWCAP_IDIVA    (1 << 17)
 #define HWCAP_IDIVT    (1 << 18)
+#define HWCAP_VFPD32   (1 << 19)       /* set if VFP has 32 regs (not 16) */
 #define HWCAP_IDIV     (HWCAP_IDIVA | HWCAP_IDIVT)
 
 
index e21bac2..fc6692e 100644 (file)
@@ -107,13 +107,6 @@ static void sched_clock_poll(unsigned long wrap_ticks)
        update_sched_clock();
 }
 
-void __init setup_sched_clock_needs_suspend(u32 (*read)(void), int bits,
-               unsigned long rate)
-{
-       setup_sched_clock(read, bits, rate);
-       cd.needs_suspend = true;
-}
-
 void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
 {
        unsigned long r, w;
@@ -189,18 +182,15 @@ void __init sched_clock_postinit(void)
 static int sched_clock_suspend(void)
 {
        sched_clock_poll(sched_clock_timer.data);
-       if (cd.needs_suspend)
-               cd.suspended = true;
+       cd.suspended = true;
        return 0;
 }
 
 static void sched_clock_resume(void)
 {
-       if (cd.needs_suspend) {
-               cd.epoch_cyc = read_sched_clock();
-               cd.epoch_cyc_copy = cd.epoch_cyc;
-               cd.suspended = false;
-       }
+       cd.epoch_cyc = read_sched_clock();
+       cd.epoch_cyc_copy = cd.epoch_cyc;
+       cd.suspended = false;
 }
 
 static struct syscore_ops sched_clock_ops = {
index 5269825..a3e4710 100644 (file)
@@ -361,10 +361,10 @@ static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0       /* Advanced Interrupt Controller (IRQ6) */
 };
 
-struct at91_init_soc __initdata at91rm9200_soc = {
+AT91_SOC_START(rm9200)
        .map_io = at91rm9200_map_io,
        .default_irq_priority = at91rm9200_default_irq_priority,
        .ioremap_registers = at91rm9200_ioremap_registers,
        .register_clocks = at91rm9200_register_clocks,
        .init = at91rm9200_initialize,
-};
+AT91_SOC_END
index f820261..7aaa62c 100644 (file)
@@ -235,6 +235,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_ID("pioA", &pioA_clk),
        CLKDEV_CON_ID("pioB", &pioB_clk),
        CLKDEV_CON_ID("pioC", &pioC_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk),
 };
 
 static struct clk_lookup usart_clocks_lookups[] = {
@@ -390,10 +393,10 @@ static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller */
 };
 
-struct at91_init_soc __initdata at91sam9260_soc = {
+AT91_SOC_START(sam9260)
        .map_io = at91sam9260_map_io,
        .default_irq_priority = at91sam9260_default_irq_priority,
        .ioremap_registers = at91sam9260_ioremap_registers,
        .register_clocks = at91sam9260_register_clocks,
        .init = at91sam9260_initialize,
-};
+AT91_SOC_END
index 04295c0..4d262f3 100644 (file)
@@ -334,10 +334,10 @@ static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller */
 };
 
-struct at91_init_soc __initdata at91sam9261_soc = {
+AT91_SOC_START(sam9261)
        .map_io = at91sam9261_map_io,
        .default_irq_priority = at91sam9261_default_irq_priority,
        .ioremap_registers = at91sam9261_ioremap_registers,
        .register_clocks = at91sam9261_register_clocks,
        .init = at91sam9261_initialize,
-};
+AT91_SOC_END
index d6f9c23..448fce1 100644 (file)
@@ -212,6 +212,11 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
        CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
        CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioCDE_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCDE_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCDE_clk),
 };
 
 static struct clk_lookup usart_clocks_lookups[] = {
@@ -365,10 +370,10 @@ static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller (IRQ1) */
 };
 
-struct at91_init_soc __initdata at91sam9263_soc = {
+AT91_SOC_START(sam9263)
        .map_io = at91sam9263_map_io,
        .default_irq_priority = at91sam9263_default_irq_priority,
        .ioremap_registers = at91sam9263_ioremap_registers,
        .register_clocks = at91sam9263_register_clocks,
        .init = at91sam9263_initialize,
-};
+AT91_SOC_END
index 84af1b5..e6dd371 100644 (file)
@@ -260,6 +260,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk),
        /* fake hclk clock */
        CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioC_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioDE_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioDE_clk),
+
        CLKDEV_CON_ID("pioA", &pioA_clk),
        CLKDEV_CON_ID("pioB", &pioB_clk),
        CLKDEV_CON_ID("pioC", &pioC_clk),
@@ -409,10 +415,10 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller (IRQ0) */
 };
 
-struct at91_init_soc __initdata at91sam9g45_soc = {
+AT91_SOC_START(sam9g45)
        .map_io = at91sam9g45_map_io,
        .default_irq_priority = at91sam9g45_default_irq_priority,
        .ioremap_registers = at91sam9g45_ioremap_registers,
        .register_clocks = at91sam9g45_register_clocks,
        .init = at91sam9g45_initialize,
-};
+AT91_SOC_END
index 732d3d3..bf8a083 100644 (file)
@@ -171,10 +171,10 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
        CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
        CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
-       CLKDEV_CON_ID("pioA", &pioAB_clk),
-       CLKDEV_CON_ID("pioB", &pioAB_clk),
-       CLKDEV_CON_ID("pioC", &pioCD_clk),
-       CLKDEV_CON_ID("pioD", &pioCD_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioAB_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioAB_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCD_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCD_clk),
        /* additional fake clock for macb_hclk */
        CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
        CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk),
@@ -223,13 +223,10 @@ static void __init at91sam9n12_map_io(void)
 void __init at91sam9n12_initialize(void)
 {
        at91_extern_irq = (1 << AT91SAM9N12_ID_IRQ0);
-
-       /* Register GPIO subsystem (using DT) */
-       at91_gpio_init(NULL, 0);
 }
 
-struct at91_init_soc __initdata at91sam9n12_soc = {
+AT91_SOC_START(sam9n12)
        .map_io = at91sam9n12_map_io,
        .register_clocks = at91sam9n12_register_clocks,
        .init = at91sam9n12_initialize,
-};
+AT91_SOC_END
index 72e9084..cbe72e4 100644 (file)
@@ -338,10 +338,10 @@ static unsigned int at91sam9rl_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller */
 };
 
-struct at91_init_soc __initdata at91sam9rl_soc = {
+AT91_SOC_START(sam9rl)
        .map_io = at91sam9rl_map_io,
        .default_irq_priority = at91sam9rl_default_irq_priority,
        .ioremap_registers = at91sam9rl_ioremap_registers,
        .register_clocks = at91sam9rl_register_clocks,
        .init = at91sam9rl_initialize,
-};
+AT91_SOC_END
index e503538..56d13a4 100644 (file)
@@ -234,10 +234,10 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
        CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
        CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
-       CLKDEV_CON_ID("pioA", &pioAB_clk),
-       CLKDEV_CON_ID("pioB", &pioAB_clk),
-       CLKDEV_CON_ID("pioC", &pioCD_clk),
-       CLKDEV_CON_ID("pioD", &pioCD_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioAB_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioAB_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCD_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCD_clk),
        /* additional fake clock for macb_hclk */
        CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb0_clk),
        CLKDEV_CON_DEV_ID("hclk", "f8030000.ethernet", &macb1_clk),
@@ -313,18 +313,11 @@ static void __init at91sam9x5_map_io(void)
        at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
 }
 
-void __init at91sam9x5_initialize(void)
-{
-       /* Register GPIO subsystem (using DT) */
-       at91_gpio_init(NULL, 0);
-}
-
 /* --------------------------------------------------------------------
  *  Interrupt initialization
  * -------------------------------------------------------------------- */
 
-struct at91_init_soc __initdata at91sam9x5_soc = {
+AT91_SOC_START(sam9x5)
        .map_io = at91sam9x5_map_io,
        .register_clocks = at91sam9x5_register_clocks,
-       .init = at91sam9x5_initialize,
-};
+AT91_SOC_END
index e8f45c4..3b6a948 100644 (file)
@@ -30,8 +30,6 @@
 static const struct of_device_id irq_of_match[] __initconst = {
 
        { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init },
-       { .compatible = "atmel,at91rm9200-gpio", .data = at91_gpio_of_irq_setup },
-       { .compatible = "atmel,at91sam9x5-gpio", .data = at91_gpio_of_irq_setup },
        { /*sentinel*/ }
 };
 
index be42cf0..c5d7e1e 100644 (file)
@@ -23,8 +23,6 @@
 #include <linux/io.h>
 #include <linux/irqdomain.h>
 #include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_gpio.h>
 
 #include <asm/mach/irq.h>
 
@@ -33,6 +31,8 @@
 
 #include "generic.h"
 
+#define MAX_NB_GPIO_PER_BANK   32
+
 struct at91_gpio_chip {
        struct gpio_chip        chip;
        struct at91_gpio_chip   *next;          /* Bank sharing same clock */
@@ -46,6 +46,7 @@ struct at91_gpio_chip {
 
 #define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
 
+static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset);
 static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip);
 static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val);
 static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset);
@@ -55,26 +56,27 @@ static int at91_gpiolib_direction_input(struct gpio_chip *chip,
                                        unsigned offset);
 static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
 
-#define AT91_GPIO_CHIP(name, nr_gpio)                                  \
+#define AT91_GPIO_CHIP(name)                                           \
        {                                                               \
                .chip = {                                               \
                        .label            = name,                       \
+                       .request          = at91_gpiolib_request,       \
                        .direction_input  = at91_gpiolib_direction_input, \
                        .direction_output = at91_gpiolib_direction_output, \
                        .get              = at91_gpiolib_get,           \
                        .set              = at91_gpiolib_set,           \
                        .dbg_show         = at91_gpiolib_dbg_show,      \
                        .to_irq           = at91_gpiolib_to_irq,        \
-                       .ngpio            = nr_gpio,                    \
+                       .ngpio            = MAX_NB_GPIO_PER_BANK,       \
                },                                                      \
        }
 
 static struct at91_gpio_chip gpio_chip[] = {
-       AT91_GPIO_CHIP("pioA", 32),
-       AT91_GPIO_CHIP("pioB", 32),
-       AT91_GPIO_CHIP("pioC", 32),
-       AT91_GPIO_CHIP("pioD", 32),
-       AT91_GPIO_CHIP("pioE", 32),
+       AT91_GPIO_CHIP("pioA"),
+       AT91_GPIO_CHIP("pioB"),
+       AT91_GPIO_CHIP("pioC"),
+       AT91_GPIO_CHIP("pioD"),
+       AT91_GPIO_CHIP("pioE"),
 };
 
 static int gpio_banks;
@@ -89,7 +91,7 @@ static unsigned long at91_gpio_caps;
 
 static inline void __iomem *pin_to_controller(unsigned pin)
 {
-       pin /= 32;
+       pin /= MAX_NB_GPIO_PER_BANK;
        if (likely(pin < gpio_banks))
                return gpio_chip[pin].regbase;
 
@@ -98,7 +100,7 @@ static inline void __iomem *pin_to_controller(unsigned pin)
 
 static inline unsigned pin_to_mask(unsigned pin)
 {
-       return 1 << (pin % 32);
+       return 1 << (pin % MAX_NB_GPIO_PER_BANK);
 }
 
 
@@ -713,80 +715,6 @@ postcore_initcall(at91_gpio_debugfs_init);
  */
 static struct lock_class_key gpio_lock_class;
 
-#if defined(CONFIG_OF)
-static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
-                                                       irq_hw_number_t hw)
-{
-       struct at91_gpio_chip   *at91_gpio = h->host_data;
-
-       irq_set_lockdep_class(virq, &gpio_lock_class);
-
-       /*
-        * Can use the "simple" and not "edge" handler since it's
-        * shorter, and the AIC handles interrupts sanely.
-        */
-       irq_set_chip_and_handler(virq, &gpio_irqchip,
-                                handle_simple_irq);
-       set_irq_flags(virq, IRQF_VALID);
-       irq_set_chip_data(virq, at91_gpio);
-
-       return 0;
-}
-
-static struct irq_domain_ops at91_gpio_ops = {
-       .map    = at91_gpio_irq_map,
-       .xlate  = irq_domain_xlate_twocell,
-};
-
-int __init at91_gpio_of_irq_setup(struct device_node *node,
-                                    struct device_node *parent)
-{
-       struct at91_gpio_chip   *prev = NULL;
-       int                     alias_idx = of_alias_get_id(node, "gpio");
-       struct at91_gpio_chip   *at91_gpio = &gpio_chip[alias_idx];
-
-       /* Setup proper .irq_set_type function */
-       if (has_pio3())
-               gpio_irqchip.irq_set_type = alt_gpio_irq_type;
-       else
-               gpio_irqchip.irq_set_type = gpio_irq_type;
-
-       /* Disable irqs of this PIO controller */
-       __raw_writel(~0, at91_gpio->regbase + PIO_IDR);
-
-       /* Setup irq domain */
-       at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
-                                               &at91_gpio_ops, at91_gpio);
-       if (!at91_gpio->domain)
-               panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
-                       at91_gpio->pioc_idx);
-
-       /* Setup chained handler */
-       if (at91_gpio->pioc_idx)
-               prev = &gpio_chip[at91_gpio->pioc_idx - 1];
-
-       /* The toplevel handler handles one bank of GPIOs, except
-        * on some SoC it can handles up to three...
-        * We only set up the handler for the first of the list.
-        */
-       if (prev && prev->next == at91_gpio)
-               return 0;
-
-       at91_gpio->pioc_virq = irq_create_mapping(irq_find_host(parent),
-                                                       at91_gpio->pioc_hwirq);
-       irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
-       irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
-
-       return 0;
-}
-#else
-int __init at91_gpio_of_irq_setup(struct device_node *node,
-                                    struct device_node *parent)
-{
-       return -EINVAL;
-}
-#endif
-
 /*
  * irqdomain initialization: pile up irqdomains on top of AIC range
  */
@@ -862,6 +790,16 @@ void __init at91_gpio_irq_setup(void)
 }
 
 /* gpiolib support */
+static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset)
+{
+       struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+       void __iomem *pio = at91_gpio->regbase;
+       unsigned mask = 1 << offset;
+
+       __raw_writel(mask, pio + PIO_PER);
+       return 0;
+}
+
 static int at91_gpiolib_direction_input(struct gpio_chip *chip,
                                        unsigned offset)
 {
@@ -975,81 +913,11 @@ err:
        return -EINVAL;
 }
 
-#ifdef CONFIG_OF_GPIO
-static void __init of_at91_gpio_init_one(struct device_node *np)
-{
-       int alias_idx;
-       struct at91_gpio_chip *at91_gpio;
-
-       if (!np)
-               return;
-
-       alias_idx = of_alias_get_id(np, "gpio");
-       if (alias_idx >= MAX_GPIO_BANKS) {
-               pr_err("at91_gpio, failed alias idx(%d) > MAX_GPIO_BANKS(%d), ignoring.\n",
-                                               alias_idx, MAX_GPIO_BANKS);
-               return;
-       }
-
-       at91_gpio = &gpio_chip[alias_idx];
-       at91_gpio->chip.base = alias_idx * at91_gpio->chip.ngpio;
-
-       at91_gpio->regbase = of_iomap(np, 0);
-       if (!at91_gpio->regbase) {
-               pr_err("at91_gpio.%d, failed to map registers, ignoring.\n",
-                                                               alias_idx);
-               return;
-       }
-
-       /* Get the interrupts property */
-       if (of_property_read_u32(np, "interrupts", &at91_gpio->pioc_hwirq)) {
-               pr_err("at91_gpio.%d, failed to get interrupts property, ignoring.\n",
-                                                               alias_idx);
-               goto ioremap_err;
-       }
-
-       /* Get capabilities from compatibility property */
-       if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio"))
-               at91_gpio_caps |= AT91_GPIO_CAP_PIO3;
-
-       /* Setup clock */
-       if (at91_gpio_setup_clk(alias_idx))
-               goto ioremap_err;
-
-       at91_gpio->chip.of_node = np;
-       gpio_banks = max(gpio_banks, alias_idx + 1);
-       at91_gpio->pioc_idx = alias_idx;
-       return;
-
-ioremap_err:
-       iounmap(at91_gpio->regbase);
-}
-
-static int __init of_at91_gpio_init(void)
-{
-       struct device_node *np = NULL;
-
-       /*
-        * This isn't ideal, but it gets things hooked up until this
-        * driver is converted into a platform_device
-        */
-       for_each_compatible_node(np, NULL, "atmel,at91rm9200-gpio")
-               of_at91_gpio_init_one(np);
-
-       return gpio_banks > 0 ? 0 : -EINVAL;
-}
-#else
-static int __init of_at91_gpio_init(void)
-{
-       return -EINVAL;
-}
-#endif
-
 static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq)
 {
        struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
 
-       at91_gpio->chip.base = idx * at91_gpio->chip.ngpio;
+       at91_gpio->chip.base = idx * MAX_NB_GPIO_PER_BANK;
        at91_gpio->pioc_hwirq = pioc_hwirq;
        at91_gpio->pioc_idx = idx;
 
@@ -1079,11 +947,11 @@ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
 
        BUG_ON(nr_banks > MAX_GPIO_BANKS);
 
-       if (of_at91_gpio_init() < 0) {
-               /* No GPIO controller found in device tree */
-               for (i = 0; i < nr_banks; i++)
-                       at91_gpio_init_one(i, data[i].regbase, data[i].id);
-       }
+       if (of_have_populated_dt())
+               return;
+
+       for (i = 0; i < nr_banks; i++)
+               at91_gpio_init_one(i, data[i].regbase, data[i].id);
 
        for (i = 0; i < gpio_banks; i++) {
                at91_gpio = &gpio_chip[i];
index 0b32c81..80f4bfd 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/mm.h>
 #include <linux/pm.h>
 #include <linux/of_address.h>
+#include <linux/pinctrl/machine.h>
 
 #include <asm/system_misc.h>
 #include <asm/mach/map.h>
@@ -448,7 +449,8 @@ void __init at91_dt_initialize(void)
        /* Register the processor-specific clocks */
        at91_boot_soc.register_clocks();
 
-       at91_boot_soc.init();
+       if (at91_boot_soc.init)
+               at91_boot_soc.init();
 }
 #endif
 
@@ -463,4 +465,6 @@ void __init at91_initialize(unsigned long main_clock)
        at91_boot_soc.register_clocks();
 
        at91_boot_soc.init();
+
+       pinctrl_provide_dummies();
 }
index a9cfeb1..9c6d3d4 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 struct at91_init_soc {
+       int builtin;
        unsigned int *default_irq_priority;
        void (*map_io)(void);
        void (*ioremap_registers)(void);
@@ -22,9 +23,18 @@ extern struct at91_init_soc at91sam9rl_soc;
 extern struct at91_init_soc at91sam9x5_soc;
 extern struct at91_init_soc at91sam9n12_soc;
 
+#define AT91_SOC_START(_name)                          \
+struct at91_init_soc __initdata at91##_name##_soc      \
+ __used                                                        \
+                                               = {     \
+       .builtin        = 1,                            \
+
+#define AT91_SOC_END                                   \
+};
+
 static inline int at91_soc_is_enabled(void)
 {
-       return at91_boot_soc.init != NULL;
+       return at91_boot_soc.builtin;
 }
 
 #if !defined(CONFIG_SOC_AT91RM9200)
index b8efac4..ce2de0d 100644 (file)
@@ -1445,7 +1445,6 @@ static struct platform_device pinctrl_device = {
 static struct u300_gpio_platform u300_gpio_plat = {
        .ports = 7,
        .gpio_base = 0,
-       .gpio_irq_base = IRQ_U300_GPIO_BASE,
        .pinctrl_device = &pinctrl_device,
 };
 
@@ -1804,7 +1803,7 @@ MACHINE_START(U300, "Ericsson AB U335 S335/B335 Prototype Board")
        /* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
        .atag_offset    = 0x100,
        .map_io         = u300_map_io,
-       .nr_irqs        = NR_IRQS_U300,
+       .nr_irqs        = 0,
        .init_irq       = u300_init_irq,
        .handle_irq     = vic_handle_irq,
        .timer          = &u300_timer,
index e27425a..21d5e76 100644 (file)
 #ifndef __MACH_IRQS_H
 #define __MACH_IRQS_H
 
-#define IRQ_U300_INTCON0_START         1
-#define IRQ_U300_INTCON1_START         33
+#define IRQ_U300_INTCON0_START         32
+#define IRQ_U300_INTCON1_START         64
 /* These are on INTCON0 - 30 lines */
-#define IRQ_U300_IRQ0_EXT              1
-#define IRQ_U300_IRQ1_EXT              2
-#define IRQ_U300_DMA                   3
-#define IRQ_U300_VIDEO_ENC_0           4
-#define IRQ_U300_VIDEO_ENC_1           5
-#define IRQ_U300_AAIF_RX               6
-#define IRQ_U300_AAIF_TX               7
-#define IRQ_U300_AAIF_VGPIO            8
-#define IRQ_U300_AAIF_WAKEUP           9
-#define IRQ_U300_PCM_I2S0_FRAME                10
-#define IRQ_U300_PCM_I2S0_FIFO         11
-#define IRQ_U300_PCM_I2S1_FRAME                12
-#define IRQ_U300_PCM_I2S1_FIFO         13
-#define IRQ_U300_XGAM_GAMCON           14
-#define IRQ_U300_XGAM_CDI              15
-#define IRQ_U300_XGAM_CDICON           16
-#define IRQ_U300_XGAM_PDI              18
-#define IRQ_U300_XGAM_PDICON           19
-#define IRQ_U300_XGAM_GAMEACC          20
-#define IRQ_U300_XGAM_MCIDCT           21
-#define IRQ_U300_APEX                  22
-#define IRQ_U300_UART0                 23
-#define IRQ_U300_SPI                   24
-#define IRQ_U300_TIMER_APP_OS          25
-#define IRQ_U300_TIMER_APP_DD          26
-#define IRQ_U300_TIMER_APP_GP1         27
-#define IRQ_U300_TIMER_APP_GP2         28
-#define IRQ_U300_TIMER_OS              29
-#define IRQ_U300_TIMER_MS              30
-#define IRQ_U300_KEYPAD_KEYBF          31
-#define IRQ_U300_KEYPAD_KEYBR          32
+#define IRQ_U300_IRQ0_EXT              32
+#define IRQ_U300_IRQ1_EXT              33
+#define IRQ_U300_DMA                   34
+#define IRQ_U300_VIDEO_ENC_0           35
+#define IRQ_U300_VIDEO_ENC_1           36
+#define IRQ_U300_AAIF_RX               37
+#define IRQ_U300_AAIF_TX               38
+#define IRQ_U300_AAIF_VGPIO            39
+#define IRQ_U300_AAIF_WAKEUP           40
+#define IRQ_U300_PCM_I2S0_FRAME                41
+#define IRQ_U300_PCM_I2S0_FIFO         42
+#define IRQ_U300_PCM_I2S1_FRAME                43
+#define IRQ_U300_PCM_I2S1_FIFO         44
+#define IRQ_U300_XGAM_GAMCON           45
+#define IRQ_U300_XGAM_CDI              46
+#define IRQ_U300_XGAM_CDICON           47
+#define IRQ_U300_XGAM_PDI              49
+#define IRQ_U300_XGAM_PDICON           50
+#define IRQ_U300_XGAM_GAMEACC          51
+#define IRQ_U300_XGAM_MCIDCT           52
+#define IRQ_U300_APEX                  53
+#define IRQ_U300_UART0                 54
+#define IRQ_U300_SPI                   55
+#define IRQ_U300_TIMER_APP_OS          56
+#define IRQ_U300_TIMER_APP_DD          57
+#define IRQ_U300_TIMER_APP_GP1         58
+#define IRQ_U300_TIMER_APP_GP2         59
+#define IRQ_U300_TIMER_OS              60
+#define IRQ_U300_TIMER_MS              61
+#define IRQ_U300_KEYPAD_KEYBF          62
+#define IRQ_U300_KEYPAD_KEYBR          63
 /* These are on INTCON1 - 32 lines */
-#define IRQ_U300_GPIO_PORT0            33
-#define IRQ_U300_GPIO_PORT1            34
-#define IRQ_U300_GPIO_PORT2            35
+#define IRQ_U300_GPIO_PORT0            64
+#define IRQ_U300_GPIO_PORT1            65
+#define IRQ_U300_GPIO_PORT2            66
 
 /* These are for DB3150, DB3200 and DB3350 */
-#define IRQ_U300_WDOG                  36
-#define IRQ_U300_EVHIST                        37
-#define IRQ_U300_MSPRO                 38
-#define IRQ_U300_MMCSD_MCIINTR0                39
-#define IRQ_U300_MMCSD_MCIINTR1                40
-#define IRQ_U300_I2C0                  41
-#define IRQ_U300_I2C1                  42
-#define IRQ_U300_RTC                   43
-#define IRQ_U300_NFIF                  44
-#define IRQ_U300_NFIF2                 45
+#define IRQ_U300_WDOG                  67
+#define IRQ_U300_EVHIST                        68
+#define IRQ_U300_MSPRO                 69
+#define IRQ_U300_MMCSD_MCIINTR0                70
+#define IRQ_U300_MMCSD_MCIINTR1                71
+#define IRQ_U300_I2C0                  72
+#define IRQ_U300_I2C1                  73
+#define IRQ_U300_RTC                   74
+#define IRQ_U300_NFIF                  75
+#define IRQ_U300_NFIF2                 76
 
 /* The DB3350-specific interrupt lines */
-#define IRQ_U300_ISP_F0                        46
-#define IRQ_U300_ISP_F1                        47
-#define IRQ_U300_ISP_F2                        48
-#define IRQ_U300_ISP_F3                        49
-#define IRQ_U300_ISP_F4                        50
-#define IRQ_U300_GPIO_PORT3            51
-#define IRQ_U300_SYSCON_PLL_LOCK       52
-#define IRQ_U300_UART1                 53
-#define IRQ_U300_GPIO_PORT4            54
-#define IRQ_U300_GPIO_PORT5            55
-#define IRQ_U300_GPIO_PORT6            56
-#define U300_VIC_IRQS_END              57
-
-/* Maximum 8*7 GPIO lines */
-#ifdef CONFIG_PINCTRL_COH901
-#define IRQ_U300_GPIO_BASE             (U300_VIC_IRQS_END)
-#define IRQ_U300_GPIO_END              (IRQ_U300_GPIO_BASE + 56)
-#else
-#define IRQ_U300_GPIO_END              (U300_VIC_IRQS_END)
-#endif
-
-#define NR_IRQS_U300                   (IRQ_U300_GPIO_END - IRQ_U300_INTCON0_START)
+#define IRQ_U300_ISP_F0                        77
+#define IRQ_U300_ISP_F1                        78
+#define IRQ_U300_ISP_F2                        79
+#define IRQ_U300_ISP_F3                        80
+#define IRQ_U300_ISP_F4                        81
+#define IRQ_U300_GPIO_PORT3            82
+#define IRQ_U300_SYSCON_PLL_LOCK       83
+#define IRQ_U300_UART1                 84
+#define IRQ_U300_GPIO_PORT4            85
+#define IRQ_U300_GPIO_PORT5            86
+#define IRQ_U300_GPIO_PORT6            87
+#define U300_VIC_IRQS_END              88
 
 #endif
index 023f443..b820eda 100644 (file)
@@ -745,7 +745,7 @@ do_alignment_t32_to_handler(unsigned long *pinstr, struct pt_regs *regs,
 static int
 do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
-       union offset_union offset;
+       union offset_union uninitialized_var(offset);
        unsigned long instr = 0, instrptr;
        int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
        unsigned int type;
index c834b32..3b44e0d 100644 (file)
@@ -701,11 +701,14 @@ static int __init vfp_init(void)
                        elf_hwcap |= HWCAP_VFPv3;
 
                        /*
-                        * Check for VFPv3 D16. CPUs in this configuration
-                        * only have 16 x 64bit registers.
+                        * Check for VFPv3 D16 and VFPv4 D16.  CPUs in
+                        * this configuration only have 16 x 64bit
+                        * registers.
                         */
                        if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1)
-                               elf_hwcap |= HWCAP_VFPv3D16;
+                               elf_hwcap |= HWCAP_VFPv3D16; /* also v4-D16 */
+                       else
+                               elf_hwcap |= HWCAP_VFPD32;
                }
 #endif
                /*
index 59bcb96..f576092 100644 (file)
@@ -166,3 +166,14 @@ void free_xenballooned_pages(int nr_pages, struct page **pages)
        *pages = NULL;
 }
 EXPORT_SYMBOL_GPL(free_xenballooned_pages);
+
+/* In the hypervisor.S file. */
+EXPORT_SYMBOL_GPL(HYPERVISOR_event_channel_op);
+EXPORT_SYMBOL_GPL(HYPERVISOR_grant_table_op);
+EXPORT_SYMBOL_GPL(HYPERVISOR_xen_version);
+EXPORT_SYMBOL_GPL(HYPERVISOR_console_io);
+EXPORT_SYMBOL_GPL(HYPERVISOR_sched_op);
+EXPORT_SYMBOL_GPL(HYPERVISOR_hvm_op);
+EXPORT_SYMBOL_GPL(HYPERVISOR_memory_op);
+EXPORT_SYMBOL_GPL(HYPERVISOR_physdev_op);
+EXPORT_SYMBOL_GPL(privcmd_call);
index 074f5ed..71f7239 100644 (file)
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/opcodes-virt.h>
 #include <xen/interface/xen.h>
 
 
-/* HVC 0xEA1 */
-#ifdef CONFIG_THUMB2_KERNEL
-#define xen_hvc .word 0xf7e08ea1
-#else
-#define xen_hvc .word 0xe140ea71
-#endif
+#define XEN_IMM 0xEA1
 
 #define HYPERCALL_SIMPLE(hypercall)            \
 ENTRY(HYPERVISOR_##hypercall)                  \
        mov r12, #__HYPERVISOR_##hypercall;     \
-       xen_hvc;                                                        \
+       __HVC(XEN_IMM);                                         \
        mov pc, lr;                                                     \
 ENDPROC(HYPERVISOR_##hypercall)
 
@@ -76,7 +72,7 @@ ENTRY(HYPERVISOR_##hypercall)                 \
        stmdb sp!, {r4}                                         \
        ldr r4, [sp, #4]                                        \
        mov r12, #__HYPERVISOR_##hypercall;     \
-       xen_hvc                                                         \
+       __HVC(XEN_IMM);                                         \
        ldm sp!, {r4}                                           \
        mov pc, lr                                                      \
 ENDPROC(HYPERVISOR_##hypercall)
@@ -100,7 +96,7 @@ ENTRY(privcmd_call)
        mov r2, r3
        ldr r3, [sp, #8]
        ldr r4, [sp, #4]
-       xen_hvc
+       __HVC(XEN_IMM)
        ldm sp!, {r4}
        mov pc, lr
 ENDPROC(privcmd_call);
index ef54a59..15ac18a 100644 (file)
@@ -1,6 +1,7 @@
 config ARM64
        def_bool y
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+       select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
        select GENERIC_CLOCKEVENTS
        select GENERIC_HARDIRQS_NO_DEPRECATED
        select GENERIC_IOMAP
index cf28464..07fea29 100644 (file)
 #include <asm/user.h>
 
 typedef unsigned long elf_greg_t;
-typedef unsigned long elf_freg_t[3];
 
 #define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-
-typedef struct user_fp elf_fpregset_t;
+typedef struct user_fpsimd_state elf_fpregset_t;
 
 #define EM_AARCH64             183
 
@@ -87,7 +85,6 @@ typedef struct user_fp elf_fpregset_t;
 #define R_AARCH64_MOVW_PREL_G2_NC      292
 #define R_AARCH64_MOVW_PREL_G3         293
 
-
 /*
  * These are used to set parameters in the core dumps.
  */
index b42fab9..c43b4ac 100644 (file)
@@ -25,9 +25,8 @@
  *  - FPSR and FPCR
  *  - 32 128-bit data registers
  *
- * Note that user_fp forms a prefix of this structure, which is relied
- * upon in the ptrace FP/SIMD accessors. struct user_fpsimd_state must
- * form a prefix of struct fpsimd_state.
+ * Note that user_fpsimd forms a prefix of this structure, which is
+ * relied upon in the ptrace FP/SIMD accessors.
  */
 struct fpsimd_state {
        union {
index 74a2a7d..54f6116 100644 (file)
@@ -114,7 +114,7 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
  *  I/O port access primitives.
  */
 #define IO_SPACE_LIMIT         0xffff
-#define PCI_IOBASE             ((void __iomem *)0xffffffbbfffe0000UL)
+#define PCI_IOBASE             ((void __iomem *)(MODULES_VADDR - SZ_2M))
 
 static inline u8 inb(unsigned long addr)
 {
@@ -225,9 +225,9 @@ extern void __iounmap(volatile void __iomem *addr);
 #define PROT_DEVICE_nGnRE      (PROT_DEFAULT | PTE_XN | PTE_ATTRINDX(MT_DEVICE_nGnRE))
 #define PROT_NORMAL_NC         (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL_NC))
 
-#define ioremap(addr, size)            __ioremap((addr), (size), PROT_DEVICE_nGnRE)
-#define ioremap_nocache(addr, size)    __ioremap((addr), (size), PROT_DEVICE_nGnRE)
-#define ioremap_wc(addr, size)         __ioremap((addr), (size), PROT_NORMAL_NC)
+#define ioremap(addr, size)            __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
+#define ioremap_nocache(addr, size)    __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
+#define ioremap_wc(addr, size)         __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
 #define iounmap                                __iounmap
 
 #define ARCH_HAS_IOREMAP_WC
index 5d81004..77f696c 100644 (file)
@@ -43,6 +43,8 @@
 #else
 #define STACK_TOP              STACK_TOP_MAX
 #endif /* CONFIG_COMPAT */
+
+#define ARCH_LOW_ADDRESS_LIMIT PHYS_MASK
 #endif /* __KERNEL__ */
 
 struct debug_info {
index 63f853f..68aff28 100644 (file)
@@ -14,7 +14,6 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 #ifdef CONFIG_COMPAT
-#define __ARCH_WANT_COMPAT_IPC_PARSE_VERSION
 #define __ARCH_WANT_COMPAT_STAT64
 #define __ARCH_WANT_SYS_GETHOSTNAME
 #define __ARCH_WANT_SYS_PAUSE
index ecbf2d8..c76c724 100644 (file)
@@ -613,17 +613,11 @@ enum armv8_pmuv3_perf_types {
        ARMV8_PMUV3_PERFCTR_BUS_ACCESS                          = 0x19,
        ARMV8_PMUV3_PERFCTR_MEM_ERROR                           = 0x1A,
        ARMV8_PMUV3_PERFCTR_BUS_CYCLES                          = 0x1D,
-
-       /*
-        * This isn't an architected event.
-        * We detect this event number and use the cycle counter instead.
-        */
-       ARMV8_PMUV3_PERFCTR_CPU_CYCLES                          = 0xFF,
 };
 
 /* PMUv3 HW events mapping. */
 static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = {
-       [PERF_COUNT_HW_CPU_CYCLES]              = ARMV8_PMUV3_PERFCTR_CPU_CYCLES,
+       [PERF_COUNT_HW_CPU_CYCLES]              = ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES,
        [PERF_COUNT_HW_INSTRUCTIONS]            = ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED,
        [PERF_COUNT_HW_CACHE_REFERENCES]        = ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS,
        [PERF_COUNT_HW_CACHE_MISSES]            = ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL,
@@ -1106,7 +1100,7 @@ static int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc,
        unsigned long evtype = event->config_base & ARMV8_EVTYPE_EVENT;
 
        /* Always place a cycle counter into the cycle counter. */
-       if (evtype == ARMV8_PMUV3_PERFCTR_CPU_CYCLES) {
+       if (evtype == ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES) {
                if (test_and_set_bit(ARMV8_IDX_CYCLE_COUNTER, cpuc->used_mask))
                        return -EAGAIN;
 
index f22965e..e04cebd 100644 (file)
@@ -310,24 +310,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
 }
 
 /*
- * Fill in the task's elfregs structure for a core dump.
- */
-int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs)
-{
-       elf_core_copy_regs(elfregs, task_pt_regs(t));
-       return 1;
-}
-
-/*
- * fill in the fpe structure for a core dump...
- */
-int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
-{
-       return 0;
-}
-EXPORT_SYMBOL(dump_fpu);
-
-/*
  * Shuffle the argument into the correct register before calling the
  * thread function.  x1 is the thread argument, x2 is the pointer to
  * the thread function, and x3 points to the exit function.
index 226b6bf..538300f 100644 (file)
@@ -211,8 +211,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
         * before we continue.
         */
        set_cpu_online(cpu, true);
-       while (!cpu_active(cpu))
-               cpu_relax();
+       complete(&cpu_running);
 
        /*
         * OK, it's off to the idle thread for us
index efbf7df..4cd2893 100644 (file)
@@ -80,7 +80,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
 #ifdef CONFIG_ZONE_DMA32
        /* 4GB maximum for 32-bit only capable devices */
        max_dma32 = min(max, MAX_DMA32_PFN);
-       zone_size[ZONE_DMA32] = max_dma32 - min;
+       zone_size[ZONE_DMA32] = max(min, max_dma32) - min;
 #endif
        zone_size[ZONE_NORMAL] = max - max_dma32;
 
index b741250..df2eb4b 100644 (file)
@@ -13,6 +13,7 @@ config FRV
        select GENERIC_CPU_DEVICES
        select ARCH_WANT_IPC_PARSE_VERSION
        select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
 
 config ZONE_DMA
        bool
index 6ae3254..636d5bb 100644 (file)
@@ -17,6 +17,8 @@ PARAMS_PHYS    = 0x0207c000
 INITRD_PHYS     = 0x02180000
 INITRD_VIRT     = 0x02180000
 
+OBJCOPYFLAGS   :=-O binary -R .note -R .note.gnu.build-id -R .comment
+
 #
 # If you don't define ZRELADDR above,
 # then it defaults to ZTEXTADDR
@@ -32,18 +34,18 @@ Image: $(obj)/Image
 targets: $(obj)/Image
 
 $(obj)/Image: vmlinux FORCE
-       $(OBJCOPY) -O binary -R .note -R .comment -S vmlinux $@
+       $(OBJCOPY) $(OBJCOPYFLAGS) -S vmlinux $@
 
 #$(obj)/Image: $(CONFIGURE) $(SYSTEM)
-#      $(OBJCOPY) -O binary -R .note -R .comment -g -S $(SYSTEM) $@
+#      $(OBJCOPY) $(OBJCOPYFLAGS) -g -S $(SYSTEM) $@
 
 bzImage: zImage
 
 zImage:        $(CONFIGURE) compressed/$(LINUX)
-       $(OBJCOPY) -O binary -R .note -R .comment -S compressed/$(LINUX) $@
+       $(OBJCOPY) $(OBJCOPYFLAGS) -S compressed/$(LINUX) $@
 
 bootpImage: bootp/bootp
-       $(OBJCOPY) -O binary -R .note -R .comment -S bootp/bootp $@
+       $(OBJCOPY) $(OBJCOPYFLAGS) -S bootp/bootp $@
 
 compressed/$(LINUX): $(LINUX) dep
        @$(MAKE) -C compressed $(LINUX)
index 266a5b2..2358634 100644 (file)
@@ -30,7 +30,6 @@
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #define __ARCH_WANT_SYS_EXECVE
-#define __ARCH_WANT_KERNEL_EXECVE
 
 /*
  * "Conditional" syscalls
index ee0beb3..dfcd263 100644 (file)
@@ -869,11 +869,6 @@ ret_from_kernel_thread:
        call            schedule_tail
        calll.p         @(gr21,gr0)
        or              gr20,gr20,gr8
-       bra             sys_exit
-
-       .globl          ret_from_kernel_execve
-ret_from_kernel_execve:
-       ori             gr28,0,sp
        bra             __syscall_exit
 
 ###################################################################################################
@@ -1080,27 +1075,10 @@ __entry_return_from_kernel_interrupt:
        subicc          gr5,#0,gr0,icc0
        beq             icc0,#0,__entry_return_direct
 
-__entry_preempt_need_resched:
-       ldi             @(gr15,#TI_FLAGS),gr4
-       andicc          gr4,#_TIF_NEED_RESCHED,gr0,icc0
-       beq             icc0,#1,__entry_return_direct
-
-       setlos          #PREEMPT_ACTIVE,gr5
-       sti             gr5,@(gr15,#TI_FLAGS)
-
-       andi            gr23,#~PSR_PIL,gr23
-       movgs           gr23,psr
-
-       call            schedule
-       sti             gr0,@(gr15,#TI_PRE_COUNT)
-
-       movsg           psr,gr23
-       ori             gr23,#PSR_PIL_14,gr23
-       movgs           gr23,psr
-       bra             __entry_preempt_need_resched
-#else
-       bra             __entry_return_direct
+       subcc           gr0,gr0,gr0,icc2                /* set Z and clear C */
+       call            preempt_schedule_irq
 #endif
+       bra             __entry_return_direct
 
 
 ###############################################################################
index e1e3aa1..7e33215 100644 (file)
@@ -181,6 +181,9 @@ int copy_thread(unsigned long clone_flags,
        childregs = (struct pt_regs *)
                (task_stack_page(p) + THREAD_SIZE - FRV_FRAME0_SIZE);
 
+       /* set up the userspace frame (the only place that the USP is stored) */
+       *childregs = *__kernel_frame0_ptr;
+
        p->set_child_tid = p->clear_child_tid = NULL;
 
        p->thread.frame  = childregs;
@@ -191,10 +194,8 @@ int copy_thread(unsigned long clone_flags,
        p->thread.frame0 = childregs;
 
        if (unlikely(!regs)) {
-               memset(childregs, 0, sizeof(struct pt_regs));
                childregs->gr9 = usp; /* function */
                childregs->gr8 = arg;
-               childregs->psr = PSR_S;
                p->thread.pc = (unsigned long) ret_from_kernel_thread;
                save_user_regs(p->thread.user);
                return 0;
index e47857f..b99c2a7 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/types.h>
 #include <linux/slab.h>
+#include <linux/export.h>
 #include <linux/dma-mapping.h>
 #include <linux/list.h>
 #include <linux/pci.h>
index c635028..05887a1 100644 (file)
@@ -2,7 +2,8 @@
 #define __ARCH_H8300_CACHE_H
 
 /* bytes per L1 cache line */
-#define        L1_CACHE_BYTES  4
+#define        L1_CACHE_SHIFT  2
+#define        L1_CACHE_BYTES  (1 << L1_CACHE_SHIFT)
 
 /* m68k-elf-gcc  2.95.2 doesn't like these */
 
index 55bde60..ad2b924 100644 (file)
@@ -9,6 +9,8 @@
 
 #define LPM_ANYPATH 0xff
 #define __MAX_CSSID 0
+#define __MAX_SUBCHANNEL 65535
+#define __MAX_SSID 3
 
 #include <asm/scsw.h>
 
index dd647c9..2d3b7cb 100644 (file)
@@ -506,12 +506,15 @@ static inline int pud_bad(pud_t pud)
 
 static inline int pmd_present(pmd_t pmd)
 {
-       return (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN) != 0UL;
+       unsigned long mask = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO;
+       return (pmd_val(pmd) & mask) == _HPAGE_TYPE_NONE ||
+              !(pmd_val(pmd) & _SEGMENT_ENTRY_INV);
 }
 
 static inline int pmd_none(pmd_t pmd)
 {
-       return (pmd_val(pmd) & _SEGMENT_ENTRY_INV) != 0UL;
+       return (pmd_val(pmd) & _SEGMENT_ENTRY_INV) &&
+              !(pmd_val(pmd) & _SEGMENT_ENTRY_RO);
 }
 
 static inline int pmd_large(pmd_t pmd)
@@ -1223,6 +1226,11 @@ static inline void __pmd_idte(unsigned long address, pmd_t *pmdp)
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+
+#define SEGMENT_NONE   __pgprot(_HPAGE_TYPE_NONE)
+#define SEGMENT_RO     __pgprot(_HPAGE_TYPE_RO)
+#define SEGMENT_RW     __pgprot(_HPAGE_TYPE_RW)
+
 #define __HAVE_ARCH_PGTABLE_DEPOSIT
 extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable);
 
@@ -1242,16 +1250,15 @@ static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
 
 static inline unsigned long massage_pgprot_pmd(pgprot_t pgprot)
 {
-       unsigned long pgprot_pmd = 0;
-
-       if (pgprot_val(pgprot) & _PAGE_INVALID) {
-               if (pgprot_val(pgprot) & _PAGE_SWT)
-                       pgprot_pmd |= _HPAGE_TYPE_NONE;
-               pgprot_pmd |= _SEGMENT_ENTRY_INV;
-       }
-       if (pgprot_val(pgprot) & _PAGE_RO)
-               pgprot_pmd |= _SEGMENT_ENTRY_RO;
-       return pgprot_pmd;
+       /*
+        * pgprot is PAGE_NONE, PAGE_RO, or PAGE_RW (see __Pxxx / __Sxxx)
+        * Convert to segment table entry format.
+        */
+       if (pgprot_val(pgprot) == pgprot_val(PAGE_NONE))
+               return pgprot_val(SEGMENT_NONE);
+       if (pgprot_val(pgprot) == pgprot_val(PAGE_RO))
+               return pgprot_val(SEGMENT_RO);
+       return pgprot_val(SEGMENT_RW);
 }
 
 static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
@@ -1269,7 +1276,9 @@ static inline pmd_t pmd_mkhuge(pmd_t pmd)
 
 static inline pmd_t pmd_mkwrite(pmd_t pmd)
 {
-       pmd_val(pmd) &= ~_SEGMENT_ENTRY_RO;
+       /* Do not clobber _HPAGE_TYPE_NONE pages! */
+       if (!(pmd_val(pmd) & _SEGMENT_ENTRY_INV))
+               pmd_val(pmd) &= ~_SEGMENT_ENTRY_RO;
        return pmd;
 }
 
index bf05389..b6506ee 100644 (file)
@@ -44,6 +44,12 @@ _sclp_wait_int:
 #endif
        mvc     .LoldpswS1-.LbaseS1(16,%r13),0(%r8)
        mvc     0(16,%r8),0(%r9)
+#ifdef CONFIG_64BIT
+       epsw    %r6,%r7                         # set current addressing mode
+       nill    %r6,0x1                         # in new psw (31 or 64 bit mode)
+       nilh    %r7,0x8000
+       stm     %r6,%r7,0(%r8)
+#endif
        lhi     %r6,0x0200                      # cr mask for ext int (cr0.54)
        ltr     %r2,%r2
        jz      .LsetctS1
@@ -87,7 +93,7 @@ _sclp_wait_int:
        .long   0x00080000, 0x80000000+.LwaitS1 # PSW to handle ext int
 #ifdef CONFIG_64BIT
 .LextpswS1_64:
-       .quad   0x0000000180000000, .LwaitS1    # PSW to handle ext int, 64 bit
+       .quad   0, .LwaitS1                     # PSW to handle ext int, 64 bit
 #endif
 .LwaitpswS1:
        .long   0x010a0000, 0x00000000+.LloopS1 # PSW to wait for ext int
index 2d37bb8..9017a63 100644 (file)
@@ -39,7 +39,7 @@ static __always_inline unsigned long follow_table(struct mm_struct *mm,
        pmd = pmd_offset(pud, addr);
        if (pmd_none(*pmd))
                return -0x10UL;
-       if (pmd_huge(*pmd)) {
+       if (pmd_large(*pmd)) {
                if (write && (pmd_val(*pmd) & _SEGMENT_ENTRY_RO))
                        return -0x04UL;
                return (pmd_val(*pmd) & HPAGE_MASK) + (addr & ~HPAGE_MASK);
index 60acb93..8b82853 100644 (file)
@@ -126,7 +126,7 @@ static inline int gup_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr,
                 */
                if (pmd_none(pmd) || pmd_trans_splitting(pmd))
                        return 0;
-               if (unlikely(pmd_huge(pmd))) {
+               if (unlikely(pmd_large(pmd))) {
                        if (!gup_huge_pmd(pmdp, pmd, addr, next,
                                          write, pages, nr))
                                return 0;
index b6b442b..9f2edb5 100644 (file)
@@ -20,6 +20,7 @@ config SPARC
        select HAVE_ARCH_TRACEHOOK
        select SYSCTL_EXCEPTION_TRACE
        select ARCH_WANT_OPTIONAL_GPIOLIB
+       select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select RTC_CLASS
        select RTC_DRV_M48T59
        select HAVE_IRQ_WORK
index 6ae1ad5..5d469d8 100644 (file)
@@ -13,13 +13,13 @@ obj-$(CONFIG_CRYPTO_DES_SPARC64) += camellia-sparc64.o
 
 obj-$(CONFIG_CRYPTO_CRC32C_SPARC64) += crc32c-sparc64.o
 
-sha1-sparc64-y := sha1_asm.o sha1_glue.o crop_devid.o
-sha256-sparc64-y := sha256_asm.o sha256_glue.o crop_devid.o
-sha512-sparc64-y := sha512_asm.o sha512_glue.o crop_devid.o
-md5-sparc64-y := md5_asm.o md5_glue.o crop_devid.o
+sha1-sparc64-y := sha1_asm.o sha1_glue.o
+sha256-sparc64-y := sha256_asm.o sha256_glue.o
+sha512-sparc64-y := sha512_asm.o sha512_glue.o
+md5-sparc64-y := md5_asm.o md5_glue.o
 
-aes-sparc64-y := aes_asm.o aes_glue.o crop_devid.o
-des-sparc64-y := des_asm.o des_glue.o crop_devid.o
-camellia-sparc64-y := camellia_asm.o camellia_glue.o crop_devid.o
+aes-sparc64-y := aes_asm.o aes_glue.o
+des-sparc64-y := des_asm.o des_glue.o
+camellia-sparc64-y := camellia_asm.o camellia_glue.o
 
-crc32c-sparc64-y := crc32c_asm.o crc32c_glue.o crop_devid.o
+crc32c-sparc64-y := crc32c_asm.o crc32c_glue.o
index 8f1c998..3965d1d 100644 (file)
@@ -475,3 +475,5 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("AES Secure Hash Algorithm, sparc64 aes opcode accelerated");
 
 MODULE_ALIAS("aes");
+
+#include "crop_devid.c"
index 42905c0..62c89af 100644 (file)
@@ -320,3 +320,5 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Camellia Cipher Algorithm, sparc64 camellia opcode accelerated");
 
 MODULE_ALIAS("aes");
+
+#include "crop_devid.c"
index 0bd89ce..5162fad 100644 (file)
@@ -177,3 +177,5 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("CRC32c (Castagnoli), sparc64 crc32c opcode accelerated");
 
 MODULE_ALIAS("crc32c");
+
+#include "crop_devid.c"
index c4940c2..41524ce 100644 (file)
@@ -527,3 +527,5 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms, sparc64 des opcode accelerated");
 
 MODULE_ALIAS("des");
+
+#include "crop_devid.c"
index 603d723..09a9ea1 100644 (file)
@@ -186,3 +186,5 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("MD5 Secure Hash Algorithm, sparc64 md5 opcode accelerated");
 
 MODULE_ALIAS("md5");
+
+#include "crop_devid.c"
index 2bbb20b..6cd5f29 100644 (file)
@@ -181,3 +181,5 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, sparc64 sha1 opcode accelerated");
 
 MODULE_ALIAS("sha1");
+
+#include "crop_devid.c"
index 591e656..04f555a 100644 (file)
@@ -239,3 +239,5 @@ MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm, sparc64 sha256 op
 
 MODULE_ALIAS("sha224");
 MODULE_ALIAS("sha256");
+
+#include "crop_devid.c"
index 486f0a2..f04d199 100644 (file)
@@ -224,3 +224,5 @@ MODULE_DESCRIPTION("SHA-384 and SHA-512 Secure Hash Algorithm, sparc64 sha512 op
 
 MODULE_ALIAS("sha384");
 MODULE_ALIAS("sha512");
+
+#include "crop_devid.c"
index ce35a1c..be56a24 100644 (file)
@@ -1,7 +1,7 @@
 /* atomic.h: Thankfully the V9 is at least reasonable for this
  *           stuff.
  *
- * Copyright (C) 1996, 1997, 2000 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1997, 2000, 2012 David S. Miller (davem@redhat.com)
  */
 
 #ifndef __ARCH_SPARC64_ATOMIC__
@@ -106,6 +106,8 @@ static inline long atomic64_add_unless(atomic64_t *v, long a, long u)
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
 
+extern long atomic64_dec_if_positive(atomic64_t *v);
+
 /* Atomic operations are already serializing */
 #define smp_mb__before_atomic_dec()    barrier()
 #define smp_mb__after_atomic_dec()     barrier()
index db3af0d..4e02086 100644 (file)
@@ -1,6 +1,46 @@
 #ifndef _SPARC64_BACKOFF_H
 #define _SPARC64_BACKOFF_H
 
+/* The macros in this file implement an exponential backoff facility
+ * for atomic operations.
+ *
+ * When multiple threads compete on an atomic operation, it is
+ * possible for one thread to be continually denied a successful
+ * completion of the compare-and-swap instruction.  Heavily
+ * threaded cpu implementations like Niagara can compound this
+ * problem even further.
+ *
+ * When an atomic operation fails and needs to be retried, we spin a
+ * certain number of times.  At each subsequent failure of the same
+ * operation we double the spin count, realizing an exponential
+ * backoff.
+ *
+ * When we spin, we try to use an operation that will cause the
+ * current cpu strand to block, and therefore make the core fully
+ * available to any other other runnable strands.  There are two
+ * options, based upon cpu capabilities.
+ *
+ * On all cpus prior to SPARC-T4 we do three dummy reads of the
+ * condition code register.  Each read blocks the strand for something
+ * between 40 and 50 cpu cycles.
+ *
+ * For SPARC-T4 and later we have a special "pause" instruction
+ * available.  This is implemented using writes to register %asr27.
+ * The cpu will block the number of cycles written into the register,
+ * unless a disrupting trap happens first.  SPARC-T4 specifically
+ * implements pause with a granularity of 8 cycles.  Each strand has
+ * an internal pause counter which decrements every 8 cycles.  So the
+ * chip shifts the %asr27 value down by 3 bits, and writes the result
+ * into the pause counter.  If a value smaller than 8 is written, the
+ * chip blocks for 1 cycle.
+ *
+ * To achieve the same amount of backoff as the three %ccr reads give
+ * on earlier chips, we shift the backoff value up by 7 bits.  (Three
+ * %ccr reads block for about 128 cycles, 1 << 7 == 128) We write the
+ * whole amount we want to block into the pause register, rather than
+ * loop writing 128 each time.
+ */
+
 #define BACKOFF_LIMIT  (4 * 1024)
 
 #ifdef CONFIG_SMP
 #define BACKOFF_LABEL(spin_label, continue_label) \
        spin_label
 
-#define BACKOFF_SPIN(reg, tmp, label)  \
-       mov     reg, tmp; \
-88:    brnz,pt tmp, 88b; \
-        sub    tmp, 1, tmp; \
-       set     BACKOFF_LIMIT, tmp; \
-       cmp     reg, tmp; \
-       bg,pn   %xcc, label; \
-        nop; \
-       ba,pt   %xcc, label; \
-        sllx   reg, 1, reg;
+#define BACKOFF_SPIN(reg, tmp, label)          \
+       mov             reg, tmp;               \
+88:    rd              %ccr, %g0;              \
+       rd              %ccr, %g0;              \
+       rd              %ccr, %g0;              \
+       .section        .pause_3insn_patch,"ax";\
+       .word           88b;                    \
+       sllx            tmp, 7, tmp;            \
+       wr              tmp, 0, %asr27;         \
+       clr             tmp;                    \
+       .previous;                              \
+       brnz,pt         tmp, 88b;               \
+        sub            tmp, 1, tmp;            \
+       set             BACKOFF_LIMIT, tmp;     \
+       cmp             reg, tmp;               \
+       bg,pn           %xcc, label;            \
+        nop;                                   \
+       ba,pt           %xcc, label;            \
+        sllx           reg, 1, reg;
 
 #else
 
index cef99fb..830502f 100644 (file)
@@ -232,9 +232,10 @@ static inline void __user *arch_compat_alloc_user_space(long len)
        struct pt_regs *regs = current_thread_info()->kregs;
        unsigned long usp = regs->u_regs[UREG_I6];
 
-       if (!(test_thread_flag(TIF_32BIT)))
+       if (test_thread_64bit_stack(usp))
                usp += STACK_BIAS;
-       else
+
+       if (test_thread_flag(TIF_32BIT))
                usp &= 0xffffffffUL;
 
        usp -= len;
index 4e5a483..721e25f 100644 (file)
@@ -196,7 +196,22 @@ extern unsigned long get_wchan(struct task_struct *task);
 #define KSTK_EIP(tsk)  (task_pt_regs(tsk)->tpc)
 #define KSTK_ESP(tsk)  (task_pt_regs(tsk)->u_regs[UREG_FP])
 
-#define cpu_relax()    barrier()
+/* Please see the commentary in asm/backoff.h for a description of
+ * what these instructions are doing and how they have been choosen.
+ * To make a long story short, we are trying to yield the current cpu
+ * strand during busy loops.
+ */
+#define cpu_relax()    asm volatile("\n99:\n\t"                        \
+                                    "rd        %%ccr, %%g0\n\t"        \
+                                    "rd        %%ccr, %%g0\n\t"        \
+                                    "rd        %%ccr, %%g0\n\t"        \
+                                    ".section  .pause_3insn_patch,\"ax\"\n\t"\
+                                    ".word     99b\n\t"                \
+                                    "wr        %%g0, 128, %%asr27\n\t" \
+                                    "nop\n\t"                          \
+                                    "nop\n\t"                          \
+                                    ".previous"                        \
+                                    ::: "memory")
 
 /* Prefetch support.  This is tuned for UltraSPARC-III and later.
  * UltraSPARC-I will treat these as nops, and UltraSPARC-II has
index c287651..f930031 100644 (file)
@@ -63,5 +63,10 @@ extern char *of_console_options;
 extern void irq_trans_init(struct device_node *dp);
 extern char *build_path_component(struct device_node *dp);
 
+/* SPARC has a local implementation */
+extern int of_address_to_resource(struct device_node *dev, int index,
+                                 struct resource *r);
+#define of_address_to_resource of_address_to_resource
+
 #endif /* __KERNEL__ */
 #endif /* _SPARC_PROM_H */
index 4e22766..a3fe4dc 100644 (file)
@@ -259,6 +259,11 @@ static inline bool test_and_clear_restore_sigmask(void)
 
 #define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
 
+#define thread32_stack_is_64bit(__SP) (((__SP) & 0x1) != 0)
+#define test_thread_64bit_stack(__SP) \
+       ((test_thread_flag(TIF_32BIT) && !thread32_stack_is_64bit(__SP)) ? \
+        false : true)
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 48f2807..71b5a67 100644 (file)
@@ -372,7 +372,9 @@ etrap_spill_fixup_64bit:                            \
 
 /* Normal 32bit spill */
 #define SPILL_2_GENERIC(ASI)                           \
-       srl     %sp, 0, %sp;                            \
+       and     %sp, 1, %g3;                            \
+       brnz,pn %g3, (. - (128 + 4));                   \
+        srl    %sp, 0, %sp;                            \
        stwa    %l0, [%sp + %g0] ASI;                   \
        mov     0x04, %g3;                              \
        stwa    %l1, [%sp + %g3] ASI;                   \
@@ -398,14 +400,16 @@ etrap_spill_fixup_64bit:                          \
        stwa    %i6, [%g1 + %g0] ASI;                   \
        stwa    %i7, [%g1 + %g3] ASI;                   \
        saved;                                          \
-        retry; nop; nop;                               \
+        retry;                                         \
        b,a,pt  %xcc, spill_fixup_dax;                  \
        b,a,pt  %xcc, spill_fixup_mna;                  \
        b,a,pt  %xcc, spill_fixup;
 
 #define SPILL_2_GENERIC_ETRAP          \
 etrap_user_spill_32bit:                        \
-       srl     %sp, 0, %sp;            \
+       and     %sp, 1, %g3;            \
+       brnz,pn %g3, etrap_user_spill_64bit;    \
+        srl    %sp, 0, %sp;            \
        stwa    %l0, [%sp + 0x00] %asi; \
        stwa    %l1, [%sp + 0x04] %asi; \
        stwa    %l2, [%sp + 0x08] %asi; \
@@ -427,7 +431,7 @@ etrap_user_spill_32bit:                     \
        ba,pt   %xcc, etrap_save;       \
         wrpr   %g1, %cwp;              \
        nop; nop; nop; nop;             \
-       nop; nop; nop; nop;             \
+       nop; nop;                       \
        ba,a,pt %xcc, etrap_spill_fixup_32bit; \
        ba,a,pt %xcc, etrap_spill_fixup_32bit; \
        ba,a,pt %xcc, etrap_spill_fixup_32bit;
@@ -592,7 +596,9 @@ user_rtt_fill_64bit:                                        \
 
 /* Normal 32bit fill */
 #define FILL_2_GENERIC(ASI)                            \
-       srl     %sp, 0, %sp;                            \
+       and     %sp, 1, %g3;                            \
+       brnz,pn %g3, (. - (128 + 4));                   \
+        srl    %sp, 0, %sp;                            \
        lduwa   [%sp + %g0] ASI, %l0;                   \
        mov     0x04, %g2;                              \
        mov     0x08, %g3;                              \
@@ -616,14 +622,16 @@ user_rtt_fill_64bit:                                      \
        lduwa   [%g1 + %g3] ASI, %i6;                   \
        lduwa   [%g1 + %g5] ASI, %i7;                   \
        restored;                                       \
-       retry; nop; nop; nop; nop;                      \
+       retry; nop; nop;                                \
        b,a,pt  %xcc, fill_fixup_dax;                   \
        b,a,pt  %xcc, fill_fixup_mna;                   \
        b,a,pt  %xcc, fill_fixup;
 
 #define FILL_2_GENERIC_RTRAP                           \
 user_rtt_fill_32bit:                                   \
-       srl     %sp, 0, %sp;                            \
+       and     %sp, 1, %g3;                            \
+       brnz,pn %g3, user_rtt_fill_64bit;               \
+        srl    %sp, 0, %sp;                            \
        lduwa   [%sp + 0x00] %asi, %l0;                 \
        lduwa   [%sp + 0x04] %asi, %l1;                 \
        lduwa   [%sp + 0x08] %asi, %l2;                 \
@@ -643,7 +651,7 @@ user_rtt_fill_32bit:                                        \
        ba,pt   %xcc, user_rtt_pre_restore;             \
         restored;                                      \
        nop; nop; nop; nop; nop;                        \
-       nop; nop; nop; nop; nop;                        \
+       nop; nop; nop;                                  \
        ba,a,pt %xcc, user_rtt_fill_fixup;              \
        ba,a,pt %xcc, user_rtt_fill_fixup;              \
        ba,a,pt %xcc, user_rtt_fill_fixup;
index 8974ef7..cac719d 100644 (file)
 #define __NR_setns             337
 #define __NR_process_vm_readv  338
 #define __NR_process_vm_writev 339
+#define __NR_kern_features     340
+#define __NR_kcmp              341
 
-#define NR_syscalls            340
+#define NR_syscalls            342
+
+/* Bitmask values returned from kern_features system call.  */
+#define KERN_FEATURE_MIXED_MODE_STACK  0x00000001
 
 #ifdef __32bit_syscall_numbers__
 /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
index 0c218e4..cc3c5cb 100644 (file)
@@ -59,6 +59,13 @@ struct popc_6insn_patch_entry {
 extern struct popc_6insn_patch_entry __popc_6insn_patch,
        __popc_6insn_patch_end;
 
+struct pause_patch_entry {
+       unsigned int    addr;
+       unsigned int    insns[3];
+};
+extern struct pause_patch_entry __pause_3insn_patch,
+       __pause_3insn_patch_end;
+
 extern void __init per_cpu_patch(void);
 extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *,
                                    struct sun4v_1insn_patch_entry *);
index f8b6eee..87f60ee 100644 (file)
@@ -56,11 +56,13 @@ static inline unsigned int leon_eirq_get(int cpu)
 static void leon_handle_ext_irq(unsigned int irq, struct irq_desc *desc)
 {
        unsigned int eirq;
+       struct irq_bucket *p;
        int cpu = sparc_leon3_cpuid();
 
        eirq = leon_eirq_get(cpu);
-       if ((eirq & 0x10) && irq_map[eirq]->irq) /* bit4 tells if IRQ happened */
-               generic_handle_irq(irq_map[eirq]->irq);
+       p = irq_map[eirq];
+       if ((eirq & 0x10) && p && p->irq) /* bit4 tells if IRQ happened */
+               generic_handle_irq(p->irq);
 }
 
 /* The extended IRQ controller has been found, this function registers it */
index 885a8af..b5c38fa 100644 (file)
@@ -1762,15 +1762,25 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry,
 
        ufp = regs->u_regs[UREG_I6] & 0xffffffffUL;
        do {
-               struct sparc_stackf32 *usf, sf;
                unsigned long pc;
 
-               usf = (struct sparc_stackf32 *) ufp;
-               if (__copy_from_user_inatomic(&sf, usf, sizeof(sf)))
-                       break;
+               if (thread32_stack_is_64bit(ufp)) {
+                       struct sparc_stackf *usf, sf;
 
-               pc = sf.callers_pc;
-               ufp = (unsigned long)sf.fp;
+                       ufp += STACK_BIAS;
+                       usf = (struct sparc_stackf *) ufp;
+                       if (__copy_from_user_inatomic(&sf, usf, sizeof(sf)))
+                               break;
+                       pc = sf.callers_pc & 0xffffffff;
+                       ufp = ((unsigned long) sf.fp) & 0xffffffff;
+               } else {
+                       struct sparc_stackf32 *usf, sf;
+                       usf = (struct sparc_stackf32 *) ufp;
+                       if (__copy_from_user_inatomic(&sf, usf, sizeof(sf)))
+                               break;
+                       pc = sf.callers_pc;
+                       ufp = (unsigned long)sf.fp;
+               }
                perf_callchain_store(entry, pc);
        } while (entry->nr < PERF_MAX_STACK_DEPTH);
 }
index d778248..c6e0c29 100644 (file)
@@ -452,13 +452,16 @@ void flush_thread(void)
 /* It's a bit more tricky when 64-bit tasks are involved... */
 static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
 {
+       bool stack_64bit = test_thread_64bit_stack(psp);
        unsigned long fp, distance, rval;
 
-       if (!(test_thread_flag(TIF_32BIT))) {
+       if (stack_64bit) {
                csp += STACK_BIAS;
                psp += STACK_BIAS;
                __get_user(fp, &(((struct reg_window __user *)psp)->ins[6]));
                fp += STACK_BIAS;
+               if (test_thread_flag(TIF_32BIT))
+                       fp &= 0xffffffff;
        } else
                __get_user(fp, &(((struct reg_window32 __user *)psp)->ins[6]));
 
@@ -472,7 +475,7 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
        rval = (csp - distance);
        if (copy_in_user((void __user *) rval, (void __user *) psp, distance))
                rval = 0;
-       else if (test_thread_flag(TIF_32BIT)) {
+       else if (!stack_64bit) {
                if (put_user(((u32)csp),
                             &(((struct reg_window32 __user *)rval)->ins[6])))
                        rval = 0;
@@ -507,18 +510,18 @@ void synchronize_user_stack(void)
 
        flush_user_windows();
        if ((window = get_thread_wsaved()) != 0) {
-               int winsize = sizeof(struct reg_window);
-               int bias = 0;
-
-               if (test_thread_flag(TIF_32BIT))
-                       winsize = sizeof(struct reg_window32);
-               else
-                       bias = STACK_BIAS;
-
                window -= 1;
                do {
-                       unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
                        struct reg_window *rwin = &t->reg_window[window];
+                       int winsize = sizeof(struct reg_window);
+                       unsigned long sp;
+
+                       sp = t->rwbuf_stkptrs[window];
+
+                       if (test_thread_64bit_stack(sp))
+                               sp += STACK_BIAS;
+                       else
+                               winsize = sizeof(struct reg_window32);
 
                        if (!copy_to_user((char __user *)sp, rwin, winsize)) {
                                shift_window_buffer(window, get_thread_wsaved() - 1, t);
@@ -544,13 +547,6 @@ void fault_in_user_windows(void)
 {
        struct thread_info *t = current_thread_info();
        unsigned long window;
-       int winsize = sizeof(struct reg_window);
-       int bias = 0;
-
-       if (test_thread_flag(TIF_32BIT))
-               winsize = sizeof(struct reg_window32);
-       else
-               bias = STACK_BIAS;
 
        flush_user_windows();
        window = get_thread_wsaved();
@@ -558,8 +554,16 @@ void fault_in_user_windows(void)
        if (likely(window != 0)) {
                window -= 1;
                do {
-                       unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
                        struct reg_window *rwin = &t->reg_window[window];
+                       int winsize = sizeof(struct reg_window);
+                       unsigned long sp;
+
+                       sp = t->rwbuf_stkptrs[window];
+
+                       if (test_thread_64bit_stack(sp))
+                               sp += STACK_BIAS;
+                       else
+                               winsize = sizeof(struct reg_window32);
 
                        if (unlikely(sp & 0x7UL))
                                stack_unaligned(sp);
index 484daba..7ff45e4 100644 (file)
@@ -151,7 +151,7 @@ static int regwindow64_get(struct task_struct *target,
 {
        unsigned long rw_addr = regs->u_regs[UREG_I6];
 
-       if (test_tsk_thread_flag(current, TIF_32BIT)) {
+       if (!test_thread_64bit_stack(rw_addr)) {
                struct reg_window32 win32;
                int i;
 
@@ -176,7 +176,7 @@ static int regwindow64_set(struct task_struct *target,
 {
        unsigned long rw_addr = regs->u_regs[UREG_I6];
 
-       if (test_tsk_thread_flag(current, TIF_32BIT)) {
+       if (!test_thread_64bit_stack(rw_addr)) {
                struct reg_window32 win32;
                int i;
 
index 0800e71..0eaf005 100644 (file)
@@ -316,6 +316,25 @@ static void __init popc_patch(void)
        }
 }
 
+static void __init pause_patch(void)
+{
+       struct pause_patch_entry *p;
+
+       p = &__pause_3insn_patch;
+       while (p < &__pause_3insn_patch_end) {
+               unsigned long i, addr = p->addr;
+
+               for (i = 0; i < 3; i++) {
+                       *(unsigned int *) (addr +  (i * 4)) = p->insns[i];
+                       wmb();
+                       __asm__ __volatile__("flush     %0"
+                                            : : "r" (addr +  (i * 4)));
+               }
+
+               p++;
+       }
+}
+
 #ifdef CONFIG_SMP
 void __init boot_cpu_id_too_large(int cpu)
 {
@@ -528,6 +547,8 @@ static void __init init_sparc64_elf_hwcap(void)
 
        if (sparc64_elf_hwcap & AV_SPARC_POPC)
                popc_patch();
+       if (sparc64_elf_hwcap & AV_SPARC_PAUSE)
+               pause_patch();
 }
 
 void __init setup_arch(char **cmdline_p)
index 11c6c96..878ef3d 100644 (file)
@@ -751,3 +751,8 @@ int kernel_execve(const char *filename,
                      : "cc");
        return __res;
 }
+
+asmlinkage long sys_kern_features(void)
+{
+       return KERN_FEATURE_MIXED_MODE_STACK;
+}
index 63402f9..5147f57 100644 (file)
@@ -85,3 +85,4 @@ sys_call_table:
 /*325*/        .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
 /*330*/        .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
 /*335*/        .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
+/*340*/        .long sys_ni_syscall, sys_kcmp
index 3a58e0d..1c9af9f 100644 (file)
@@ -86,6 +86,7 @@ sys_call_table32:
        .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init
 /*330*/        .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime
        .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev
+/*340*/        .word sys_kern_features, sys_kcmp
 
 #endif /* CONFIG_COMPAT */
 
@@ -163,3 +164,4 @@ sys_call_table:
        .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
 /*330*/        .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
        .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
+/*340*/        .word sys_kern_features, sys_kcmp
index f81d038..8201c25 100644 (file)
@@ -113,21 +113,24 @@ static inline long sign_extend_imm13(long imm)
 
 static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
 {
-       unsigned long value;
+       unsigned long value, fp;
        
        if (reg < 16)
                return (!reg ? 0 : regs->u_regs[reg]);
+
+       fp = regs->u_regs[UREG_FP];
+
        if (regs->tstate & TSTATE_PRIV) {
                struct reg_window *win;
-               win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+               win = (struct reg_window *)(fp + STACK_BIAS);
                value = win->locals[reg - 16];
-       } else if (test_thread_flag(TIF_32BIT)) {
+       } else if (!test_thread_64bit_stack(fp)) {
                struct reg_window32 __user *win32;
-               win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
+               win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp));
                get_user(value, &win32->locals[reg - 16]);
        } else {
                struct reg_window __user *win;
-               win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+               win = (struct reg_window __user *)(fp + STACK_BIAS);
                get_user(value, &win->locals[reg - 16]);
        }
        return value;
@@ -135,19 +138,24 @@ static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
 
 static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
 {
+       unsigned long fp;
+
        if (reg < 16)
                return &regs->u_regs[reg];
+
+       fp = regs->u_regs[UREG_FP];
+
        if (regs->tstate & TSTATE_PRIV) {
                struct reg_window *win;
-               win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+               win = (struct reg_window *)(fp + STACK_BIAS);
                return &win->locals[reg - 16];
-       } else if (test_thread_flag(TIF_32BIT)) {
+       } else if (!test_thread_64bit_stack(fp)) {
                struct reg_window32 *win32;
-               win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
+               win32 = (struct reg_window32 *)((unsigned long)((u32)fp));
                return (unsigned long *)&win32->locals[reg - 16];
        } else {
                struct reg_window *win;
-               win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+               win = (struct reg_window *)(fp + STACK_BIAS);
                return &win->locals[reg - 16];
        }
 }
@@ -392,13 +400,15 @@ int handle_popc(u32 insn, struct pt_regs *regs)
                if (rd)
                        regs->u_regs[rd] = ret;
        } else {
-               if (test_thread_flag(TIF_32BIT)) {
+               unsigned long fp = regs->u_regs[UREG_FP];
+
+               if (!test_thread_64bit_stack(fp)) {
                        struct reg_window32 __user *win32;
-                       win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
+                       win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp));
                        put_user(ret, &win32->locals[rd - 16]);
                } else {
                        struct reg_window __user *win;
-                       win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+                       win = (struct reg_window __user *)(fp + STACK_BIAS);
                        put_user(ret, &win->locals[rd - 16]);
                }
        }
@@ -554,7 +564,7 @@ void handle_ld_nf(u32 insn, struct pt_regs *regs)
                reg[0] = 0;
                if ((insn & 0x780000) == 0x180000)
                        reg[1] = 0;
-       } else if (test_thread_flag(TIF_32BIT)) {
+       } else if (!test_thread_64bit_stack(regs->u_regs[UREG_FP])) {
                put_user(0, (int __user *) reg);
                if ((insn & 0x780000) == 0x180000)
                        put_user(0, ((int __user *) reg) + 1);
index 08e074b..c096c62 100644 (file)
@@ -149,21 +149,24 @@ static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
 
 static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
 {
-       unsigned long value;
+       unsigned long value, fp;
        
        if (reg < 16)
                return (!reg ? 0 : regs->u_regs[reg]);
+
+       fp = regs->u_regs[UREG_FP];
+
        if (regs->tstate & TSTATE_PRIV) {
                struct reg_window *win;
-               win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+               win = (struct reg_window *)(fp + STACK_BIAS);
                value = win->locals[reg - 16];
-       } else if (test_thread_flag(TIF_32BIT)) {
+       } else if (!test_thread_64bit_stack(fp)) {
                struct reg_window32 __user *win32;
-               win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
+               win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp));
                get_user(value, &win32->locals[reg - 16]);
        } else {
                struct reg_window __user *win;
-               win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+               win = (struct reg_window __user *)(fp + STACK_BIAS);
                get_user(value, &win->locals[reg - 16]);
        }
        return value;
@@ -172,16 +175,18 @@ static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
 static inline unsigned long __user *__fetch_reg_addr_user(unsigned int reg,
                                                          struct pt_regs *regs)
 {
+       unsigned long fp = regs->u_regs[UREG_FP];
+
        BUG_ON(reg < 16);
        BUG_ON(regs->tstate & TSTATE_PRIV);
 
-       if (test_thread_flag(TIF_32BIT)) {
+       if (!test_thread_64bit_stack(fp)) {
                struct reg_window32 __user *win32;
-               win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
+               win32 = (struct reg_window32 __user *)((unsigned long)((u32)fp));
                return (unsigned long __user *)&win32->locals[reg - 16];
        } else {
                struct reg_window __user *win;
-               win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+               win = (struct reg_window __user *)(fp + STACK_BIAS);
                return &win->locals[reg - 16];
        }
 }
@@ -204,7 +209,7 @@ static void store_reg(struct pt_regs *regs, unsigned long val, unsigned long rd)
        } else {
                unsigned long __user *rd_user = __fetch_reg_addr_user(rd, regs);
 
-               if (test_thread_flag(TIF_32BIT))
+               if (!test_thread_64bit_stack(regs->u_regs[UREG_FP]))
                        __put_user((u32)val, (u32 __user *)rd_user);
                else
                        __put_user(val, rd_user);
index 89c2c29..0bacceb 100644 (file)
@@ -132,6 +132,11 @@ SECTIONS
                *(.popc_6insn_patch)
                __popc_6insn_patch_end = .;
        }
+       .pause_3insn_patch : {
+               __pause_3insn_patch = .;
+               *(.pause_3insn_patch)
+               __pause_3insn_patch_end = .;
+       }
        PERCPU_SECTION(SMP_CACHE_BYTES)
 
        . = ALIGN(PAGE_SIZE);
index a6b0863..1e67ce9 100644 (file)
@@ -43,6 +43,8 @@ spill_fixup_mna:
 spill_fixup_dax:
        TRAP_LOAD_THREAD_REG(%g6, %g1)
        ldx     [%g6 + TI_FLAGS], %g1
+       andcc   %sp, 0x1, %g0
+       movne   %icc, 0, %g1
        andcc   %g1, _TIF_32BIT, %g0
        ldub    [%g6 + TI_WSAVED], %g1
        sll     %g1, 3, %g3
index 4d502da..85c233d 100644 (file)
@@ -1,6 +1,6 @@
 /* atomic.S: These things are too big to do inline.
  *
- * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1999, 2007 2012 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/linkage.h>
@@ -117,3 +117,17 @@ ENTRY(atomic64_sub_ret) /* %o0 = decrement, %o1 = atomic_ptr */
         sub    %g1, %o0, %o0
 2:     BACKOFF_SPIN(%o2, %o3, 1b)
 ENDPROC(atomic64_sub_ret)
+
+ENTRY(atomic64_dec_if_positive) /* %o0 = atomic_ptr */
+       BACKOFF_SETUP(%o2)
+1:     ldx     [%o0], %g1
+       brlez,pn %g1, 3f
+        sub    %g1, 1, %g7
+       casx    [%o0], %g1, %g7
+       cmp     %g1, %g7
+       bne,pn  %xcc, BACKOFF_LABEL(2f, 1b)
+        nop
+3:     retl
+        sub    %g1, 1, %o0
+2:     BACKOFF_SPIN(%o2, %o3, 1b)
+ENDPROC(atomic64_dec_if_positive)
index ee31b88..0c4e35e 100644 (file)
@@ -116,6 +116,7 @@ EXPORT_SYMBOL(atomic64_add);
 EXPORT_SYMBOL(atomic64_add_ret);
 EXPORT_SYMBOL(atomic64_sub);
 EXPORT_SYMBOL(atomic64_sub_ret);
+EXPORT_SYMBOL(atomic64_dec_if_positive);
 
 /* Atomic bit operations. */
 EXPORT_SYMBOL(test_and_set_bit);
index 1704068..034aadb 100644 (file)
@@ -320,7 +320,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap)
                                        XR = 0;
                                else if (freg < 16)
                                        XR = regs->u_regs[freg];
-                               else if (test_thread_flag(TIF_32BIT)) {
+                               else if (!test_thread_64bit_stack(regs->u_regs[UREG_FP])) {
                                        struct reg_window32 __user *win32;
                                        flushw_user ();
                                        win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
index 59c226d..c20d1ce 100644 (file)
@@ -359,18 +359,14 @@ HYPERVISOR_update_va_mapping(unsigned long va, pte_t new_val,
                return _hypercall4(int, update_va_mapping, va,
                                   new_val.pte, new_val.pte >> 32, flags);
 }
+extern int __must_check xen_event_channel_op_compat(int, void *);
 
 static inline int
 HYPERVISOR_event_channel_op(int cmd, void *arg)
 {
        int rc = _hypercall2(int, event_channel_op, cmd, arg);
-       if (unlikely(rc == -ENOSYS)) {
-               struct evtchn_op op;
-               op.cmd = cmd;
-               memcpy(&op.u, arg, sizeof(op.u));
-               rc = _hypercall1(int, event_channel_op_compat, &op);
-               memcpy(arg, &op.u, sizeof(op.u));
-       }
+       if (unlikely(rc == -ENOSYS))
+               rc = xen_event_channel_op_compat(cmd, arg);
        return rc;
 }
 
@@ -386,17 +382,14 @@ HYPERVISOR_console_io(int cmd, int count, char *str)
        return _hypercall3(int, console_io, cmd, count, str);
 }
 
+extern int __must_check HYPERVISOR_physdev_op_compat(int, void *);
+
 static inline int
 HYPERVISOR_physdev_op(int cmd, void *arg)
 {
        int rc = _hypercall2(int, physdev_op, cmd, arg);
-       if (unlikely(rc == -ENOSYS)) {
-               struct physdev_op op;
-               op.cmd = cmd;
-               memcpy(&op.u, arg, sizeof(op.u));
-               rc = _hypercall1(int, physdev_op_compat, &op);
-               memcpy(arg, &op.u, sizeof(op.u));
-       }
+       if (unlikely(rc == -ENOSYS))
+               rc = HYPERVISOR_physdev_op_compat(cmd, arg);
        return rc;
 }
 
index 66d0fff..125f344 100644 (file)
@@ -33,7 +33,6 @@
 #ifndef _ASM_X86_XEN_HYPERVISOR_H
 #define _ASM_X86_XEN_HYPERVISOR_H
 
-/* arch/i386/kernel/setup.c */
 extern struct shared_info *HYPERVISOR_shared_info;
 extern struct start_info *xen_start_info;
 
index 1eefebe..224a7e7 100644 (file)
@@ -3779,7 +3779,7 @@ static int write_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa,
 {
        struct kvm_mmio_fragment *frag = &vcpu->mmio_fragments[0];
 
-       memcpy(vcpu->run->mmio.data, frag->data, frag->len);
+       memcpy(vcpu->run->mmio.data, frag->data, min(8u, frag->len));
        return X86EMUL_CONTINUE;
 }
 
@@ -3832,18 +3832,11 @@ mmio:
        bytes -= handled;
        val += handled;
 
-       while (bytes) {
-               unsigned now = min(bytes, 8U);
-
-               frag = &vcpu->mmio_fragments[vcpu->mmio_nr_fragments++];
-               frag->gpa = gpa;
-               frag->data = val;
-               frag->len = now;
-
-               gpa += now;
-               val += now;
-               bytes -= now;
-       }
+       WARN_ON(vcpu->mmio_nr_fragments >= KVM_MAX_MMIO_FRAGMENTS);
+       frag = &vcpu->mmio_fragments[vcpu->mmio_nr_fragments++];
+       frag->gpa = gpa;
+       frag->data = val;
+       frag->len = bytes;
        return X86EMUL_CONTINUE;
 }
 
@@ -3890,7 +3883,7 @@ int emulator_read_write(struct x86_emulate_ctxt *ctxt, unsigned long addr,
        vcpu->mmio_needed = 1;
        vcpu->mmio_cur_fragment = 0;
 
-       vcpu->run->mmio.len = vcpu->mmio_fragments[0].len;
+       vcpu->run->mmio.len = min(8u, vcpu->mmio_fragments[0].len);
        vcpu->run->mmio.is_write = vcpu->mmio_is_write = ops->write;
        vcpu->run->exit_reason = KVM_EXIT_MMIO;
        vcpu->run->mmio.phys_addr = gpa;
@@ -5522,28 +5515,44 @@ static int complete_emulated_pio(struct kvm_vcpu *vcpu)
  *
  * read:
  *   for each fragment
- *     write gpa, len
- *     exit
- *     copy data
+ *     for each mmio piece in the fragment
+ *       write gpa, len
+ *       exit
+ *       copy data
  *   execute insn
  *
  * write:
  *   for each fragment
- *      write gpa, len
- *      copy data
- *      exit
+ *     for each mmio piece in the fragment
+ *       write gpa, len
+ *       copy data
+ *       exit
  */
 static int complete_emulated_mmio(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
        struct kvm_mmio_fragment *frag;
+       unsigned len;
 
        BUG_ON(!vcpu->mmio_needed);
 
        /* Complete previous fragment */
-       frag = &vcpu->mmio_fragments[vcpu->mmio_cur_fragment++];
+       frag = &vcpu->mmio_fragments[vcpu->mmio_cur_fragment];
+       len = min(8u, frag->len);
        if (!vcpu->mmio_is_write)
-               memcpy(frag->data, run->mmio.data, frag->len);
+               memcpy(frag->data, run->mmio.data, len);
+
+       if (frag->len <= 8) {
+               /* Switch to the next fragment. */
+               frag++;
+               vcpu->mmio_cur_fragment++;
+       } else {
+               /* Go forward to the next mmio piece. */
+               frag->data += len;
+               frag->gpa += len;
+               frag->len -= len;
+       }
+
        if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) {
                vcpu->mmio_needed = 0;
                if (vcpu->mmio_is_write)
@@ -5551,13 +5560,12 @@ static int complete_emulated_mmio(struct kvm_vcpu *vcpu)
                vcpu->mmio_read_completed = 1;
                return complete_emulated_io(vcpu);
        }
-       /* Initiate next fragment */
-       ++frag;
+
        run->exit_reason = KVM_EXIT_MMIO;
        run->mmio.phys_addr = frag->gpa;
        if (vcpu->mmio_is_write)
-               memcpy(run->mmio.data, frag->data, frag->len);
-       run->mmio.len = frag->len;
+               memcpy(run->mmio.data, frag->data, min(8u, frag->len));
+       run->mmio.len = min(8u, frag->len);
        run->mmio.is_write = vcpu->mmio_is_write;
        vcpu->arch.complete_userspace_io = complete_emulated_mmio;
        return 0;
index 6226c99..dcf5f2d 100644 (file)
@@ -1288,6 +1288,25 @@ unsigned long xen_read_cr2_direct(void)
        return this_cpu_read(xen_vcpu_info.arch.cr2);
 }
 
+void xen_flush_tlb_all(void)
+{
+       struct mmuext_op *op;
+       struct multicall_space mcs;
+
+       trace_xen_mmu_flush_tlb_all(0);
+
+       preempt_disable();
+
+       mcs = xen_mc_entry(sizeof(*op));
+
+       op = mcs.args;
+       op->cmd = MMUEXT_TLB_FLUSH_ALL;
+       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+       preempt_enable();
+}
 static void xen_flush_tlb(void)
 {
        struct mmuext_op *op;
@@ -2518,7 +2537,7 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
        err = 0;
 out:
 
-       flush_tlb_all();
+       xen_flush_tlb_all();
 
        return err;
 }
index cdcb48a..0d1f36a 100644 (file)
@@ -13,6 +13,8 @@ config XTENSA
        select GENERIC_CPU_DEVICES
        select MODULES_USE_ELF_RELA
        select GENERIC_PCI_IOMAP
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
        select ARCH_WANT_OPTIONAL_GPIOLIB
        help
          Xtensa processors are 32-bit RISC machines designed by Tensilica
index e6be5b9..700c2e6 100644 (file)
@@ -62,6 +62,10 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
 static inline void iounmap(volatile void __iomem *addr)
 {
 }
+
+#define virt_to_bus     virt_to_phys
+#define bus_to_virt     phys_to_virt
+
 #endif /* CONFIG_MMU */
 
 /*
index 5c371d8..2d630e7 100644 (file)
@@ -152,6 +152,7 @@ struct thread_struct {
 
 /* Clearing a0 terminates the backtrace. */
 #define start_thread(regs, new_pc, new_sp) \
+       memset(regs, 0, sizeof(*regs)); \
        regs->pc = new_pc; \
        regs->ps = USER_PS_VALUE; \
        regs->areg[1] = new_sp; \
@@ -168,9 +169,6 @@ struct mm_struct;
 /* Free all resources held by a thread. */
 #define release_thread(thread) do { } while(0)
 
-/* Create a kernel thread without removing it from tasklists */
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
 /* Copy and release all segment info associated with a VM */
 #define copy_segments(p, mm)   do { } while(0)
 #define release_segments(mm)   do { } while(0)
index c1dacca..124aeee 100644 (file)
@@ -10,7 +10,7 @@
 
 struct pt_regs;
 struct sigaction;
-asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*);
+asmlinkage long sys_execve(char*, char**, char**, struct pt_regs*);
 asmlinkage long xtensa_clone(unsigned long, unsigned long, struct pt_regs*);
 asmlinkage long xtensa_ptrace(long, long, long, long);
 asmlinkage long xtensa_sigreturn(struct pt_regs*);
index 9ef1c31..f4e6eaa 100644 (file)
@@ -1,16 +1,9 @@
-/*
- * include/asm-xtensa/unistd.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
+#ifndef _XTENSA_UNISTD_H
+#define _XTENSA_UNISTD_H
 
+#define __ARCH_WANT_SYS_EXECVE
 #include <uapi/asm/unistd.h>
 
-
 /*
  * "Conditional" syscalls
  *
@@ -37,3 +30,5 @@
 #define __IGNORE_mmap                          /* use mmap2 */
 #define __IGNORE_vfork                         /* use clone */
 #define __IGNORE_fadvise64                     /* use fadvise64_64 */
+
+#endif /* _XTENSA_UNISTD_H */
index 479abae..9f36d0e 100644 (file)
@@ -1,14 +1,4 @@
-/*
- * include/asm-xtensa/unistd.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2012 Tensilica Inc.
- */
-
-#ifndef _UAPI_XTENSA_UNISTD_H
+#if !defined(_UAPI_XTENSA_UNISTD_H) || defined(__SYSCALL)
 #define _UAPI_XTENSA_UNISTD_H
 
 #ifndef __SYSCALL
@@ -272,7 +262,7 @@ __SYSCALL(115, sys_sendmmsg, 4)
 #define __NR_clone                             116
 __SYSCALL(116, xtensa_clone, 5)
 #define __NR_execve                            117
-__SYSCALL(117, xtensa_execve, 3)
+__SYSCALL(117, sys_execve, 3)
 #define __NR_exit                              118
 __SYSCALL(118, sys_exit, 1)
 #define __NR_exit_group                        119
@@ -759,4 +749,6 @@ __SYSCALL(331, sys_kcmp, 5)
 
 #define SYS_XTENSA_COUNT                  5     /* count */
 
+#undef __SYSCALL
+
 #endif /* _UAPI_XTENSA_UNISTD_H */
index 1845306..90bfc1d 100644 (file)
@@ -1833,50 +1833,6 @@ ENTRY(system_call)
 
 
 /*
- * Create a kernel thread
- *
- * int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
- * a2                    a2                 a3             a4
- */
-
-ENTRY(kernel_thread)
-       entry   a1, 16
-
-       mov     a5, a2                  # preserve fn over syscall
-       mov     a7, a3                  # preserve args over syscall
-
-       movi    a3, _CLONE_VM | _CLONE_UNTRACED
-       movi    a2, __NR_clone
-       or      a6, a4, a3              # arg0: flags
-       mov     a3, a1                  # arg1: sp
-       syscall
-
-       beq     a3, a1, 1f              # branch if parent
-       mov     a6, a7                  # args
-       callx4  a5                      # fn(args)
-
-       movi    a2, __NR_exit
-       syscall                         # return value of fn(args) still in a6
-
-1:     retw
-
-/*
- * Do a system call from kernel instead of calling sys_execve, so we end up
- * with proper pt_regs.
- *
- * int kernel_execve(const char *fname, char *const argv[], charg *const envp[])
- * a2                        a2               a3                  a4
- */
-
-ENTRY(kernel_execve)
-       entry   a1, 16
-       mov     a6, a2                  # arg0 is in a6
-       movi    a2, __NR_execve
-       syscall
-
-       retw
-
-/*
  * Task switch.
  *
  * struct task*  _switch_to (struct task* prev, struct task* next)
@@ -1958,3 +1914,16 @@ ENTRY(ret_from_fork)
 
        j       common_exception_return
 
+/*
+ * Kernel thread creation helper
+ * On entry, set up by copy_thread: a2 = thread_fn, a3 = thread_fn arg
+ *           left from _switch_to: a6 = prev
+ */
+ENTRY(ret_from_kernel_thread)
+
+       call4   schedule_tail
+       mov     a6, a3
+       callx4  a2
+       j       common_exception_return
+
+ENDPROC(ret_from_kernel_thread)
index 1908f66..09ae7bf 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/regs.h>
 
 extern void ret_from_fork(void);
+extern void ret_from_kernel_thread(void);
 
 struct task_struct *current_set[NR_CPUS] = {&init_task, };
 
@@ -158,18 +159,30 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 /*
  * Copy thread.
  *
+ * There are two modes in which this function is called:
+ * 1) Userspace thread creation,
+ *    regs != NULL, usp_thread_fn is userspace stack pointer.
+ *    It is expected to copy parent regs (in case CLONE_VM is not set
+ *    in the clone_flags) and set up passed usp in the childregs.
+ * 2) Kernel thread creation,
+ *    regs == NULL, usp_thread_fn is the function to run in the new thread
+ *    and thread_fn_arg is its parameter.
+ *    childregs are not used for the kernel threads.
+ *
  * The stack layout for the new thread looks like this:
  *
- *     +------------------------+ <- sp in childregs (= tos)
+ *     +------------------------+
  *     |       childregs        |
  *     +------------------------+ <- thread.sp = sp in dummy-frame
  *     |      dummy-frame       |    (saved in dummy-frame spill-area)
  *     +------------------------+
  *
- * We create a dummy frame to return to ret_from_fork:
- *   a0 points to ret_from_fork (simulating a call4)
+ * We create a dummy frame to return to either ret_from_fork or
+ *   ret_from_kernel_thread:
+ *   a0 points to ret_from_fork/ret_from_kernel_thread (simulating a call4)
  *   sp points to itself (thread.sp)
- *   a2, a3 are unused.
+ *   a2, a3 are unused for userspace threads,
+ *   a2 points to thread_fn, a3 holds thread_fn arg for kernel threads.
  *
  * Note: This is a pristine frame, so we don't need any spill region on top of
  *       childregs.
@@ -185,43 +198,63 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
  * involved.  Much simpler to just not copy those live frames across.
  */
 
-int copy_thread(unsigned long clone_flags, unsigned long usp,
-               unsigned long unused,
-                struct task_struct * p, struct pt_regs * regs)
+int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
+               unsigned long thread_fn_arg,
+               struct task_struct *p, struct pt_regs *unused)
 {
-       struct pt_regs *childregs;
-       unsigned long tos;
-       int user_mode = user_mode(regs);
+       struct pt_regs *childregs = task_pt_regs(p);
 
 #if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
        struct thread_info *ti;
 #endif
 
-       /* Set up new TSS. */
-       tos = (unsigned long)task_stack_page(p) + THREAD_SIZE;
-       if (user_mode)
-               childregs = (struct pt_regs*)(tos - PT_USER_SIZE);
-       else
-               childregs = (struct pt_regs*)tos - 1;
-
-       /* This does not copy all the regs.  In a bout of brilliance or madness,
-          ARs beyond a0-a15 exist past the end of the struct. */
-       *childregs = *regs;
-
        /* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */
        *((int*)childregs - 3) = (unsigned long)childregs;
        *((int*)childregs - 4) = 0;
 
-       childregs->areg[2] = 0;
-       p->set_child_tid = p->clear_child_tid = NULL;
-       p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1);
        p->thread.sp = (unsigned long)childregs;
 
-       if (user_mode(regs)) {
+       if (!(p->flags & PF_KTHREAD)) {
+               struct pt_regs *regs = current_pt_regs();
+               unsigned long usp = usp_thread_fn ?
+                       usp_thread_fn : regs->areg[1];
 
+               p->thread.ra = MAKE_RA_FOR_CALL(
+                               (unsigned long)ret_from_fork, 0x1);
+
+               /* This does not copy all the regs.
+                * In a bout of brilliance or madness,
+                * ARs beyond a0-a15 exist past the end of the struct.
+                */
+               *childregs = *regs;
                childregs->areg[1] = usp;
+               childregs->areg[2] = 0;
+
+               /* When sharing memory with the parent thread, the child
+                  usually starts on a pristine stack, so we have to reset
+                  windowbase, windowstart and wmask.
+                  (Note that such a new thread is required to always create
+                  an initial call4 frame)
+                  The exception is vfork, where the new thread continues to
+                  run on the parent's stack until it calls execve. This could
+                  be a call8 or call12, which requires a legal stack frame
+                  of the previous caller for the overflow handlers to work.
+                  (Note that it's always legal to overflow live registers).
+                  In this case, ensure to spill at least the stack pointer
+                  of that frame. */
+
                if (clone_flags & CLONE_VM) {
-                       childregs->wmask = 1;   /* can't share live windows */
+                       /* check that caller window is live and same stack */
+                       int len = childregs->wmask & ~0xf;
+                       if (regs->areg[1] == usp && len != 0) {
+                               int callinc = (regs->areg[0] >> 30) & 3;
+                               int caller_ars = XCHAL_NUM_AREGS - callinc * 4;
+                               put_user(regs->areg[caller_ars+1],
+                                        (unsigned __user*)(usp - 12));
+                       }
+                       childregs->wmask = 1;
+                       childregs->windowstart = 1;
+                       childregs->windowbase = 0;
                } else {
                        int len = childregs->wmask & ~0xf;
                        memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
@@ -230,11 +263,19 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
 // FIXME: we need to set THREADPTR in thread_info...
                if (clone_flags & CLONE_SETTLS)
                        childregs->areg[2] = childregs->areg[6];
-
        } else {
-               /* In kernel space, we start a new thread with a new stack. */
-               childregs->wmask = 1;
-               childregs->areg[1] = tos;
+               p->thread.ra = MAKE_RA_FOR_CALL(
+                               (unsigned long)ret_from_kernel_thread, 1);
+
+               /* pass parameters to ret_from_kernel_thread:
+                * a2 = thread_fn, a3 = thread_fn arg
+                */
+               *((int *)childregs - 1) = thread_fn_arg;
+               *((int *)childregs - 2) = usp_thread_fn;
+
+               /* Childregs are only used when we're going to userspace
+                * in which case start_thread will set them up.
+                */
        }
 
 #if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
@@ -330,32 +371,5 @@ long xtensa_clone(unsigned long clone_flags, unsigned long newsp,
                   void __user *child_tid, long a5,
                   struct pt_regs *regs)
 {
-        if (!newsp)
-                newsp = regs->areg[1];
         return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
 }
-
-/*
- * xtensa_execve() executes a new program.
- */
-
-asmlinkage
-long xtensa_execve(const char __user *name,
-                  const char __user *const __user *argv,
-                   const char __user *const __user *envp,
-                   long a3, long a4, long a5,
-                   struct pt_regs *regs)
-{
-       long error;
-       struct filename *filename;
-
-       filename = getname(name);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-       error = do_execve(filename->name, argv, envp, regs);
-       putname(filename);
-out:
-       return error;
-}
-
index a5c01e7..5702065 100644 (file)
@@ -32,10 +32,8 @@ typedef void (*syscall_t)(void);
 syscall_t sys_call_table[__NR_syscall_count] /* FIXME __cacheline_aligned */= {
        [0 ... __NR_syscall_count - 1] = (syscall_t)&sys_ni_syscall,
 
-#undef __SYSCALL
 #define __SYSCALL(nr,symbol,nargs) [ nr ] = (syscall_t)symbol,
-#undef  __KERNEL_SYSCALLS__
-#include <asm/unistd.h>
+#include <uapi/asm/unistd.h>
 };
 
 asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
@@ -49,7 +47,8 @@ asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
        return (long)ret;
 }
 
-asmlinkage long xtensa_fadvise64_64(int fd, int advice, unsigned long long offset, unsigned long long len)
+asmlinkage long xtensa_fadvise64_64(int fd, int advice,
+               unsigned long long offset, unsigned long long len)
 {
        return sys_fadvise64_64(fd, offset, len, advice);
 }
index a8b9f1f..afe058b 100644 (file)
@@ -43,7 +43,6 @@ EXPORT_SYMBOL(__strncpy_user);
 EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(copy_page);
 
-EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(empty_zero_page);
 
 /*
index 09acf1b..a7e40a7 100644 (file)
@@ -89,7 +89,7 @@ config BLK_DEV_INTEGRITY
 
 config BLK_DEV_THROTTLING
        bool "Block layer bio throttling support"
-       depends on BLK_CGROUP=y && EXPERIMENTAL
+       depends on BLK_CGROUP=y
        default n
        ---help---
        Block layer bio throttling support. It can be used to limit
index cafcd74..d0b7703 100644 (file)
@@ -285,6 +285,13 @@ static void blkg_destroy_all(struct request_queue *q)
                blkg_destroy(blkg);
                spin_unlock(&blkcg->lock);
        }
+
+       /*
+        * root blkg is destroyed.  Just clear the pointer since
+        * root_rl does not take reference on root blkg.
+        */
+       q->root_blkg = NULL;
+       q->root_rl.blkg = NULL;
 }
 
 static void blkg_rcu_free(struct rcu_head *rcu_head)
@@ -326,6 +333,9 @@ struct request_list *__blk_queue_next_rl(struct request_list *rl,
         */
        if (rl == &q->root_rl) {
                ent = &q->blkg_list;
+               /* There are no more block groups, hence no request lists */
+               if (list_empty(ent))
+                       return NULL;
        } else {
                blkg = container_of(rl, struct blkcg_gq, rl);
                ent = &blkg->q_node;
index a33870b..3c95c4d 100644 (file)
@@ -2868,7 +2868,8 @@ static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
        struct request *rqa = container_of(a, struct request, queuelist);
        struct request *rqb = container_of(b, struct request, queuelist);
 
-       return !(rqa->q <= rqb->q);
+       return !(rqa->q < rqb->q ||
+               (rqa->q == rqb->q && blk_rq_pos(rqa) < blk_rq_pos(rqb)));
 }
 
 /*
index 671d4d6..7bdd61b 100644 (file)
@@ -137,13 +137,18 @@ static void cryptd_queue_worker(struct work_struct *work)
        struct crypto_async_request *req, *backlog;
 
        cpu_queue = container_of(work, struct cryptd_cpu_queue, work);
-       /* Only handle one request at a time to avoid hogging crypto
-        * workqueue. preempt_disable/enable is used to prevent
-        * being preempted by cryptd_enqueue_request() */
+       /*
+        * Only handle one request at a time to avoid hogging crypto workqueue.
+        * preempt_disable/enable is used to prevent being preempted by
+        * cryptd_enqueue_request(). local_bh_disable/enable is used to prevent
+        * cryptd_enqueue_request() being accessed from software interrupts.
+        */
+       local_bh_disable();
        preempt_disable();
        backlog = crypto_get_backlog(&cpu_queue->queue);
        req = crypto_dequeue_request(&cpu_queue->queue);
        preempt_enable();
+       local_bh_enable();
 
        if (!req)
                return;
index f94d4c8..0230cb6 100644 (file)
@@ -1345,12 +1345,15 @@ static int
 acpi_video_bus_get_devices(struct acpi_video_bus *video,
                           struct acpi_device *device)
 {
-       int status;
+       int status = 0;
        struct acpi_device *dev;
 
-       status = acpi_video_device_enumerate(video);
-       if (status)
-               return status;
+       /*
+        * There are systems where video module known to work fine regardless
+        * of broken _DOD and ignoring returned value here doesn't cause
+        * any issues later.
+        */
+       acpi_video_device_enumerate(video);
 
        list_for_each_entry(dev, &device->children, node) {
 
index 8727e9c..72c776f 100644 (file)
@@ -83,9 +83,16 @@ EXPORT_SYMBOL_GPL(platform_get_resource);
  */
 int platform_get_irq(struct platform_device *dev, unsigned int num)
 {
+#ifdef CONFIG_SPARC
+       /* sparc does not have irqs represented as IORESOURCE_IRQ resources */
+       if (!dev || num >= dev->archdata.num_irqs)
+               return -ENXIO;
+       return dev->archdata.irqs[num];
+#else
        struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
 
        return r ? r->start : -ENXIO;
+#endif
 }
 EXPORT_SYMBOL_GPL(platform_get_irq);
 
index f529407..824e09c 100644 (file)
@@ -131,6 +131,7 @@ config BLK_CPQ_DA
 config BLK_CPQ_CISS_DA
        tristate "Compaq Smart Array 5xxx support"
        depends on PCI
+       select CHECK_SIGNATURE
        help
          This is the driver for Compaq Smart Array 5xxx controllers.
          Everyone using these boards should say Y here.
@@ -166,8 +167,8 @@ config BLK_DEV_DAC960
          module will be called DAC960.
 
 config BLK_DEV_UMEM
-       tristate "Micro Memory MM5415 Battery Backed RAM support (EXPERIMENTAL)"
-       depends on PCI && EXPERIMENTAL
+       tristate "Micro Memory MM5415 Battery Backed RAM support"
+       depends on PCI
        ---help---
          Saying Y here will include support for the MM5415 family of
          battery backed (Non-volatile) RAM cards.
@@ -430,8 +431,8 @@ config CDROM_PKTCDVD_BUFFERS
          a disc is opened for writing.
 
 config CDROM_PKTCDVD_WCACHE
-       bool "Enable write caching (EXPERIMENTAL)"
-       depends on CDROM_PKTCDVD && EXPERIMENTAL
+       bool "Enable write caching"
+       depends on CDROM_PKTCDVD
        help
          If enabled, write caching will be set for the CD-R/W device. For now
          this option is dangerous unless the CD-RW media is known good, as we
@@ -508,8 +509,8 @@ config XEN_BLKDEV_BACKEND
 
 
 config VIRTIO_BLK
-       tristate "Virtio block driver (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && VIRTIO
+       tristate "Virtio block driver"
+       depends on VIRTIO
        ---help---
          This is the virtual block driver for virtio.  It can be used with
           lguest or QEMU based VMMs (like KVM or Xen).  Say Y or M.
@@ -528,7 +529,7 @@ config BLK_DEV_HD
 
 config BLK_DEV_RBD
        tristate "Rados block device (RBD)"
-       depends on INET && EXPERIMENTAL && BLOCK
+       depends on INET && BLOCK
        select CEPH_LIB
        select LIBCRC32C
        select CRYPTO_AES
index b0f553b..ca83f96 100644 (file)
@@ -5205,7 +5205,6 @@ static void cciss_shutdown(struct pci_dev *pdev)
                return;
        }
        /* write all data in the battery backed cache to disk */
-       memset(flush_buf, 0, 4);
        return_code = sendcmd_withirq(h, CCISS_CACHE_FLUSH, flush_buf,
                4, 0, CTLR_LUNID, TYPE_CMD);
        kfree(flush_buf);
index 17c675c..1c49d71 100644 (file)
@@ -4109,12 +4109,19 @@ static struct platform_driver floppy_driver = {
 
 static struct platform_device floppy_device[N_DRIVE];
 
+static bool floppy_available(int drive)
+{
+       if (!(allowed_drive_mask & (1 << drive)))
+               return false;
+       if (fdc_state[FDC(drive)].version == FDC_NONE)
+               return false;
+       return true;
+}
+
 static struct kobject *floppy_find(dev_t dev, int *part, void *data)
 {
        int drive = (*part & 3) | ((*part & 0x80) >> 5);
-       if (drive >= N_DRIVE ||
-           !(allowed_drive_mask & (1 << drive)) ||
-           fdc_state[FDC(drive)].version == FDC_NONE)
+       if (drive >= N_DRIVE || !floppy_available(drive))
                return NULL;
        if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
                return NULL;
@@ -4124,8 +4131,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
 
 static int __init do_floppy_init(void)
 {
-       int i, unit, drive;
-       int err, dr;
+       int i, unit, drive, err;
 
        set_debugt();
        interruptjiffies = resultjiffies = jiffies;
@@ -4137,34 +4143,32 @@ static int __init do_floppy_init(void)
 
        raw_cmd = NULL;
 
-       for (dr = 0; dr < N_DRIVE; dr++) {
-               disks[dr] = alloc_disk(1);
-               if (!disks[dr]) {
-                       err = -ENOMEM;
-                       goto out_put_disk;
-               }
+       floppy_wq = alloc_ordered_workqueue("floppy", 0);
+       if (!floppy_wq)
+               return -ENOMEM;
 
-               floppy_wq = alloc_ordered_workqueue("floppy", 0);
-               if (!floppy_wq) {
+       for (drive = 0; drive < N_DRIVE; drive++) {
+               disks[drive] = alloc_disk(1);
+               if (!disks[drive]) {
                        err = -ENOMEM;
                        goto out_put_disk;
                }
 
-               disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock);
-               if (!disks[dr]->queue) {
+               disks[drive]->queue = blk_init_queue(do_fd_request, &floppy_lock);
+               if (!disks[drive]->queue) {
                        err = -ENOMEM;
-                       goto out_destroy_workq;
+                       goto out_put_disk;
                }
 
-               blk_queue_max_hw_sectors(disks[dr]->queue, 64);
-               disks[dr]->major = FLOPPY_MAJOR;
-               disks[dr]->first_minor = TOMINOR(dr);
-               disks[dr]->fops = &floppy_fops;
-               sprintf(disks[dr]->disk_name, "fd%d", dr);
+               blk_queue_max_hw_sectors(disks[drive]->queue, 64);
+               disks[drive]->major = FLOPPY_MAJOR;
+               disks[drive]->first_minor = TOMINOR(drive);
+               disks[drive]->fops = &floppy_fops;
+               sprintf(disks[drive]->disk_name, "fd%d", drive);
 
-               init_timer(&motor_off_timer[dr]);
-               motor_off_timer[dr].data = dr;
-               motor_off_timer[dr].function = motor_off_callback;
+               init_timer(&motor_off_timer[drive]);
+               motor_off_timer[drive].data = drive;
+               motor_off_timer[drive].function = motor_off_callback;
        }
 
        err = register_blkdev(FLOPPY_MAJOR, "fd");
@@ -4282,9 +4286,7 @@ static int __init do_floppy_init(void)
        }
 
        for (drive = 0; drive < N_DRIVE; drive++) {
-               if (!(allowed_drive_mask & (1 << drive)))
-                       continue;
-               if (fdc_state[FDC(drive)].version == FDC_NONE)
+               if (!floppy_available(drive))
                        continue;
 
                floppy_device[drive].name = floppy_device_name;
@@ -4293,7 +4295,7 @@ static int __init do_floppy_init(void)
 
                err = platform_device_register(&floppy_device[drive]);
                if (err)
-                       goto out_release_dma;
+                       goto out_remove_drives;
 
                err = device_create_file(&floppy_device[drive].dev,
                                         &dev_attr_cmos);
@@ -4311,29 +4313,34 @@ static int __init do_floppy_init(void)
 
 out_unreg_platform_dev:
        platform_device_unregister(&floppy_device[drive]);
+out_remove_drives:
+       while (drive--) {
+               if (floppy_available(drive)) {
+                       del_gendisk(disks[drive]);
+                       device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
+                       platform_device_unregister(&floppy_device[drive]);
+               }
+       }
 out_release_dma:
        if (atomic_read(&usage_count))
                floppy_release_irq_and_dma();
 out_unreg_region:
        blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
        platform_driver_unregister(&floppy_driver);
-out_destroy_workq:
-       destroy_workqueue(floppy_wq);
 out_unreg_blkdev:
        unregister_blkdev(FLOPPY_MAJOR, "fd");
 out_put_disk:
-       while (dr--) {
-               del_timer_sync(&motor_off_timer[dr]);
-               if (disks[dr]->queue) {
-                       blk_cleanup_queue(disks[dr]->queue);
-                       /*
-                        * put_disk() is not paired with add_disk() and
-                        * will put queue reference one extra time. fix it.
-                        */
-                       disks[dr]->queue = NULL;
+       for (drive = 0; drive < N_DRIVE; drive++) {
+               if (!disks[drive])
+                       break;
+               if (disks[drive]->queue) {
+                       del_timer_sync(&motor_off_timer[drive]);
+                       blk_cleanup_queue(disks[drive]->queue);
+                       disks[drive]->queue = NULL;
                }
-               put_disk(disks[dr]);
+               put_disk(disks[drive]);
        }
+       destroy_workqueue(floppy_wq);
        return err;
 }
 
@@ -4551,8 +4558,7 @@ static void __exit floppy_module_exit(void)
        for (drive = 0; drive < N_DRIVE; drive++) {
                del_timer_sync(&motor_off_timer[drive]);
 
-               if ((allowed_drive_mask & (1 << drive)) &&
-                   fdc_state[FDC(drive)].version != FDC_NONE) {
+               if (floppy_available(drive)) {
                        del_gendisk(disks[drive]);
                        device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
                        platform_device_unregister(&floppy_device[drive]);
index e9d594f..54046e5 100644 (file)
@@ -976,8 +976,21 @@ static int loop_clr_fd(struct loop_device *lo)
        if (lo->lo_state != Lo_bound)
                return -ENXIO;
 
-       if (lo->lo_refcnt > 1)  /* we needed one fd for the ioctl */
-               return -EBUSY;
+       /*
+        * If we've explicitly asked to tear down the loop device,
+        * and it has an elevated reference count, set it for auto-teardown when
+        * the last reference goes away. This stops $!~#$@ udev from
+        * preventing teardown because it decided that it needs to run blkid on
+        * the loopback device whenever they appear. xfstests is notorious for
+        * failing tests because blkid via udev races with a losetup
+        * <dev>/do something like mkfs/losetup -d <dev> causing the losetup -d
+        * command to fail with EBUSY.
+        */
+       if (lo->lo_refcnt > 1) {
+               lo->lo_flags |= LO_FLAGS_AUTOCLEAR;
+               mutex_unlock(&lo->lo_ctl_mutex);
+               return 0;
+       }
 
        if (filp == NULL)
                return -EINVAL;
index f946d31..adc6f36 100644 (file)
@@ -2035,8 +2035,9 @@ static unsigned int implicit_sector(unsigned char command,
        }
        return rv;
 }
-
-static void mtip_set_timeout(struct host_to_dev_fis *fis, unsigned int *timeout)
+static void mtip_set_timeout(struct driver_data *dd,
+                                       struct host_to_dev_fis *fis,
+                                       unsigned int *timeout, u8 erasemode)
 {
        switch (fis->command) {
        case ATA_CMD_DOWNLOAD_MICRO:
@@ -2044,7 +2045,10 @@ static void mtip_set_timeout(struct host_to_dev_fis *fis, unsigned int *timeout)
                break;
        case ATA_CMD_SEC_ERASE_UNIT:
        case 0xFC:
-               *timeout = 240000; /* 4 minutes */
+               if (erasemode)
+                       *timeout = ((*(dd->port->identify + 90) * 2) * 60000);
+               else
+                       *timeout = ((*(dd->port->identify + 89) * 2) * 60000);
                break;
        case ATA_CMD_STANDBYNOW1:
                *timeout = 120000;  /* 2 minutes */
@@ -2087,6 +2091,7 @@ static int exec_drive_taskfile(struct driver_data *dd,
        unsigned int transfer_size;
        unsigned long task_file_data;
        int intotal = outtotal + req_task->out_size;
+       int erasemode = 0;
 
        taskout = req_task->out_size;
        taskin = req_task->in_size;
@@ -2212,7 +2217,13 @@ static int exec_drive_taskfile(struct driver_data *dd,
                fis.lba_hi,
                fis.device);
 
-       mtip_set_timeout(&fis, &timeout);
+       /* check for erase mode support during secure erase.*/
+       if ((fis.command == ATA_CMD_SEC_ERASE_UNIT)
+                                       && (outbuf[0] & MTIP_SEC_ERASE_MODE)) {
+               erasemode = 1;
+       }
+
+       mtip_set_timeout(dd, &fis, &timeout, erasemode);
 
        /* Determine the correct transfer size.*/
        if (force_single_sector)
index 18627a1..5f4a917 100644 (file)
@@ -33,6 +33,9 @@
 /* offset of Device Control register in PCIe extended capabilites space */
 #define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET  0x48
 
+/* check for erase mode support during secure erase */
+#define MTIP_SEC_ERASE_MODE     0x3
+
 /* # of times to retry timed out/failed IOs */
 #define MTIP_MAX_RETRIES       2
 
index 9ad3b5e..9a54623 100644 (file)
@@ -158,8 +158,8 @@ struct xen_vbd {
        struct block_device     *bdev;
        /* Cached size parameter. */
        sector_t                size;
-       bool                    flush_support;
-       bool                    discard_secure;
+       unsigned int            flush_support:1;
+       unsigned int            discard_secure:1;
 };
 
 struct backend_info;
index 4f66171..f58434c 100644 (file)
@@ -105,11 +105,10 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
 {
        struct xen_blkif *blkif;
 
-       blkif = kmem_cache_alloc(xen_blkif_cachep, GFP_KERNEL);
+       blkif = kmem_cache_zalloc(xen_blkif_cachep, GFP_KERNEL);
        if (!blkif)
                return ERR_PTR(-ENOMEM);
 
-       memset(blkif, 0, sizeof(*blkif));
        blkif->domid = domid;
        spin_lock_init(&blkif->blk_ring_lock);
        atomic_set(&blkif->refcnt, 1);
@@ -196,7 +195,7 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif)
        }
 }
 
-void xen_blkif_free(struct xen_blkif *blkif)
+static void xen_blkif_free(struct xen_blkif *blkif)
 {
        if (!atomic_dec_and_test(&blkif->refcnt))
                BUG();
@@ -257,7 +256,7 @@ static struct attribute_group xen_vbdstat_group = {
 VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor);
 VBD_SHOW(mode, "%s\n", be->mode);
 
-int xenvbd_sysfs_addif(struct xenbus_device *dev)
+static int xenvbd_sysfs_addif(struct xenbus_device *dev)
 {
        int error;
 
@@ -281,7 +280,7 @@ fail1:      device_remove_file(&dev->dev, &dev_attr_physical_device);
        return error;
 }
 
-void xenvbd_sysfs_delif(struct xenbus_device *dev)
+static void xenvbd_sysfs_delif(struct xenbus_device *dev)
 {
        sysfs_remove_group(&dev->dev.kobj, &xen_vbdstat_group);
        device_remove_file(&dev->dev, &dev_attr_mode);
index c16a3a5..e3ebb4f 100644 (file)
@@ -5,7 +5,7 @@
  *  http://www.gnu.org/licenses/gpl.html
  *
  *  Maintainer:
- *  Andreas Herrmann <andreas.herrmann3@amd.com>
+ *  Andreas Herrmann <herrmann.der.user@googlemail.com>
  *
  *  Based on the powernow-k7.c module written by Dave Jones.
  *  (C) 2003 Dave Jones on behalf of SuSE Labs
index d055cee..f11d8e3 100644 (file)
@@ -47,7 +47,7 @@ if GPIOLIB
 
 config OF_GPIO
        def_bool y
-       depends on OF && !SPARC
+       depends on OF
 
 config DEBUG_GPIO
        bool "Debug GPIO calls"
index ed3e551..f05e542 100644 (file)
@@ -153,7 +153,7 @@ static int __devinit gen_74x164_probe(struct spi_device *spi)
        }
 
        chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers;
-       chip->buffer = devm_kzalloc(&spi->dev, chip->gpio_chip.ngpio, GFP_KERNEL);
+       chip->buffer = devm_kzalloc(&spi->dev, chip->registers, GFP_KERNEL);
        if (!chip->buffer) {
                ret = -ENOMEM;
                goto exit_destroy;
index 7a87412..cf7afb9 100644 (file)
@@ -244,6 +244,8 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
        if (ret)
                return ret;
 
+       mvebu_gpio_set(chip, pin, value);
+
        spin_lock_irqsave(&mvchip->lock, flags);
        u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
        u &= ~(1 << pin);
@@ -644,7 +646,7 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
        ct->handler = handle_edge_irq;
        ct->chip.name = mvchip->chip.label;
 
-       irq_setup_generic_chip(gc, IRQ_MSK(ngpios), IRQ_GC_INIT_MASK_CACHE,
+       irq_setup_generic_chip(gc, IRQ_MSK(ngpios), 0,
                               IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
 
        /* Setup irq domain on top of the generic chip. */
index 94cbc84..d335af1 100644 (file)
@@ -251,6 +251,40 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
        }
 }
 
+/**
+ * _clear_gpio_debounce - clear debounce settings for a gpio
+ * @bank: the gpio bank we're acting upon
+ * @gpio: the gpio number on this @gpio
+ *
+ * If a gpio is using debounce, then clear the debounce enable bit and if
+ * this is the only gpio in this bank using debounce, then clear the debounce
+ * time too. The debounce clock will also be disabled when calling this function
+ * if this is the only gpio in the bank using debounce.
+ */
+static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio)
+{
+       u32 gpio_bit = GPIO_BIT(bank, gpio);
+
+       if (!bank->dbck_flag)
+               return;
+
+       if (!(bank->dbck_enable_mask & gpio_bit))
+               return;
+
+       bank->dbck_enable_mask &= ~gpio_bit;
+       bank->context.debounce_en &= ~gpio_bit;
+       __raw_writel(bank->context.debounce_en,
+                    bank->base + bank->regs->debounce_en);
+
+       if (!bank->dbck_enable_mask) {
+               bank->context.debounce = 0;
+               __raw_writel(bank->context.debounce, bank->base +
+                            bank->regs->debounce);
+               clk_disable(bank->dbck);
+               bank->dbck_enabled = false;
+       }
+}
+
 static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
                                                unsigned trigger)
 {
@@ -539,6 +573,7 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio)
        _set_gpio_irqenable(bank, gpio, 0);
        _clear_gpio_irqstatus(bank, gpio);
        _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
+       _clear_gpio_debounce(bank, gpio);
 }
 
 /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
index 031c6ad..1a3e2b9 100644 (file)
@@ -116,7 +116,7 @@ static void timbgpio_irq_disable(struct irq_data *d)
        unsigned long flags;
 
        spin_lock_irqsave(&tgpio->lock, flags);
-       tgpio->last_ier &= ~(1 << offset);
+       tgpio->last_ier &= ~(1UL << offset);
        iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
        spin_unlock_irqrestore(&tgpio->lock, flags);
 }
@@ -128,7 +128,7 @@ static void timbgpio_irq_enable(struct irq_data *d)
        unsigned long flags;
 
        spin_lock_irqsave(&tgpio->lock, flags);
-       tgpio->last_ier |= 1 << offset;
+       tgpio->last_ier |= 1UL << offset;
        iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
        spin_unlock_irqrestore(&tgpio->lock, flags);
 }
index f1a4599..a40cd84 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_gpio.h>
+#include <linux/pinctrl/pinctrl.h>
 #include <linux/slab.h>
 
 /* Private data structure for of_gpiochip_find_and_xlate */
@@ -216,6 +217,42 @@ err0:
 }
 EXPORT_SYMBOL(of_mm_gpiochip_add);
 
+#ifdef CONFIG_PINCTRL
+static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
+{
+       struct device_node *np = chip->of_node;
+       struct of_phandle_args pinspec;
+       struct pinctrl_dev *pctldev;
+       int index = 0, ret;
+
+       if (!np)
+               return;
+
+       do {
+               ret = of_parse_phandle_with_args(np, "gpio-ranges",
+                               "#gpio-range-cells", index, &pinspec);
+               if (ret)
+                       break;
+
+               pctldev = of_pinctrl_get(pinspec.np);
+               if (!pctldev)
+                       break;
+
+               ret = gpiochip_add_pin_range(chip,
+                                            pinctrl_dev_get_name(pctldev),
+                                            pinspec.args[0],
+                                            pinspec.args[1]);
+
+               if (ret)
+                       break;
+
+       } while (index++);
+}
+
+#else
+static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {}
+#endif
+
 void of_gpiochip_add(struct gpio_chip *chip)
 {
        if ((!chip->of_node) && (chip->dev))
@@ -229,11 +266,14 @@ void of_gpiochip_add(struct gpio_chip *chip)
                chip->of_xlate = of_gpio_simple_xlate;
        }
 
+       of_gpiochip_add_pin_range(chip);
        of_node_get(chip->of_node);
 }
 
 void of_gpiochip_remove(struct gpio_chip *chip)
 {
+       gpiochip_remove_pin_ranges(chip);
+
        if (chip->of_node)
                of_node_put(chip->of_node);
 }
index 5d6c71e..c5f6500 100644 (file)
@@ -623,9 +623,11 @@ static ssize_t export_store(struct class *class,
         */
 
        status = gpio_request(gpio, "sysfs");
-       if (status < 0)
+       if (status < 0) {
+               if (status == -EPROBE_DEFER)
+                       status = -ENODEV;
                goto done;
-
+       }
        status = gpio_export(gpio, true);
        if (status < 0)
                gpio_free(gpio);
@@ -1081,6 +1083,10 @@ int gpiochip_add(struct gpio_chip *chip)
                }
        }
 
+#ifdef CONFIG_PINCTRL
+       INIT_LIST_HEAD(&chip->pin_ranges);
+#endif
+
        of_gpiochip_add(chip);
 
 unlock:
@@ -1121,6 +1127,7 @@ int gpiochip_remove(struct gpio_chip *chip)
 
        spin_lock_irqsave(&gpio_lock, flags);
 
+       gpiochip_remove_pin_ranges(chip);
        of_gpiochip_remove(chip);
 
        for (id = chip->base; id < chip->base + chip->ngpio; id++) {
@@ -1178,6 +1185,47 @@ struct gpio_chip *gpiochip_find(void *data,
 }
 EXPORT_SYMBOL_GPL(gpiochip_find);
 
+#ifdef CONFIG_PINCTRL
+
+int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+                          unsigned int pin_base, unsigned int npins)
+{
+       struct gpio_pin_range *pin_range;
+
+       pin_range = devm_kzalloc(chip->dev, sizeof(*pin_range), GFP_KERNEL);
+       if (!pin_range) {
+               pr_err("%s: GPIO chip: failed to allocate pin ranges\n",
+                               chip->label);
+               return -ENOMEM;
+       }
+
+       pin_range->range.name = chip->label;
+       pin_range->range.base = chip->base;
+       pin_range->range.pin_base = pin_base;
+       pin_range->range.npins = npins;
+       pin_range->pctldev = find_pinctrl_and_add_gpio_range(pinctl_name,
+                       &pin_range->range);
+
+       list_add_tail(&pin_range->node, &chip->pin_ranges);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_add_pin_range);
+
+void gpiochip_remove_pin_ranges(struct gpio_chip *chip)
+{
+       struct gpio_pin_range *pin_range, *tmp;
+
+       list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) {
+               list_del(&pin_range->node);
+               pinctrl_remove_gpio_range(pin_range->pctldev,
+                               &pin_range->range);
+       }
+}
+EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
+
+#endif /* CONFIG_PINCTRL */
+
 /* These "optional" allocation calls help prevent drivers from stomping
  * on each other, and help provide better diagnostics in debugfs.
  * They're called even less than the "set direction" calls.
@@ -1191,8 +1239,10 @@ int gpio_request(unsigned gpio, const char *label)
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       if (!gpio_is_valid(gpio))
+       if (!gpio_is_valid(gpio)) {
+               status = -EINVAL;
                goto done;
+       }
        desc = &gpio_desc[gpio];
        chip = desc->chip;
        if (chip == NULL)
index 7ef1b67..133b413 100644 (file)
@@ -121,6 +121,8 @@ int drm_open(struct inode *inode, struct file *filp)
        int minor_id = iminor(inode);
        struct drm_minor *minor;
        int retcode = 0;
+       int need_setup = 0;
+       struct address_space *old_mapping;
 
        minor = idr_find(&drm_minors_idr, minor_id);
        if (!minor)
@@ -132,23 +134,37 @@ int drm_open(struct inode *inode, struct file *filp)
        if (drm_device_is_unplugged(dev))
                return -ENODEV;
 
+       if (!dev->open_count++)
+               need_setup = 1;
+       mutex_lock(&dev->struct_mutex);
+       old_mapping = dev->dev_mapping;
+       if (old_mapping == NULL)
+               dev->dev_mapping = &inode->i_data;
+       /* ihold ensures nobody can remove inode with our i_data */
+       ihold(container_of(dev->dev_mapping, struct inode, i_data));
+       inode->i_mapping = dev->dev_mapping;
+       filp->f_mapping = dev->dev_mapping;
+       mutex_unlock(&dev->struct_mutex);
+
        retcode = drm_open_helper(inode, filp, dev);
-       if (!retcode) {
-               atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
-               if (!dev->open_count++)
-                       retcode = drm_setup(dev);
-       }
-       if (!retcode) {
-               mutex_lock(&dev->struct_mutex);
-               if (dev->dev_mapping == NULL)
-                       dev->dev_mapping = &inode->i_data;
-               /* ihold ensures nobody can remove inode with our i_data */
-               ihold(container_of(dev->dev_mapping, struct inode, i_data));
-               inode->i_mapping = dev->dev_mapping;
-               filp->f_mapping = dev->dev_mapping;
-               mutex_unlock(&dev->struct_mutex);
+       if (retcode)
+               goto err_undo;
+       atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
+       if (need_setup) {
+               retcode = drm_setup(dev);
+               if (retcode)
+                       goto err_undo;
        }
+       return 0;
 
+err_undo:
+       mutex_lock(&dev->struct_mutex);
+       filp->f_mapping = old_mapping;
+       inode->i_mapping = old_mapping;
+       iput(container_of(dev->dev_mapping, struct inode, i_data));
+       dev->dev_mapping = old_mapping;
+       mutex_unlock(&dev->struct_mutex);
+       dev->open_count--;
        return retcode;
 }
 EXPORT_SYMBOL(drm_open);
index 59a26e5..fc345d4 100644 (file)
@@ -1,6 +1,6 @@
 config DRM_EXYNOS
        tristate "DRM Support for Samsung SoC EXYNOS Series"
-       depends on DRM && PLAT_SAMSUNG
+       depends on DRM && (PLAT_SAMSUNG || ARCH_MULTIPLATFORM)
        select DRM_KMS_HELPER
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
index 18c2718..0f68a28 100644 (file)
@@ -374,6 +374,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
        exynos_connector->encoder_id = encoder->base.id;
        exynos_connector->manager = manager;
        exynos_connector->dpms = DRM_MODE_DPMS_OFF;
+       connector->dpms = DRM_MODE_DPMS_OFF;
        connector->encoder = encoder;
 
        err = drm_mode_connector_attach_encoder(connector, encoder);
index e51503f..241ad1e 100644 (file)
  * @manager: specific encoder has its own manager to control a hardware
  *     appropriately and we can access a hardware drawing on this manager.
  * @dpms: store the encoder dpms value.
+ * @updated: indicate whether overlay data updating is needed or not.
  */
 struct exynos_drm_encoder {
        struct drm_crtc                 *old_crtc;
        struct drm_encoder              drm_encoder;
        struct exynos_drm_manager       *manager;
-       int dpms;
+       int                             dpms;
+       bool                            updated;
 };
 
 static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode)
@@ -85,7 +87,9 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
        switch (mode) {
        case DRM_MODE_DPMS_ON:
                if (manager_ops && manager_ops->apply)
-                       manager_ops->apply(manager->dev);
+                       if (!exynos_encoder->updated)
+                               manager_ops->apply(manager->dev);
+
                exynos_drm_connector_power(encoder, mode);
                exynos_encoder->dpms = mode;
                break;
@@ -94,6 +98,7 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
        case DRM_MODE_DPMS_OFF:
                exynos_drm_connector_power(encoder, mode);
                exynos_encoder->dpms = mode;
+               exynos_encoder->updated = false;
                break;
        default:
                DRM_ERROR("unspecified mode %d\n", mode);
@@ -205,13 +210,22 @@ static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
 
 static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
 {
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
+       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+       struct exynos_drm_manager *manager = exynos_encoder->manager;
        struct exynos_drm_manager_ops *manager_ops = manager->ops;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        if (manager_ops && manager_ops->commit)
                manager_ops->commit(manager->dev);
+
+       /*
+        * this will avoid one issue that overlay data is updated to
+        * real hardware two times.
+        * And this variable will be used to check if the data was
+        * already updated or not by exynos_drm_encoder_dpms function.
+        */
+       exynos_encoder->updated = true;
 }
 
 static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
@@ -401,19 +415,6 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
                manager_ops->dpms(manager->dev, mode);
 
        /*
-        * set current mode to new one so that data aren't updated into
-        * registers by drm_helper_connector_dpms two times.
-        *
-        * in case that drm_crtc_helper_set_mode() is called,
-        * overlay_ops->commit() and manager_ops->commit() callbacks
-        * can be called two times, first at drm_crtc_helper_set_mode()
-        * and second at drm_helper_connector_dpms().
-        * so with this setting, when drm_helper_connector_dpms() is called
-        * encoder->funcs->dpms() will be ignored.
-        */
-       exynos_encoder->dpms = mode;
-
-       /*
         * if this condition is ok then it means that the crtc is already
         * detached from encoder and last function for detaching is properly
         * done, so clear pipe from manager to prevent repeated call.
index 614b2e9..e7fbb82 100644 (file)
@@ -1142,7 +1142,7 @@ static int __devinit mixer_probe(struct platform_device *pdev)
                const struct of_device_id *match;
                match = of_match_node(of_match_ptr(mixer_match_types),
                                                          pdev->dev.of_node);
-               drv = match->data;
+               drv = (struct mixer_drv_data *)match->data;
        } else {
                drv = (struct mixer_drv_data *)
                        platform_get_device_id(pdev)->driver_data;
index c9bfd83..61ae104 100644 (file)
@@ -1505,7 +1505,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                goto put_gmch;
        }
 
-       i915_kick_out_firmware_fb(dev_priv);
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               i915_kick_out_firmware_fb(dev_priv);
 
        pci_set_master(dev->pdev);
 
index f78061a..b726b47 100644 (file)
@@ -729,7 +729,7 @@ void intel_crt_init(struct drm_device *dev)
 
        crt->base.type = INTEL_OUTPUT_ANALOG;
        crt->base.cloneable = true;
-       if (IS_HASWELL(dev))
+       if (IS_HASWELL(dev) || IS_I830(dev))
                crt->base.crtc_mask = (1 << 0);
        else
                crt->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
index 4956259..d7bc817 100644 (file)
@@ -341,9 +341,17 @@ static int intel_overlay_off(struct intel_overlay *overlay)
        intel_ring_emit(ring, flip_addr);
        intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
        /* turn overlay off */
-       intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
-       intel_ring_emit(ring, flip_addr);
-       intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+       if (IS_I830(dev)) {
+               /* Workaround: Don't disable the overlay fully, since otherwise
+                * it dies on the next OVERLAY_ON cmd. */
+               intel_ring_emit(ring, MI_NOOP);
+               intel_ring_emit(ring, MI_NOOP);
+               intel_ring_emit(ring, MI_NOOP);
+       } else {
+               intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
+               intel_ring_emit(ring, flip_addr);
+               intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+       }
        intel_ring_advance(ring);
 
        return intel_overlay_do_wait_request(overlay, intel_overlay_off_tail);
index e019b23..e2aacd3 100644 (file)
@@ -435,7 +435,7 @@ int intel_panel_setup_backlight(struct drm_device *dev)
        props.type = BACKLIGHT_RAW;
        props.max_brightness = _intel_panel_get_max_backlight(dev);
        if (props.max_brightness == 0) {
-               DRM_ERROR("Failed to get maximum backlight value\n");
+               DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n");
                return -ENODEV;
        }
        dev_priv->backlight =
index c01d97d..79d308d 100644 (file)
@@ -894,6 +894,45 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo)
 }
 #endif
 
+static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
+                                      unsigned if_index, uint8_t tx_rate,
+                                      uint8_t *data, unsigned length)
+{
+       uint8_t set_buf_index[2] = { if_index, 0 };
+       uint8_t hbuf_size, tmp[8];
+       int i;
+
+       if (!intel_sdvo_set_value(intel_sdvo,
+                                 SDVO_CMD_SET_HBUF_INDEX,
+                                 set_buf_index, 2))
+               return false;
+
+       if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO,
+                                 &hbuf_size, 1))
+               return false;
+
+       /* Buffer size is 0 based, hooray! */
+       hbuf_size++;
+
+       DRM_DEBUG_KMS("writing sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n",
+                     if_index, length, hbuf_size);
+
+       for (i = 0; i < hbuf_size; i += 8) {
+               memset(tmp, 0, 8);
+               if (i < length)
+                       memcpy(tmp, data + i, min_t(unsigned, 8, length - i));
+
+               if (!intel_sdvo_set_value(intel_sdvo,
+                                         SDVO_CMD_SET_HBUF_DATA,
+                                         tmp, 8))
+                       return false;
+       }
+
+       return intel_sdvo_set_value(intel_sdvo,
+                                   SDVO_CMD_SET_HBUF_TXRATE,
+                                   &tx_rate, 1);
+}
+
 static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
 {
        struct dip_infoframe avi_if = {
@@ -901,11 +940,7 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
                .ver = DIP_VERSION_AVI,
                .len = DIP_LEN_AVI,
        };
-       uint8_t tx_rate = SDVO_HBUF_TX_VSYNC;
-       uint8_t set_buf_index[2] = { 1, 0 };
        uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)];
-       uint64_t *data = (uint64_t *)sdvo_data;
-       unsigned i;
 
        intel_dip_infoframe_csum(&avi_if);
 
@@ -915,22 +950,9 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
        sdvo_data[3] = avi_if.checksum;
        memcpy(&sdvo_data[4], &avi_if.body, sizeof(avi_if.body.avi));
 
-       if (!intel_sdvo_set_value(intel_sdvo,
-                                 SDVO_CMD_SET_HBUF_INDEX,
-                                 set_buf_index, 2))
-               return false;
-
-       for (i = 0; i < sizeof(sdvo_data); i += 8) {
-               if (!intel_sdvo_set_value(intel_sdvo,
-                                         SDVO_CMD_SET_HBUF_DATA,
-                                         data, 8))
-                       return false;
-               data++;
-       }
-
-       return intel_sdvo_set_value(intel_sdvo,
-                                   SDVO_CMD_SET_HBUF_TXRATE,
-                                   &tx_rate, 1);
+       return intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
+                                         SDVO_HBUF_TX_VSYNC,
+                                         sdvo_data, sizeof(sdvo_data));
 }
 
 static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo)
index 9d03014..770bdd6 100644 (file)
@@ -708,6 +708,8 @@ struct intel_sdvo_enhancements_arg {
 #define SDVO_CMD_SET_AUDIO_STAT                0x91
 #define SDVO_CMD_GET_AUDIO_STAT                0x92
 #define SDVO_CMD_SET_HBUF_INDEX                0x93
+  #define SDVO_HBUF_INDEX_ELD          0
+  #define SDVO_HBUF_INDEX_AVI_IF       1
 #define SDVO_CMD_GET_HBUF_INDEX                0x94
 #define SDVO_CMD_GET_HBUF_INFO         0x95
 #define SDVO_CMD_SET_HBUF_AV_SPLIT     0x96
index 4d62064..a6d3cd6 100644 (file)
@@ -218,13 +218,16 @@ nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
        node = kzalloc(sizeof(*node), GFP_KERNEL);
        if (!node)
                return -ENOMEM;
-       node->offset = roundup(offset, mm->block_size);
-       node->length = rounddown(offset + length, mm->block_size) - node->offset;
+
+       if (length) {
+               node->offset  = roundup(offset, mm->block_size);
+               node->length  = rounddown(offset + length, mm->block_size);
+               node->length -= node->offset;
+       }
 
        list_add_tail(&node->nl_entry, &mm->nodes);
        list_add_tail(&node->fl_entry, &mm->free);
        mm->heap_nodes++;
-       mm->heap_size += length;
        return 0;
 }
 
index 16a9afb..05a909a 100644 (file)
@@ -22,6 +22,8 @@
  * Authors: Ben Skeggs
  */
 
+#include <subdev/bar.h>
+
 #include <engine/software.h>
 #include <engine/disp.h>
 
@@ -37,6 +39,7 @@ nv50_disp_sclass[] = {
 static void
 nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
 {
+       struct nouveau_bar *bar = nouveau_bar(priv);
        struct nouveau_disp *disp = &priv->base;
        struct nouveau_software_chan *chan, *temp;
        unsigned long flags;
@@ -46,18 +49,19 @@ nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
                if (chan->vblank.crtc != crtc)
                        continue;
 
-               nv_wr32(priv, 0x001704, chan->vblank.channel);
-               nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
-
                if (nv_device(priv)->chipset == 0x50) {
+                       nv_wr32(priv, 0x001704, chan->vblank.channel);
+                       nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
+                       bar->flush(bar);
                        nv_wr32(priv, 0x001570, chan->vblank.offset);
                        nv_wr32(priv, 0x001574, chan->vblank.value);
                } else {
-                       if (nv_device(priv)->chipset >= 0xc0) {
-                               nv_wr32(priv, 0x06000c,
-                                       upper_32_bits(chan->vblank.offset));
-                       }
-                       nv_wr32(priv, 0x060010, chan->vblank.offset);
+                       nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
+                       bar->flush(bar);
+                       nv_wr32(priv, 0x06000c,
+                               upper_32_bits(chan->vblank.offset));
+                       nv_wr32(priv, 0x060010,
+                               lower_32_bits(chan->vblank.offset));
                        nv_wr32(priv, 0x060014, chan->vblank.value);
                }
 
index 8d00210..4250012 100644 (file)
@@ -156,8 +156,8 @@ nv40_graph_context_ctor(struct nouveau_object *parent,
 static int
 nv40_graph_context_fini(struct nouveau_object *object, bool suspend)
 {
-       struct nv04_graph_priv *priv = (void *)object->engine;
-       struct nv04_graph_chan *chan = (void *)object;
+       struct nv40_graph_priv *priv = (void *)object->engine;
+       struct nv40_graph_chan *chan = (void *)object;
        u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4;
        int ret = 0;
 
index 1241857..f7c581a 100644 (file)
@@ -38,7 +38,7 @@ struct nv40_mpeg_priv {
 };
 
 struct nv40_mpeg_chan {
-       struct nouveau_mpeg base;
+       struct nouveau_mpeg_chan base;
 };
 
 /*******************************************************************************
index 9ee9bf4..975137b 100644 (file)
@@ -19,7 +19,6 @@ struct nouveau_mm {
 
        u32 block_size;
        int heap_nodes;
-       u32 heap_size;
 };
 
 int  nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block);
index 27fb1af..5f57080 100644 (file)
@@ -219,13 +219,11 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                             ((priv->base.ram.size & 0x000000ff) << 32);
 
        tags = nv_rd32(priv, 0x100320);
-       if (tags) {
-               ret = nouveau_mm_init(&priv->base.tags, 0, tags, 1);
-               if (ret)
-                       return ret;
+       ret = nouveau_mm_init(&priv->base.tags, 0, tags, 1);
+       if (ret)
+               return ret;
 
-               nv_debug(priv, "%d compression tags\n", tags);
-       }
+       nv_debug(priv, "%d compression tags\n", tags);
 
        size = (priv->base.ram.size >> 12) - rsvd_head - rsvd_tail;
        switch (device->chipset) {
index 3d2c883..dbfc2ab 100644 (file)
@@ -292,7 +292,7 @@ nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                case DCB_I2C_NVIO_BIT:
                        port->drive = info.drive & 0x0f;
                        if (device->card_type < NV_D0) {
-                               if (info.drive >= ARRAY_SIZE(nv50_i2c_port))
+                               if (port->drive >= ARRAY_SIZE(nv50_i2c_port))
                                        break;
                                port->drive = nv50_i2c_port[port->drive];
                                port->sense = port->drive;
index 49050d9..9474cfc 100644 (file)
@@ -67,7 +67,7 @@ nv41_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
 static void
 nv41_vm_flush(struct nouveau_vm *vm)
 {
-       struct nv04_vm_priv *priv = (void *)vm->vmm;
+       struct nv04_vmmgr_priv *priv = (void *)vm->vmm;
 
        mutex_lock(&nv_subdev(priv)->mutex);
        nv_wr32(priv, 0x100810, 0x00000022);
index 9a6e2cb..d3595b2 100644 (file)
@@ -355,7 +355,7 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)
         * valid - it's not (rh#613284)
         */
        if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
-               if (!(nv_connector->edid = nouveau_acpi_edid(dev, connector))) {
+               if ((nv_connector->edid = nouveau_acpi_edid(dev, connector))) {
                        status = connector_status_connected;
                        goto out;
                }
index d2f8ffe..86124b1 100644 (file)
@@ -290,6 +290,7 @@ nouveau_display_create(struct drm_device *dev)
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_disp *pdisp = nouveau_disp(drm->device);
        struct nouveau_display *disp;
+       u32 pclass = dev->pdev->class >> 8;
        int ret, gen;
 
        disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL);
@@ -360,23 +361,27 @@ nouveau_display_create(struct drm_device *dev)
        drm_kms_helper_poll_init(dev);
        drm_kms_helper_poll_disable(dev);
 
-       if (nv_device(drm->device)->card_type < NV_50)
-               ret = nv04_display_create(dev);
-       else
-       if (nv_device(drm->device)->card_type < NV_D0)
-               ret = nv50_display_create(dev);
-       else
-               ret = nvd0_display_create(dev);
-       if (ret)
-               goto disp_create_err;
-
-       if (dev->mode_config.num_crtc) {
-               ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+       if (nouveau_modeset == 1 ||
+           (nouveau_modeset < 0 && pclass == PCI_CLASS_DISPLAY_VGA)) {
+               if (nv_device(drm->device)->card_type < NV_50)
+                       ret = nv04_display_create(dev);
+               else
+               if (nv_device(drm->device)->card_type < NV_D0)
+                       ret = nv50_display_create(dev);
+               else
+                       ret = nvd0_display_create(dev);
                if (ret)
-                       goto vblank_err;
+                       goto disp_create_err;
+
+               if (dev->mode_config.num_crtc) {
+                       ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+                       if (ret)
+                               goto vblank_err;
+               }
+
+               nouveau_backlight_init(dev);
        }
 
-       nouveau_backlight_init(dev);
        return 0;
 
 vblank_err:
@@ -395,7 +400,8 @@ nouveau_display_destroy(struct drm_device *dev)
        nouveau_backlight_exit(dev);
        drm_vblank_cleanup(dev);
 
-       disp->dtor(dev);
+       if (disp->dtor)
+               disp->dtor(dev);
 
        drm_kms_helper_poll_fini(dev);
        drm_mode_config_cleanup(dev);
index ccae8c2..0910125 100644 (file)
@@ -63,8 +63,9 @@ MODULE_PARM_DESC(noaccel, "disable kernel/abi16 acceleration");
 static int nouveau_noaccel = 0;
 module_param_named(noaccel, nouveau_noaccel, int, 0400);
 
-MODULE_PARM_DESC(modeset, "enable driver");
-static int nouveau_modeset = -1;
+MODULE_PARM_DESC(modeset, "enable driver (default: auto, "
+                         "0 = disabled, 1 = enabled, 2 = headless)");
+int nouveau_modeset = -1;
 module_param_named(modeset, nouveau_modeset, int, 0400);
 
 static struct drm_driver driver;
@@ -363,7 +364,8 @@ nouveau_drm_unload(struct drm_device *dev)
 
        nouveau_pm_fini(dev);
 
-       nouveau_display_fini(dev);
+       if (dev->mode_config.num_crtc)
+               nouveau_display_fini(dev);
        nouveau_display_destroy(dev);
 
        nouveau_irq_fini(dev);
@@ -403,13 +405,15 @@ nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state)
            pm_state.event == PM_EVENT_PRETHAW)
                return 0;
 
-       NV_INFO(drm, "suspending fbcon...\n");
-       nouveau_fbcon_set_suspend(dev, 1);
+       if (dev->mode_config.num_crtc) {
+               NV_INFO(drm, "suspending fbcon...\n");
+               nouveau_fbcon_set_suspend(dev, 1);
 
-       NV_INFO(drm, "suspending display...\n");
-       ret = nouveau_display_suspend(dev);
-       if (ret)
-               return ret;
+               NV_INFO(drm, "suspending display...\n");
+               ret = nouveau_display_suspend(dev);
+               if (ret)
+                       return ret;
+       }
 
        NV_INFO(drm, "evicting buffers...\n");
        ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM);
@@ -445,8 +449,10 @@ fail_client:
                nouveau_client_init(&cli->base);
        }
 
-       NV_INFO(drm, "resuming display...\n");
-       nouveau_display_resume(dev);
+       if (dev->mode_config.num_crtc) {
+               NV_INFO(drm, "resuming display...\n");
+               nouveau_display_resume(dev);
+       }
        return ret;
 }
 
@@ -486,8 +492,10 @@ nouveau_drm_resume(struct pci_dev *pdev)
        nouveau_irq_postinstall(dev);
        nouveau_pm_resume(dev);
 
-       NV_INFO(drm, "resuming display...\n");
-       nouveau_display_resume(dev);
+       if (dev->mode_config.num_crtc) {
+               NV_INFO(drm, "resuming display...\n");
+               nouveau_display_resume(dev);
+       }
        return 0;
 }
 
@@ -662,9 +670,7 @@ nouveau_drm_init(void)
 #ifdef CONFIG_VGA_CONSOLE
                if (vgacon_text_force())
                        nouveau_modeset = 0;
-               else
 #endif
-                       nouveau_modeset = 1;
        }
 
        if (!nouveau_modeset)
index 8194712..a101699 100644 (file)
@@ -141,4 +141,6 @@ int nouveau_drm_resume(struct pci_dev *);
                nv_info((cli), fmt, ##args);                                   \
 } while (0)
 
+extern int nouveau_modeset;
+
 #endif
index 9ca8afd..1d8cb50 100644 (file)
@@ -61,13 +61,15 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
 
        nv_subdev(pmc)->intr(nv_subdev(pmc));
 
-       if (device->card_type >= NV_D0) {
-               if (nv_rd32(device, 0x000100) & 0x04000000)
-                       nvd0_display_intr(dev);
-       } else
-       if (device->card_type >= NV_50) {
-               if (nv_rd32(device, 0x000100) & 0x04000000)
-                       nv50_display_intr(dev);
+       if (dev->mode_config.num_crtc) {
+               if (device->card_type >= NV_D0) {
+                       if (nv_rd32(device, 0x000100) & 0x04000000)
+                               nvd0_display_intr(dev);
+               } else
+               if (device->card_type >= NV_50) {
+                       if (nv_rd32(device, 0x000100) & 0x04000000)
+                               nv50_display_intr(dev);
+               }
        }
 
        return IRQ_HANDLED;
index 347a3bd..64f7020 100644 (file)
@@ -220,7 +220,7 @@ out:
        NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode);
 
        if (blue == 0x18) {
-               NV_INFO(drm, "Load detected on head A\n");
+               NV_DEBUG(drm, "Load detected on head A\n");
                return connector_status_connected;
        }
 
@@ -338,8 +338,8 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
 
        if (nv17_dac_sample_load(encoder) &
            NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
-               NV_INFO(drm, "Load detected on output %c\n",
-                       '@' + ffs(dcb->or));
+               NV_DEBUG(drm, "Load detected on output %c\n",
+                        '@' + ffs(dcb->or));
                return connector_status_connected;
        } else {
                return connector_status_disconnected;
@@ -413,9 +413,9 @@ static void nv04_dac_commit(struct drm_encoder *encoder)
 
        helper->dpms(encoder, DRM_MODE_DPMS_ON);
 
-       NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n",
-               drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
-               nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
+       NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n",
+                drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
+                nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
 }
 
 void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable)
@@ -461,8 +461,8 @@ static void nv04_dac_dpms(struct drm_encoder *encoder, int mode)
                return;
        nv_encoder->last_dpms = mode;
 
-       NV_INFO(drm, "Setting dpms mode %d on vga encoder (output %d)\n",
-                    mode, nv_encoder->dcb->index);
+       NV_DEBUG(drm, "Setting dpms mode %d on vga encoder (output %d)\n",
+                mode, nv_encoder->dcb->index);
 
        nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);
 }
index da55d76..184cdf8 100644 (file)
@@ -476,9 +476,9 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
 
        helper->dpms(encoder, DRM_MODE_DPMS_ON);
 
-       NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n",
-               drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
-               nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
+       NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n",
+                drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
+                nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
 }
 
 static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode)
@@ -520,8 +520,8 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)
                return;
        nv_encoder->last_dpms = mode;
 
-       NV_INFO(drm, "Setting dpms mode %d on lvds encoder (output %d)\n",
-                    mode, nv_encoder->dcb->index);
+       NV_DEBUG(drm, "Setting dpms mode %d on lvds encoder (output %d)\n",
+                mode, nv_encoder->dcb->index);
 
        if (was_powersaving && is_powersaving_dpms(mode))
                return;
@@ -565,8 +565,8 @@ static void nv04_tmds_dpms(struct drm_encoder *encoder, int mode)
                return;
        nv_encoder->last_dpms = mode;
 
-       NV_INFO(drm, "Setting dpms mode %d on tmds encoder (output %d)\n",
-                    mode, nv_encoder->dcb->index);
+       NV_DEBUG(drm, "Setting dpms mode %d on tmds encoder (output %d)\n",
+                mode, nv_encoder->dcb->index);
 
        nv04_dfp_update_backlight(encoder, mode);
        nv04_dfp_update_fp_control(encoder, mode);
index 099fbed..62e826a 100644 (file)
@@ -75,8 +75,8 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode)
        struct nv04_mode_state *state = &nv04_display(dev)->mode_reg;
        uint8_t crtc1A;
 
-       NV_INFO(drm, "Setting dpms mode %d on TV encoder (output %d)\n",
-               mode, nv_encoder->dcb->index);
+       NV_DEBUG(drm, "Setting dpms mode %d on TV encoder (output %d)\n",
+                mode, nv_encoder->dcb->index);
 
        state->pllsel &= ~(PLLSEL_TV_CRTC1_MASK | PLLSEL_TV_CRTC2_MASK);
 
@@ -167,9 +167,8 @@ static void nv04_tv_commit(struct drm_encoder *encoder)
 
        helper->dpms(encoder, DRM_MODE_DPMS_ON);
 
-       NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n",
-                     drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index,
-                     '@' + ffs(nv_encoder->dcb->or));
+       NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n",
+                drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
 }
 
 static void nv04_tv_destroy(struct drm_encoder *encoder)
index 2e566e1..3bce029 100644 (file)
@@ -1696,35 +1696,43 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                        return ATOM_PPLL2;
                DRM_ERROR("unable to allocate a PPLL\n");
                return ATOM_PPLL_INVALID;
-       } else {
-               if (ASIC_IS_AVIVO(rdev)) {
-                       /* in DP mode, the DP ref clock can come from either PPLL
-                        * depending on the asic:
-                        * DCE3: PPLL1 or PPLL2
-                        */
-                       if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
-                               /* use the same PPLL for all DP monitors */
-                               pll = radeon_get_shared_dp_ppll(crtc);
-                               if (pll != ATOM_PPLL_INVALID)
-                                       return pll;
-                       } else {
-                               /* use the same PPLL for all monitors with the same clock */
-                               pll = radeon_get_shared_nondp_ppll(crtc);
-                               if (pll != ATOM_PPLL_INVALID)
-                                       return pll;
-                       }
-                       /* all other cases */
-                       pll_in_use = radeon_get_pll_use_mask(crtc);
+       } else if (ASIC_IS_AVIVO(rdev)) {
+               /* in DP mode, the DP ref clock can come from either PPLL
+                * depending on the asic:
+                * DCE3: PPLL1 or PPLL2
+                */
+               if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
+                       /* use the same PPLL for all DP monitors */
+                       pll = radeon_get_shared_dp_ppll(crtc);
+                       if (pll != ATOM_PPLL_INVALID)
+                               return pll;
+               } else {
+                       /* use the same PPLL for all monitors with the same clock */
+                       pll = radeon_get_shared_nondp_ppll(crtc);
+                       if (pll != ATOM_PPLL_INVALID)
+                               return pll;
+               }
+               /* all other cases */
+               pll_in_use = radeon_get_pll_use_mask(crtc);
+               /* the order shouldn't matter here, but we probably
+                * need this until we have atomic modeset
+                */
+               if (rdev->flags & RADEON_IS_IGP) {
                        if (!(pll_in_use & (1 << ATOM_PPLL1)))
                                return ATOM_PPLL1;
                        if (!(pll_in_use & (1 << ATOM_PPLL2)))
                                return ATOM_PPLL2;
-                       DRM_ERROR("unable to allocate a PPLL\n");
-                       return ATOM_PPLL_INVALID;
                } else {
-                       /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */
-                       return radeon_crtc->crtc_id;
+                       if (!(pll_in_use & (1 << ATOM_PPLL2)))
+                               return ATOM_PPLL2;
+                       if (!(pll_in_use & (1 << ATOM_PPLL1)))
+                               return ATOM_PPLL1;
                }
+               DRM_ERROR("unable to allocate a PPLL\n");
+               return ATOM_PPLL_INVALID;
+       } else {
+               /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */
+               return radeon_crtc->crtc_id;
        }
 }
 
index 14313ad..af31f82 100644 (file)
@@ -1372,7 +1372,7 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
        WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
 
        for (i = 0; i < rdev->num_crtc; i++) {
-               if (save->crtc_enabled) {
+               if (save->crtc_enabled[i]) {
                        if (ASIC_IS_DCE6(rdev)) {
                                tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]);
                                tmp |= EVERGREEN_CRTC_BLANK_DATA_EN;
index 30271b6..c042e49 100644 (file)
@@ -264,7 +264,7 @@ static int evergreen_surface_check_2d(struct radeon_cs_parser *p,
        /* macro tile width & height */
        palign = (8 * surf->bankw * track->npipes) * surf->mtilea;
        halign = (8 * surf->bankh * surf->nbanks) / surf->mtilea;
-       mtileb = (palign / 8) * (halign / 8) * tileb;;
+       mtileb = (palign / 8) * (halign / 8) * tileb;
        mtile_pr = surf->nbx / palign;
        mtile_ps = (mtile_pr * surf->nby) / halign;
        surf->layer_size = mtile_ps * mtileb * slice_pt;
@@ -2725,6 +2725,9 @@ static bool evergreen_vm_reg_valid(u32 reg)
        /* check config regs */
        switch (reg) {
        case GRBM_GFX_INDEX:
+       case CP_STRMOUT_CNTL:
+       case CP_COHER_CNTL:
+       case CP_COHER_SIZE:
        case VGT_VTX_VECT_EJECT_REG:
        case VGT_CACHE_INVALIDATION:
        case VGT_GS_VERTEX_REUSE:
index df542f1..2bc0f6a 100644 (file)
 #define                FB_READ_EN                                      (1 << 0)
 #define                FB_WRITE_EN                                     (1 << 1)
 
+#define        CP_STRMOUT_CNTL                                 0x84FC
+
+#define        CP_COHER_CNTL                                   0x85F0
+#define        CP_COHER_SIZE                                   0x85F4
 #define        CP_COHER_BASE                                   0x85F8
 #define        CP_STALLED_STAT1                        0x8674
 #define        CP_STALLED_STAT2                        0x8678
index 37f6a90..15f5ded 100644 (file)
@@ -352,9 +352,9 @@ static int radeon_atpx_switchto(enum vga_switcheroo_client_id id)
 }
 
 /**
- * radeon_atpx_switchto - switch to the requested GPU
+ * radeon_atpx_power_state - power down/up the requested GPU
  *
- * @id: GPU to switch to
+ * @id: GPU to power down/up
  * @state: requested power state (0 = off, 1 = on)
  *
  * Execute the necessary ATPX function to power down/up the discrete GPU
index 67cfc17..b884c36 100644 (file)
@@ -941,7 +941,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
        struct drm_mode_object *obj;
        int i;
        enum drm_connector_status ret = connector_status_disconnected;
-       bool dret = false;
+       bool dret = false, broken_edid = false;
 
        if (!force && radeon_check_hpd_status_unchanged(connector))
                return connector->status;
@@ -965,6 +965,9 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
                                ret = connector_status_disconnected;
                                DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n", drm_get_connector_name(connector));
                                radeon_connector->ddc_bus = NULL;
+                       } else {
+                               ret = connector_status_connected;
+                               broken_edid = true; /* defer use_digital to later */
                        }
                } else {
                        radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
@@ -1047,13 +1050,24 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
 
                        encoder_funcs = encoder->helper_private;
                        if (encoder_funcs->detect) {
-                               if (ret != connector_status_connected) {
-                                       ret = encoder_funcs->detect(encoder, connector);
-                                       if (ret == connector_status_connected) {
-                                               radeon_connector->use_digital = false;
+                               if (!broken_edid) {
+                                       if (ret != connector_status_connected) {
+                                               /* deal with analog monitors without DDC */
+                                               ret = encoder_funcs->detect(encoder, connector);
+                                               if (ret == connector_status_connected) {
+                                                       radeon_connector->use_digital = false;
+                                               }
+                                               if (ret != connector_status_disconnected)
+                                                       radeon_connector->detected_by_load = true;
                                        }
-                                       if (ret != connector_status_disconnected)
-                                               radeon_connector->detected_by_load = true;
+                               } else {
+                                       enum drm_connector_status lret;
+                                       /* assume digital unless load detected otherwise */
+                                       radeon_connector->use_digital = true;
+                                       lret = encoder_funcs->detect(encoder, connector);
+                                       DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret);
+                                       if (lret == connector_status_connected)
+                                               radeon_connector->use_digital = false;
                                }
                                break;
                        }
index 5677a42..6857cb4 100644 (file)
@@ -295,6 +295,7 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct radeon_device *rdev = dev->dev_private;
+       uint32_t crtc_ext_cntl = 0;
        uint32_t mask;
 
        if (radeon_crtc->crtc_id)
@@ -307,6 +308,16 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
                        RADEON_CRTC_VSYNC_DIS |
                        RADEON_CRTC_HSYNC_DIS);
 
+       /*
+        * On all dual CRTC GPUs this bit controls the CRTC of the primary DAC.
+        * Therefore it is set in the DAC DMPS function.
+        * This is different for GPU's with a single CRTC but a primary and a
+        * TV DAC: here it controls the single CRTC no matter where it is
+        * routed. Therefore we set it here.
+        */
+       if (rdev->flags & RADEON_SINGLE_CRTC)
+               crtc_ext_cntl = RADEON_CRTC_CRT_ON;
+       
        switch (mode) {
        case DRM_MODE_DPMS_ON:
                radeon_crtc->enabled = true;
@@ -317,7 +328,7 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
                else {
                        WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN |
                                                                         RADEON_CRTC_DISP_REQ_EN_B));
-                       WREG32_P(RADEON_CRTC_EXT_CNTL, 0, ~mask);
+                       WREG32_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, ~(mask | crtc_ext_cntl));
                }
                drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
                radeon_crtc_load_lut(crtc);
@@ -331,7 +342,7 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
                else {
                        WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN |
                                                                                    RADEON_CRTC_DISP_REQ_EN_B));
-                       WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask);
+                       WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~(mask | crtc_ext_cntl));
                }
                radeon_crtc->enabled = false;
                /* adjust pm to dpms changes AFTER disabling crtcs */
index 0063df9..f5ba224 100644 (file)
@@ -537,7 +537,9 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode
                break;
        }
 
-       WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
+       /* handled in radeon_crtc_dpms() */
+       if (!(rdev->flags & RADEON_SINGLE_CRTC))
+               WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
        WREG32(RADEON_DAC_CNTL, dac_cntl);
        WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl);
 
@@ -662,6 +664,8 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc
 
        if (ASIC_IS_R300(rdev))
                tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT);
+       else if (ASIC_IS_RV100(rdev))
+               tmp |= (0x1ac << RADEON_DAC_FORCE_DATA_SHIFT);
        else
                tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT);
 
@@ -671,6 +675,7 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc
        tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN;
        WREG32(RADEON_DAC_CNTL, tmp);
 
+       tmp = dac_macro_cntl;
        tmp &= ~(RADEON_DAC_PDWN_R |
                 RADEON_DAC_PDWN_G |
                 RADEON_DAC_PDWN_B);
@@ -1092,7 +1097,8 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
        } else {
                if (is_tv)
                        WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl);
-               else
+               /* handled in radeon_crtc_dpms() */
+               else if (!(rdev->flags & RADEON_SINGLE_CRTC))
                        WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
                WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
        }
@@ -1416,13 +1422,104 @@ static bool radeon_legacy_tv_detect(struct drm_encoder *encoder,
        return found;
 }
 
+static bool radeon_legacy_ext_dac_detect(struct drm_encoder *encoder,
+                                        struct drm_connector *connector)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t gpio_monid, fp2_gen_cntl, disp_output_cntl, crtc2_gen_cntl;
+       uint32_t disp_lin_trans_grph_a, disp_lin_trans_grph_b, disp_lin_trans_grph_c;
+       uint32_t disp_lin_trans_grph_d, disp_lin_trans_grph_e, disp_lin_trans_grph_f;
+       uint32_t tmp, crtc2_h_total_disp, crtc2_v_total_disp;
+       uint32_t crtc2_h_sync_strt_wid, crtc2_v_sync_strt_wid;
+       bool found = false;
+       int i;
+
+       /* save the regs we need */
+       gpio_monid = RREG32(RADEON_GPIO_MONID);
+       fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
+       disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL);
+       crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
+       disp_lin_trans_grph_a = RREG32(RADEON_DISP_LIN_TRANS_GRPH_A);
+       disp_lin_trans_grph_b = RREG32(RADEON_DISP_LIN_TRANS_GRPH_B);
+       disp_lin_trans_grph_c = RREG32(RADEON_DISP_LIN_TRANS_GRPH_C);
+       disp_lin_trans_grph_d = RREG32(RADEON_DISP_LIN_TRANS_GRPH_D);
+       disp_lin_trans_grph_e = RREG32(RADEON_DISP_LIN_TRANS_GRPH_E);
+       disp_lin_trans_grph_f = RREG32(RADEON_DISP_LIN_TRANS_GRPH_F);
+       crtc2_h_total_disp = RREG32(RADEON_CRTC2_H_TOTAL_DISP);
+       crtc2_v_total_disp = RREG32(RADEON_CRTC2_V_TOTAL_DISP);
+       crtc2_h_sync_strt_wid = RREG32(RADEON_CRTC2_H_SYNC_STRT_WID);
+       crtc2_v_sync_strt_wid = RREG32(RADEON_CRTC2_V_SYNC_STRT_WID);
+
+       tmp = RREG32(RADEON_GPIO_MONID);
+       tmp &= ~RADEON_GPIO_A_0;
+       WREG32(RADEON_GPIO_MONID, tmp);
+
+       WREG32(RADEON_FP2_GEN_CNTL, (RADEON_FP2_ON |
+                                    RADEON_FP2_PANEL_FORMAT |
+                                    R200_FP2_SOURCE_SEL_TRANS_UNIT |
+                                    RADEON_FP2_DVO_EN |
+                                    R200_FP2_DVO_RATE_SEL_SDR));
+
+       WREG32(RADEON_DISP_OUTPUT_CNTL, (RADEON_DISP_DAC_SOURCE_RMX |
+                                        RADEON_DISP_TRANS_MATRIX_GRAPHICS));
+
+       WREG32(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_EN |
+                                      RADEON_CRTC2_DISP_REQ_EN_B));
+
+       WREG32(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000);
+       WREG32(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0);
+       WREG32(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000);
+       WREG32(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0);
+       WREG32(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000);
+       WREG32(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0);
+
+       WREG32(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008);
+       WREG32(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800);
+       WREG32(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001);
+       WREG32(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080);
+
+       for (i = 0; i < 200; i++) {
+               tmp = RREG32(RADEON_GPIO_MONID);
+               if (tmp & RADEON_GPIO_Y_0)
+                       found = true;
+
+               if (found)
+                       break;
+
+               if (!drm_can_sleep())
+                       mdelay(1);
+               else
+                       msleep(1);
+       }
+
+       /* restore the regs we used */
+       WREG32(RADEON_DISP_LIN_TRANS_GRPH_A, disp_lin_trans_grph_a);
+       WREG32(RADEON_DISP_LIN_TRANS_GRPH_B, disp_lin_trans_grph_b);
+       WREG32(RADEON_DISP_LIN_TRANS_GRPH_C, disp_lin_trans_grph_c);
+       WREG32(RADEON_DISP_LIN_TRANS_GRPH_D, disp_lin_trans_grph_d);
+       WREG32(RADEON_DISP_LIN_TRANS_GRPH_E, disp_lin_trans_grph_e);
+       WREG32(RADEON_DISP_LIN_TRANS_GRPH_F, disp_lin_trans_grph_f);
+       WREG32(RADEON_CRTC2_H_TOTAL_DISP, crtc2_h_total_disp);
+       WREG32(RADEON_CRTC2_V_TOTAL_DISP, crtc2_v_total_disp);
+       WREG32(RADEON_CRTC2_H_SYNC_STRT_WID, crtc2_h_sync_strt_wid);
+       WREG32(RADEON_CRTC2_V_SYNC_STRT_WID, crtc2_v_sync_strt_wid);
+       WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
+       WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
+       WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
+       WREG32(RADEON_GPIO_MONID, gpio_monid);
+
+       return found;
+}
+
 static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder,
                                                             struct drm_connector *connector)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
-       uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl;
-       uint32_t disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp;
+       uint32_t crtc2_gen_cntl = 0, tv_dac_cntl, dac_cntl2, dac_ext_cntl;
+       uint32_t gpiopad_a = 0, pixclks_cntl, tmp;
+       uint32_t disp_output_cntl = 0, disp_hw_debug = 0, crtc_ext_cntl = 0;
        enum drm_connector_status found = connector_status_disconnected;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
@@ -1459,12 +1556,27 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder
                return connector_status_disconnected;
        }
 
+       /* R200 uses an external DAC for secondary DAC */
+       if (rdev->family == CHIP_R200) {
+               if (radeon_legacy_ext_dac_detect(encoder, connector))
+                       found = connector_status_connected;
+               return found;
+       }
+
        /* save the regs we need */
        pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
-       gpiopad_a = ASIC_IS_R300(rdev) ? RREG32(RADEON_GPIOPAD_A) : 0;
-       disp_output_cntl = ASIC_IS_R300(rdev) ? RREG32(RADEON_DISP_OUTPUT_CNTL) : 0;
-       disp_hw_debug = ASIC_IS_R300(rdev) ? 0 : RREG32(RADEON_DISP_HW_DEBUG);
-       crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
+
+       if (rdev->flags & RADEON_SINGLE_CRTC) {
+               crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
+       } else {
+               if (ASIC_IS_R300(rdev)) {
+                       gpiopad_a = RREG32(RADEON_GPIOPAD_A);
+                       disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL);
+               } else {
+                       disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG);
+               }
+               crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
+       }
        tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
        dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL);
        dac_cntl2 = RREG32(RADEON_DAC_CNTL2);
@@ -1473,22 +1585,24 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder
                               | RADEON_PIX2CLK_DAC_ALWAYS_ONb);
        WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
 
-       if (ASIC_IS_R300(rdev))
-               WREG32_P(RADEON_GPIOPAD_A, 1, ~1);
-
-       tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK;
-       tmp |= RADEON_CRTC2_CRT2_ON |
-               (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT);
-
-       WREG32(RADEON_CRTC2_GEN_CNTL, tmp);
-
-       if (ASIC_IS_R300(rdev)) {
-               tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK;
-               tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2;
-               WREG32(RADEON_DISP_OUTPUT_CNTL, tmp);
+       if (rdev->flags & RADEON_SINGLE_CRTC) {
+               tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON;
+               WREG32(RADEON_CRTC_EXT_CNTL, tmp);
        } else {
-               tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL;
-               WREG32(RADEON_DISP_HW_DEBUG, tmp);
+               tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK;
+               tmp |= RADEON_CRTC2_CRT2_ON |
+                       (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT);
+               WREG32(RADEON_CRTC2_GEN_CNTL, tmp);
+
+               if (ASIC_IS_R300(rdev)) {
+                       WREG32_P(RADEON_GPIOPAD_A, 1, ~1);
+                       tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK;
+                       tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2;
+                       WREG32(RADEON_DISP_OUTPUT_CNTL, tmp);
+               } else {
+                       tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL;
+                       WREG32(RADEON_DISP_HW_DEBUG, tmp);
+               }
        }
 
        tmp = RADEON_TV_DAC_NBLANK |
@@ -1530,14 +1644,19 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder
        WREG32(RADEON_DAC_CNTL2, dac_cntl2);
        WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl);
        WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
-       WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
 
-       if (ASIC_IS_R300(rdev)) {
-               WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
-               WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1);
+       if (rdev->flags & RADEON_SINGLE_CRTC) {
+               WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
        } else {
-               WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug);
+               WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
+               if (ASIC_IS_R300(rdev)) {
+                       WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
+                       WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1);
+               } else {
+                       WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug);
+               }
        }
+
        WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
 
        return found;
index b0db712..4422d63 100644 (file)
@@ -2474,6 +2474,7 @@ static bool si_vm_reg_valid(u32 reg)
        /* check config regs */
        switch (reg) {
        case GRBM_GFX_INDEX:
+       case CP_STRMOUT_CNTL:
        case VGT_VTX_VECT_EJECT_REG:
        case VGT_CACHE_INVALIDATION:
        case VGT_ESGS_RING_SIZE:
index 7d2a20e..a8871af 100644 (file)
 #       define RDERR_INT_ENABLE                         (1 << 0)
 #       define GUI_IDLE_INT_ENABLE                      (1 << 19)
 
+#define        CP_STRMOUT_CNTL                                 0x84FC
 #define        SCRATCH_REG0                                    0x8500
 #define        SCRATCH_REG1                                    0x8504
 #define        SCRATCH_REG2                                    0x8508
index fccd361..87aa5f5 100644 (file)
@@ -104,7 +104,7 @@ udl_fb_user_fb_create(struct drm_device *dev,
 
 int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr,
                     const char *front, char **urb_buf_ptr,
-                    u32 byte_offset, u32 byte_width,
+                    u32 byte_offset, u32 device_byte_offset, u32 byte_width,
                     int *ident_ptr, int *sent_ptr);
 
 int udl_dumb_create(struct drm_file *file_priv,
index 69a2b16..d4ab3be 100644 (file)
@@ -114,9 +114,10 @@ static void udlfb_dpy_deferred_io(struct fb_info *info,
        list_for_each_entry(cur, &fbdefio->pagelist, lru) {
 
                if (udl_render_hline(dev, (ufbdev->ufb.base.bits_per_pixel / 8),
-                                 &urb, (char *) info->fix.smem_start,
-                                 &cmd, cur->index << PAGE_SHIFT,
-                                 PAGE_SIZE, &bytes_identical, &bytes_sent))
+                                    &urb, (char *) info->fix.smem_start,
+                                    &cmd, cur->index << PAGE_SHIFT,
+                                    cur->index << PAGE_SHIFT,
+                                    PAGE_SIZE, &bytes_identical, &bytes_sent))
                        goto error;
                bytes_rendered += PAGE_SIZE;
        }
@@ -187,10 +188,11 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
        for (i = y; i < y + height ; i++) {
                const int line_offset = fb->base.pitches[0] * i;
                const int byte_offset = line_offset + (x * bpp);
-
+               const int dev_byte_offset = (fb->base.width * bpp * i) + (x * bpp);
                if (udl_render_hline(dev, bpp, &urb,
                                     (char *) fb->obj->vmapping,
-                                    &cmd, byte_offset, width * bpp,
+                                    &cmd, byte_offset, dev_byte_offset,
+                                    width * bpp,
                                     &bytes_identical, &bytes_sent))
                        goto error;
        }
index dc09552..142fee5 100644 (file)
@@ -213,11 +213,12 @@ static void udl_compress_hline16(
  */
 int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr,
                     const char *front, char **urb_buf_ptr,
-                    u32 byte_offset, u32 byte_width,
+                    u32 byte_offset, u32 device_byte_offset,
+                    u32 byte_width,
                     int *ident_ptr, int *sent_ptr)
 {
        const u8 *line_start, *line_end, *next_pixel;
-       u32 base16 = 0 + (byte_offset / bpp) * 2;
+       u32 base16 = 0 + (device_byte_offset / bpp) * 2;
        struct urb *urb = *urb_ptr;
        u8 *cmd = *urb_buf_ptr;
        u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
index 3ce68a2..d1498bf 100644 (file)
@@ -306,7 +306,7 @@ void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin)
 
        BUG_ON(!atomic_read(&bo->reserved));
        BUG_ON(old_mem_type != TTM_PL_VRAM &&
-              old_mem_type != VMW_PL_FLAG_GMR);
+              old_mem_type != VMW_PL_GMR);
 
        pl_flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED;
        if (pin)
index ed3c1e7..2dd185e 100644 (file)
@@ -1098,6 +1098,11 @@ static void vmw_pm_complete(struct device *kdev)
        struct drm_device *dev = pci_get_drvdata(pdev);
        struct vmw_private *dev_priv = vmw_priv(dev);
 
+       mutex_lock(&dev_priv->hw_mutex);
+       vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2);
+       (void) vmw_read(dev_priv, SVGA_REG_ID);
+       mutex_unlock(&dev_priv->hw_mutex);
+
        /**
         * Reclaim 3d reference held by fbdev and potentially
         * start fifo.
index 06ebdbb..fd7722a 100644 (file)
@@ -522,6 +522,12 @@ static const struct hid_device_id apple_devices[] = {
                .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
index bd3971b..f4109fd 100644 (file)
@@ -1532,6 +1532,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -2139,6 +2142,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { }
index 269b509..9d7a428 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI  0x0252
 #define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO   0x0253
 #define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS   0x0254
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI  0x0259
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO   0x025a
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS   0x025b
 #define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI  0x0249
 #define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO   0x024a
 #define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS   0x024b
index 3acdcfc..f676c01 100644 (file)
 #define MS_RDESC               0x08
 #define MS_NOGET               0x10
 #define MS_DUPLICATE_USAGES    0x20
+#define MS_RDESC_3K            0x40
 
-/*
- * Microsoft Wireless Desktop Receiver (Model 1028) has
- * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
- */
 static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
        unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 
+       /*
+        * Microsoft Wireless Desktop Receiver (Model 1028) has
+        * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
+        */
        if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 &&
                        rdesc[559] == 0x29) {
                hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
                rdesc[557] = 0x35;
                rdesc[559] = 0x45;
        }
+       /* the same as above (s/usage/physical/) */
+       if ((quirks & MS_RDESC_3K) && *rsize == 106 &&
+                       !memcmp((char []){ 0x19, 0x00, 0x29, 0xff },
+                               &rdesc[94], 4)) {
+               rdesc[94] = 0x35;
+               rdesc[96] = 0x45;
+       }
        return rdesc;
 }
 
@@ -192,7 +200,7 @@ static const struct hid_device_id ms_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
                .driver_data = MS_PRESENTER },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K),
-               .driver_data = MS_ERGONOMY },
+               .driver_data = MS_ERGONOMY | MS_RDESC_3K },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0),
                .driver_data = MS_NOGET },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500),
index 3eb02b9..7867d69 100644 (file)
@@ -210,8 +210,7 @@ static struct mt_class mt_classes[] = {
        },
        { .name = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
                .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
-                       MT_QUIRK_SLOT_IS_CONTACTNUMBER,
-               .maxcontacts = 10
+                       MT_QUIRK_SLOT_IS_CONTACTNUMBER
        },
 
        { .name = MT_CLS_FLATFROG,
@@ -421,11 +420,11 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                         * contact max are global to the report */
                        td->last_field_index = field->index;
                        return -1;
-               }
                case HID_DG_TOUCH:
                        /* Legacy devices use TIPSWITCH and not TOUCH.
                         * Let's just ignore this field. */
                        return -1;
+               }
                /* let hid-input decide for the others */
                return 0;
 
index 17d15bb..7c47fc3 100644 (file)
@@ -42,7 +42,6 @@ static struct cdev hidraw_cdev;
 static struct class *hidraw_class;
 static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
 static DEFINE_MUTEX(minors_lock);
-static void drop_ref(struct hidraw *hid, int exists_bit);
 
 static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 {
@@ -114,7 +113,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
        __u8 *buf;
        int ret = 0;
 
-       if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
+       if (!hidraw_table[minor]) {
                ret = -ENODEV;
                goto out;
        }
@@ -262,7 +261,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
        }
 
        mutex_lock(&minors_lock);
-       if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
+       if (!hidraw_table[minor]) {
                err = -ENODEV;
                goto out_unlock;
        }
@@ -299,12 +298,36 @@ out:
 static int hidraw_release(struct inode * inode, struct file * file)
 {
        unsigned int minor = iminor(inode);
+       struct hidraw *dev;
        struct hidraw_list *list = file->private_data;
+       int ret;
+       int i;
+
+       mutex_lock(&minors_lock);
+       if (!hidraw_table[minor]) {
+               ret = -ENODEV;
+               goto unlock;
+       }
 
-       drop_ref(hidraw_table[minor], 0);
        list_del(&list->node);
+       dev = hidraw_table[minor];
+       if (!--dev->open) {
+               if (list->hidraw->exist) {
+                       hid_hw_power(dev->hid, PM_HINT_NORMAL);
+                       hid_hw_close(dev->hid);
+               } else {
+                       kfree(list->hidraw);
+               }
+       }
+
+       for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i)
+               kfree(list->buffer[i].value);
        kfree(list);
-       return 0;
+       ret = 0;
+unlock:
+       mutex_unlock(&minors_lock);
+
+       return ret;
 }
 
 static long hidraw_ioctl(struct file *file, unsigned int cmd,
@@ -506,7 +529,21 @@ EXPORT_SYMBOL_GPL(hidraw_connect);
 void hidraw_disconnect(struct hid_device *hid)
 {
        struct hidraw *hidraw = hid->hidraw;
-       drop_ref(hidraw, 1);
+
+       mutex_lock(&minors_lock);
+       hidraw->exist = 0;
+
+       device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
+
+       hidraw_table[hidraw->minor] = NULL;
+
+       if (hidraw->open) {
+               hid_hw_close(hid);
+               wake_up_interruptible(&hidraw->wait);
+       } else {
+               kfree(hidraw);
+       }
+       mutex_unlock(&minors_lock);
 }
 EXPORT_SYMBOL_GPL(hidraw_disconnect);
 
@@ -555,23 +592,3 @@ void hidraw_exit(void)
        unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
 
 }
-
-static void drop_ref(struct hidraw *hidraw, int exists_bit)
-{
-       mutex_lock(&minors_lock);
-       if (exists_bit) {
-               hid_hw_close(hidraw->hid);
-               hidraw->exist = 0;
-               if (hidraw->open)
-                       wake_up_interruptible(&hidraw->wait);
-       } else {
-               --hidraw->open;
-       }
-
-       if (!hidraw->open && !hidraw->exist) {
-               device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
-               hidraw_table[hidraw->minor] = NULL;
-               kfree(hidraw);
-       }
-       mutex_unlock(&minors_lock);
-}
index a227be4..520e5bf 100644 (file)
@@ -32,7 +32,7 @@
  * ASB100-A supports pwm1, while plain ASB100 does not.  There is no known
  * way for the driver to tell which one is there.
  *
- * Chip        #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
+ * Chip                #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
  * asb100      7       3       1       4       0x31    0x0694  yes     no
  */
 
index 68ad7d2..4f41104 100644 (file)
@@ -2,7 +2,7 @@
  * fam15h_power.c - AMD Family 15h processor power monitoring
  *
  * Copyright (c) 2011 Advanced Micro Devices, Inc.
- * Author: Andreas Herrmann <andreas.herrmann3@amd.com>
+ * Author: Andreas Herrmann <herrmann.der.user@googlemail.com>
  *
  *
  * This driver is free software; you can redistribute it and/or
@@ -28,7 +28,7 @@
 #include <asm/processor.h>
 
 MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");
-MODULE_AUTHOR("Andreas Herrmann <andreas.herrmann3@amd.com>");
+MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>");
 MODULE_LICENSE("GPL");
 
 /* D18F3 */
index 36509ae..1381a2e 100644 (file)
@@ -630,7 +630,9 @@ static struct platform_driver gpio_fan_driver = {
        .driver = {
                .name   = "gpio-fan",
                .pm     = GPIO_FAN_PM,
+#ifdef CONFIG_OF_GPIO
                .of_match_table = of_match_ptr(of_gpio_fan_match),
+#endif
        },
 };
 
index 1821b74..de3c7e0 100644 (file)
@@ -2083,6 +2083,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
        mutex_init(&data->lock);
        mutex_init(&data->update_lock);
        data->name = w83627ehf_device_names[sio_data->kind];
+       data->bank = 0xff;              /* Force initial bank selection */
        platform_set_drvdata(pdev, data);
 
        /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
index 5b1a6a6..af15899 100644 (file)
@@ -25,7 +25,7 @@
 /*
  * Supports following chips:
  *
- * Chip        #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
+ * Chip                #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
  * w83627hf    9       3       2       3       0x20    0x5ca3  no      yes(LPC)
  * w83627thf   7       3       3       3       0x90    0x5ca3  no      yes(LPC)
  * w83637hf    7       3       3       3       0x80    0x5ca3  no      yes(LPC)
index 5a5046d..20f11d3 100644 (file)
@@ -24,7 +24,7 @@
 /*
  * Supports following chips:
  *
- * Chip        #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
+ * Chip                #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
  * as99127f    7       3       0       3       0x31    0x12c3  yes     no
  * as99127f rev.2 (type_name = as99127f)       0x31    0x5ca3  yes     no
  * w83781d     7       3       0       3       0x10-1  0x5ca3  yes     yes
index 39ab7bc..ed397c6 100644 (file)
@@ -22,7 +22,7 @@
 /*
  * Supports following chips:
  *
- * Chip        #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
+ * Chip                #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
  * w83791d     10      5       5       3       0x71    0x5ca3  yes     no
  *
  * The w83791d chip appears to be part way between the 83781d and the
index 0536452..301942d 100644 (file)
@@ -31,7 +31,7 @@
 /*
  * Supports following chips:
  *
- * Chip        #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
+ * Chip                #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
  * w83792d     9       7       7       3       0x7a    0x5ca3  yes     no
  */
 
index f0e8286..79710bc 100644 (file)
@@ -20,7 +20,7 @@
 /*
  * Supports following chips:
  *
- * Chip        #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
+ * Chip                #vin    #fanin  #pwm    #temp   wchipid vendid  i2c     ISA
  * w83l786ng   3       2       2       2       0x7b    0x5ca3  yes     no
  */
 
index beee6b2..1722f50 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_I2C_SMBUS)         += i2c-smbus.o
 obj-$(CONFIG_I2C_CHARDEV)      += i2c-dev.o
 obj-$(CONFIG_I2C_MUX)          += i2c-mux.o
 obj-y                          += algos/ busses/ muxes/
+obj-$(CONFIG_I2C_STUB)         += i2c-stub.o
 
 ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
 CFLAGS_i2c-core.o := -Wno-deprecated-declarations
index 65dd599..e9df461 100644 (file)
@@ -81,7 +81,6 @@ config I2C_I801
        tristate "Intel 82801 (ICH/PCH)"
        depends on PCI
        select CHECK_SIGNATURE if X86 && DMI
-       select GPIOLIB if I2C_MUX
        help
          If you say yes to this option, support will be included for the Intel
          801 family of mainboard I2C interfaces.  Specifically, the following
index 2d33d62..395b516 100644 (file)
@@ -85,7 +85,6 @@ obj-$(CONFIG_I2C_ACORN)               += i2c-acorn.o
 obj-$(CONFIG_I2C_ELEKTOR)      += i2c-elektor.o
 obj-$(CONFIG_I2C_PCA_ISA)      += i2c-pca-isa.o
 obj-$(CONFIG_I2C_SIBYTE)       += i2c-sibyte.o
-obj-$(CONFIG_I2C_STUB)         += i2c-stub.o
 obj-$(CONFIG_SCx200_ACB)       += scx200_acb.o
 obj-$(CONFIG_SCx200_I2C)       += scx200_i2c.o
 
index 3779315..6abc00d 100644 (file)
@@ -82,7 +82,8 @@
 #include <linux/wait.h>
 #include <linux/err.h>
 
-#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
+#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
+               defined CONFIG_DMI
 #include <linux/gpio.h>
 #include <linux/i2c-mux-gpio.h>
 #include <linux/platform_device.h>
@@ -192,7 +193,8 @@ struct i801_priv {
        int len;
        u8 *data;
 
-#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
+#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
+               defined CONFIG_DMI
        const struct i801_mux_config *mux_drvdata;
        struct platform_device *mux_pdev;
 #endif
@@ -921,7 +923,8 @@ static void __init input_apanel_init(void) {}
 static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {}
 #endif /* CONFIG_X86 && CONFIG_DMI */
 
-#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
+#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
+               defined CONFIG_DMI
 static struct i801_mux_config i801_mux_config_asus_z8_d12 = {
        .gpio_chip = "gpio_ich",
        .values = { 0x02, 0x03 },
@@ -1059,7 +1062,7 @@ static unsigned int __devinit i801_get_adapter_class(struct i801_priv *priv)
 
        id = dmi_first_match(mux_dmi_table);
        if (id) {
-               /* Remove from branch classes from trunk */
+               /* Remove branch classes from trunk */
                mux_config = id->driver_data;
                for (i = 0; i < mux_config->n_values; i++)
                        class &= ~mux_config->classes[i];
index 1f58197..286ca19 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Freescale MXS I2C bus driver
  *
- * Copyright (C) 2011 Wolfram Sang, Pengutronix e.K.
+ * Copyright (C) 2011-2012 Wolfram Sang, Pengutronix e.K.
  *
  * based on a (non-working) driver which was:
  *
 
 #define DRIVER_NAME "mxs-i2c"
 
-static bool use_pioqueue;
-module_param(use_pioqueue, bool, 0);
-MODULE_PARM_DESC(use_pioqueue, "Use PIOQUEUE mode for transfer instead of DMA");
-
 #define MXS_I2C_CTRL0          (0x00)
 #define MXS_I2C_CTRL0_SET      (0x04)
 
@@ -75,23 +71,6 @@ MODULE_PARM_DESC(use_pioqueue, "Use PIOQUEUE mode for transfer instead of DMA");
                                 MXS_I2C_CTRL1_SLAVE_STOP_IRQ | \
                                 MXS_I2C_CTRL1_SLAVE_IRQ)
 
-#define MXS_I2C_QUEUECTRL      (0x60)
-#define MXS_I2C_QUEUECTRL_SET  (0x64)
-#define MXS_I2C_QUEUECTRL_CLR  (0x68)
-
-#define MXS_I2C_QUEUECTRL_QUEUE_RUN            0x20
-#define MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE       0x04
-
-#define MXS_I2C_QUEUESTAT      (0x70)
-#define MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY        0x00002000
-#define MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK 0x0000001F
-
-#define MXS_I2C_QUEUECMD       (0x80)
-
-#define MXS_I2C_QUEUEDATA      (0x90)
-
-#define MXS_I2C_DATA           (0xa0)
-
 
 #define MXS_CMD_I2C_SELECT     (MXS_I2C_CTRL0_RETAIN_CLOCK |   \
                                 MXS_I2C_CTRL0_PRE_SEND_START | \
@@ -153,7 +132,6 @@ struct mxs_i2c_dev {
        const struct mxs_i2c_speed_config *speed;
 
        /* DMA support components */
-       bool                            dma_mode;
        int                             dma_channel;
        struct dma_chan                 *dmach;
        struct mxs_dma_data             dma_data;
@@ -172,99 +150,6 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
        writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);
 
        writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
-       if (i2c->dma_mode)
-               writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
-                       i2c->regs + MXS_I2C_QUEUECTRL_CLR);
-       else
-               writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
-                       i2c->regs + MXS_I2C_QUEUECTRL_SET);
-}
-
-static void mxs_i2c_pioq_setup_read(struct mxs_i2c_dev *i2c, u8 addr, int len,
-                                       int flags)
-{
-       u32 data;
-
-       writel(MXS_CMD_I2C_SELECT, i2c->regs + MXS_I2C_QUEUECMD);
-
-       data = (addr << 1) | I2C_SMBUS_READ;
-       writel(data, i2c->regs + MXS_I2C_DATA);
-
-       data = MXS_CMD_I2C_READ | MXS_I2C_CTRL0_XFER_COUNT(len) | flags;
-       writel(data, i2c->regs + MXS_I2C_QUEUECMD);
-}
-
-static void mxs_i2c_pioq_setup_write(struct mxs_i2c_dev *i2c,
-                                   u8 addr, u8 *buf, int len, int flags)
-{
-       u32 data;
-       int i, shifts_left;
-
-       data = MXS_CMD_I2C_WRITE | MXS_I2C_CTRL0_XFER_COUNT(len + 1) | flags;
-       writel(data, i2c->regs + MXS_I2C_QUEUECMD);
-
-       /*
-        * We have to copy the slave address (u8) and buffer (arbitrary number
-        * of u8) into the data register (u32). To achieve that, the u8 are put
-        * into the MSBs of 'data' which is then shifted for the next u8. When
-        * appropriate, 'data' is written to MXS_I2C_DATA. So, the first u32
-        * looks like this:
-        *
-        *  3          2          1          0
-        * 10987654|32109876|54321098|76543210
-        * --------+--------+--------+--------
-        * buffer+2|buffer+1|buffer+0|slave_addr
-        */
-
-       data = ((addr << 1) | I2C_SMBUS_WRITE) << 24;
-
-       for (i = 0; i < len; i++) {
-               data >>= 8;
-               data |= buf[i] << 24;
-               if ((i & 3) == 2)
-                       writel(data, i2c->regs + MXS_I2C_DATA);
-       }
-
-       /* Write out the remaining bytes if any */
-       shifts_left = 24 - (i & 3) * 8;
-       if (shifts_left)
-               writel(data >> shifts_left, i2c->regs + MXS_I2C_DATA);
-}
-
-/*
- * TODO: should be replaceable with a waitqueue and RD_QUEUE_IRQ (setting the
- * rd_threshold to 1). Couldn't get this to work, though.
- */
-static int mxs_i2c_wait_for_data(struct mxs_i2c_dev *i2c)
-{
-       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-
-       while (readl(i2c->regs + MXS_I2C_QUEUESTAT)
-                       & MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY) {
-                       if (time_after(jiffies, timeout))
-                               return -ETIMEDOUT;
-                       cond_resched();
-       }
-
-       return 0;
-}
-
-static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)
-{
-       u32 uninitialized_var(data);
-       int i;
-
-       for (i = 0; i < len; i++) {
-               if ((i & 3) == 0) {
-                       if (mxs_i2c_wait_for_data(i2c))
-                               return -ETIMEDOUT;
-                       data = readl(i2c->regs + MXS_I2C_QUEUEDATA);
-               }
-               buf[i] = data & 0xff;
-               data >>= 8;
-       }
-
-       return 0;
 }
 
 static void mxs_i2c_dma_finish(struct mxs_i2c_dev *i2c)
@@ -432,39 +317,17 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
        init_completion(&i2c->cmd_complete);
        i2c->cmd_err = 0;
 
-       if (i2c->dma_mode) {
-               ret = mxs_i2c_dma_setup_xfer(adap, msg, flags);
-               if (ret)
-                       return ret;
-       } else {
-               if (msg->flags & I2C_M_RD) {
-                       mxs_i2c_pioq_setup_read(i2c, msg->addr,
-                                               msg->len, flags);
-               } else {
-                       mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf,
-                                               msg->len, flags);
-               }
-
-               writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
-                       i2c->regs + MXS_I2C_QUEUECTRL_SET);
-       }
+       ret = mxs_i2c_dma_setup_xfer(adap, msg, flags);
+       if (ret)
+               return ret;
 
        ret = wait_for_completion_timeout(&i2c->cmd_complete,
                                                msecs_to_jiffies(1000));
        if (ret == 0)
                goto timeout;
 
-       if (!i2c->dma_mode && !i2c->cmd_err && (msg->flags & I2C_M_RD)) {
-               ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len);
-               if (ret)
-                       goto timeout;
-       }
-
        if (i2c->cmd_err == -ENXIO)
                mxs_i2c_reset(i2c);
-       else
-               writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
-                               i2c->regs + MXS_I2C_QUEUECTRL_CLR);
 
        dev_dbg(i2c->dev, "Done with err=%d\n", i2c->cmd_err);
 
@@ -472,8 +335,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
 
 timeout:
        dev_dbg(i2c->dev, "Timeout!\n");
-       if (i2c->dma_mode)
-               mxs_i2c_dma_finish(i2c);
+       mxs_i2c_dma_finish(i2c);
        mxs_i2c_reset(i2c);
        return -ETIMEDOUT;
 }
@@ -502,7 +364,6 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
 {
        struct mxs_i2c_dev *i2c = dev_id;
        u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK;
-       bool is_last_cmd;
 
        if (!stat)
                return IRQ_NONE;
@@ -515,14 +376,6 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
                /* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */
                i2c->cmd_err = -EIO;
 
-       if (!i2c->dma_mode) {
-               is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
-                       MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;
-
-               if (is_last_cmd || i2c->cmd_err)
-                       complete(&i2c->cmd_complete);
-       }
-
        writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR);
 
        return IRQ_HANDLED;
@@ -556,23 +409,14 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
        int ret;
 
        /*
-        * The MXS I2C DMA mode is prefered and enabled by default.
-        * The PIO mode is still supported, but should be used only
-        * for debuging purposes etc.
-        */
-       i2c->dma_mode = !use_pioqueue;
-       if (!i2c->dma_mode)
-               dev_info(dev, "Using PIOQUEUE mode for I2C transfers!\n");
-
-       /*
         * TODO: This is a temporary solution and should be changed
         * to use generic DMA binding later when the helpers get in.
         */
        ret = of_property_read_u32(node, "fsl,i2c-dma-channel",
                                   &i2c->dma_channel);
        if (ret) {
-               dev_warn(dev, "Failed to get DMA channel, using PIOQUEUE!\n");
-               i2c->dma_mode = 0;
+               dev_err(dev, "Failed to get DMA channel!\n");
+               return -ENODEV;
        }
 
        ret = of_property_read_u32(node, "clock-frequency", &speed);
@@ -634,15 +478,13 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
        }
 
        /* Setup the DMA */
-       if (i2c->dma_mode) {
-               dma_cap_zero(mask);
-               dma_cap_set(DMA_SLAVE, mask);
-               i2c->dma_data.chan_irq = dmairq;
-               i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c);
-               if (!i2c->dmach) {
-                       dev_err(dev, "Failed to request dma\n");
-                       return -ENODEV;
-               }
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       i2c->dma_data.chan_irq = dmairq;
+       i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c);
+       if (!i2c->dmach) {
+               dev_err(dev, "Failed to request dma\n");
+               return -ENODEV;
        }
 
        platform_set_drvdata(pdev, i2c);
index 698d7ac..02c3115 100644 (file)
@@ -644,7 +644,11 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
 
        pm_runtime_get_sync(&dev->adev->dev);
 
-       clk_enable(dev->clk);
+       status = clk_prepare_enable(dev->clk);
+       if (status) {
+               dev_err(&dev->adev->dev, "can't prepare_enable clock\n");
+               goto out_clk;
+       }
 
        status = init_hw(dev);
        if (status)
@@ -671,7 +675,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
        }
 
 out:
-       clk_disable(dev->clk);
+       clk_disable_unprepare(dev->clk);
+out_clk:
        pm_runtime_put_sync(&dev->adev->dev);
 
        dev->busy = false;
index f981ac4..dcea77b 100644 (file)
@@ -742,7 +742,7 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
        }
 
        ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
-                       tegra_i2c_isr, 0, pdev->name, i2c_dev);
+                       tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
        if (ret) {
                dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
                return ret;
similarity index 75%
rename from drivers/i2c/busses/i2c-stub.c
rename to drivers/i2c/i2c-stub.c
index b1b3447..d0a9c59 100644 (file)
@@ -2,7 +2,7 @@
     i2c-stub.c - I2C/SMBus chip emulator
 
     Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
-    Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
+    Copyright (C) 2007, 2012 Jean Delvare <khali@linux-fr.org>
 
     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
@@ -51,8 +51,8 @@ struct stub_chip {
 static struct stub_chip *stub_chips;
 
 /* Return negative errno on error. */
-static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
-       char read_write, u8 command, int size, union i2c_smbus_data * data)
+static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
+       char read_write, u8 command, int size, union i2c_smbus_data *data)
 {
        s32 ret;
        int i, len;
@@ -78,14 +78,14 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
        case I2C_SMBUS_BYTE:
                if (read_write == I2C_SMBUS_WRITE) {
                        chip->pointer = command;
-                       dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
-                                       "wrote 0x%02x.\n",
-                                       addr, command);
+                       dev_dbg(&adap->dev,
+                               "smbus byte - addr 0x%02x, wrote 0x%02x.\n",
+                               addr, command);
                } else {
                        data->byte = chip->words[chip->pointer++] & 0xff;
-                       dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
-                                       "read  0x%02x.\n",
-                                       addr, data->byte);
+                       dev_dbg(&adap->dev,
+                               "smbus byte - addr 0x%02x, read  0x%02x.\n",
+                               addr, data->byte);
                }
 
                ret = 0;
@@ -95,14 +95,14 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
                if (read_write == I2C_SMBUS_WRITE) {
                        chip->words[command] &= 0xff00;
                        chip->words[command] |= data->byte;
-                       dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
-                                       "wrote 0x%02x at 0x%02x.\n",
-                                       addr, data->byte, command);
+                       dev_dbg(&adap->dev,
+                               "smbus byte data - addr 0x%02x, wrote 0x%02x at 0x%02x.\n",
+                               addr, data->byte, command);
                } else {
                        data->byte = chip->words[command] & 0xff;
-                       dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
-                                       "read  0x%02x at 0x%02x.\n",
-                                       addr, data->byte, command);
+                       dev_dbg(&adap->dev,
+                               "smbus byte data - addr 0x%02x, read  0x%02x at 0x%02x.\n",
+                               addr, data->byte, command);
                }
                chip->pointer = command + 1;
 
@@ -112,14 +112,14 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
        case I2C_SMBUS_WORD_DATA:
                if (read_write == I2C_SMBUS_WRITE) {
                        chip->words[command] = data->word;
-                       dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
-                                       "wrote 0x%04x at 0x%02x.\n",
-                                       addr, data->word, command);
+                       dev_dbg(&adap->dev,
+                               "smbus word data - addr 0x%02x, wrote 0x%04x at 0x%02x.\n",
+                               addr, data->word, command);
                } else {
                        data->word = chip->words[command];
-                       dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
-                                       "read  0x%04x at 0x%02x.\n",
-                                       addr, data->word, command);
+                       dev_dbg(&adap->dev,
+                               "smbus word data - addr 0x%02x, read  0x%04x at 0x%02x.\n",
+                               addr, data->word, command);
                }
 
                ret = 0;
@@ -132,17 +132,17 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
                                chip->words[command + i] &= 0xff00;
                                chip->words[command + i] |= data->block[1 + i];
                        }
-                       dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, "
-                                       "wrote %d bytes at 0x%02x.\n",
-                                       addr, len, command);
+                       dev_dbg(&adap->dev,
+                               "i2c block data - addr 0x%02x, wrote %d bytes at 0x%02x.\n",
+                               addr, len, command);
                } else {
                        for (i = 0; i < len; i++) {
                                data->block[1 + i] =
                                        chip->words[command + i] & 0xff;
                        }
-                       dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, "
-                                       "read  %d bytes at 0x%02x.\n",
-                                       addr, len, command);
+                       dev_dbg(&adap->dev,
+                               "i2c block data - addr 0x%02x, read  %d bytes at 0x%02x.\n",
+                               addr, len, command);
                }
 
                ret = 0;
@@ -179,25 +179,24 @@ static int __init i2c_stub_init(void)
        int i, ret;
 
        if (!chip_addr[0]) {
-               printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
+               pr_err("i2c-stub: Please specify a chip address\n");
                return -ENODEV;
        }
 
        for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
                if (chip_addr[i] < 0x03 || chip_addr[i] > 0x77) {
-                       printk(KERN_ERR "i2c-stub: Invalid chip address "
-                              "0x%02x\n", chip_addr[i]);
+                       pr_err("i2c-stub: Invalid chip address 0x%02x\n",
+                              chip_addr[i]);
                        return -EINVAL;
                }
 
-               printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n",
-                      chip_addr[i]);
+               pr_info("i2c-stub: Virtual chip at 0x%02x\n", chip_addr[i]);
        }
 
        /* Allocate memory for all chips at once */
        stub_chips = kzalloc(i * sizeof(struct stub_chip), GFP_KERNEL);
        if (!stub_chips) {
-               printk(KERN_ERR "i2c-stub: Out of memory\n");
+               pr_err("i2c-stub: Out of memory\n");
                return -ENOMEM;
        }
 
@@ -219,4 +218,3 @@ MODULE_LICENSE("GPL");
 
 module_init(i2c_stub_init);
 module_exit(i2c_stub_exit);
-
index b4b65af..de08740 100644 (file)
@@ -335,6 +335,7 @@ config KEYBOARD_LOCOMO
 config KEYBOARD_LPC32XX
        tristate "LPC32XX matrix key scanner support"
        depends on ARCH_LPC32XX && OF
+       select INPUT_MATRIXKMAP
        help
          Say Y here if you want to use NXP LPC32XX SoC key scanner interface,
          connected to a key matrix.
index 803ff6f..cad9d5d 100644 (file)
@@ -368,6 +368,9 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
        unsigned int mask = 0, direct_key_num = 0;
        unsigned long kpc = 0;
 
+       /* clear pending interrupt bit */
+       keypad_readl(KPC);
+
        /* enable matrix keys with automatic scan */
        if (pdata->matrix_key_rows && pdata->matrix_key_cols) {
                kpc |= KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL;
index 02ca868..6f7d990 100644 (file)
@@ -311,7 +311,6 @@ static void xenkbd_backend_changed(struct xenbus_device *dev,
        case XenbusStateReconfiguring:
        case XenbusStateReconfigured:
        case XenbusStateUnknown:
-       case XenbusStateClosed:
                break;
 
        case XenbusStateInitWait:
@@ -350,6 +349,10 @@ InitWait:
 
                break;
 
+       case XenbusStateClosed:
+               if (dev->state == XenbusStateClosed)
+                       break;
+               /* Missed the backend's CLOSING state -- fallthrough */
        case XenbusStateClosing:
                xenbus_frontend_closed(dev);
                break;
index 3a78f23..2baff1b 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI   0x0262
 #define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO    0x0263
 #define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS    0x0264
+/* MacbookPro10,2 (unibody, October 2012) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI  0x0259
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO   0x025a
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS   0x025b
 
 #define BCM5974_DEVICE(prod) {                                 \
        .match_flags = (USB_DEVICE_ID_MATCH_DEVICE |            \
@@ -137,6 +141,10 @@ static const struct usb_device_id bcm5974_table[] = {
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ISO),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_JIS),
+       /* MacbookPro10,2 */
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS),
        /* Terminating entry */
        {}
 };
@@ -379,6 +387,19 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                { SN_COORD, -150, 6730 },
                { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
+       {
+               USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI,
+               USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO,
+               USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS,
+               HAS_INTEGRATED_BUTTON,
+               0x84, sizeof(struct bt_data),
+               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               { SN_PRESSURE, 0, 300 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4750, 5280 },
+               { SN_COORD, -150, 6730 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
+       },
        {}
 };
 
index 2c1e12b..858ad44 100644 (file)
@@ -391,7 +391,7 @@ static int wacom_parse_hid(struct usb_interface *intf,
                                                        features->pktlen = WACOM_PKGLEN_TPC2FG;
                                                }
 
-                                               if (features->type == MTSCREEN || WACOM_24HDT)
+                                               if (features->type == MTSCREEN || features->type == WACOM_24HDT)
                                                        features->pktlen = WACOM_PKGLEN_MTOUCH;
 
                                                if (features->type == BAMBOO_PT) {
index aa60101..0a67031 100644 (file)
@@ -1518,6 +1518,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
+
+               __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
                wacom_setup_cintiq(wacom_wac);
                break;
 
index 1ba232c..f7668b2 100644 (file)
@@ -239,7 +239,7 @@ config TOUCHSCREEN_EETI
 
 config TOUCHSCREEN_EGALAX
        tristate "EETI eGalax multi-touch panel support"
-       depends on I2C
+       depends on I2C && OF
        help
          Say Y here to enable support for I2C connected EETI
          eGalax multi-touch panels.
index c1e3460..13fa62f 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/bitops.h>
 #include <linux/input/mt.h>
+#include <linux/of_gpio.h>
 
 /*
  * Mouse Mode: some panel may configure the controller to mouse mode,
@@ -122,9 +123,17 @@ static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id)
 /* wake up controller by an falling edge of interrupt gpio.  */
 static int egalax_wake_up_device(struct i2c_client *client)
 {
-       int gpio = irq_to_gpio(client->irq);
+       struct device_node *np = client->dev.of_node;
+       int gpio;
        int ret;
 
+       if (!np)
+               return -ENODEV;
+
+       gpio = of_get_named_gpio(np, "wakeup-gpios", 0);
+       if (!gpio_is_valid(gpio))
+               return -ENODEV;
+
        ret = gpio_request(gpio, "egalax_irq");
        if (ret < 0) {
                dev_err(&client->dev,
@@ -181,7 +190,11 @@ static int __devinit egalax_ts_probe(struct i2c_client *client,
        ts->input_dev = input_dev;
 
        /* controller may be in sleep, wake it up. */
-       egalax_wake_up_device(client);
+       error = egalax_wake_up_device(client);
+       if (error) {
+               dev_err(&client->dev, "Failed to wake up the controller\n");
+               goto err_free_dev;
+       }
 
        ret = egalax_firmware_version(client);
        if (ret < 0) {
@@ -274,11 +287,17 @@ static int egalax_ts_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume);
 
+static struct of_device_id egalax_ts_dt_ids[] = {
+       { .compatible = "eeti,egalax_ts" },
+       { /* sentinel */ }
+};
+
 static struct i2c_driver egalax_ts_driver = {
        .driver = {
                .name   = "egalax_ts",
                .owner  = THIS_MODULE,
                .pm     = &egalax_ts_pm_ops,
+               .of_match_table = of_match_ptr(egalax_ts_dt_ids),
        },
        .id_table       = egalax_ts_id,
        .probe          = egalax_ts_probe,
index 63209aa..eb96f16 100644 (file)
@@ -107,7 +107,6 @@ static int tsc_connect(struct serio *serio, struct serio_driver *drv)
        __set_bit(BTN_TOUCH, input_dev->keybit);
        input_set_abs_params(ptsc->dev, ABS_X, 0, 0x3ff, 0, 0);
        input_set_abs_params(ptsc->dev, ABS_Y, 0, 0x3ff, 0, 0);
-       input_set_abs_params(ptsc->dev, ABS_PRESSURE, 0, 0, 0, 0);
 
        serio_set_drvdata(serio, ptsc);
 
index a233ed5..86cd75a 100644 (file)
@@ -4,7 +4,7 @@
 
 menuconfig ISDN
        bool "ISDN support"
-       depends on NET
+       depends on NET && NETDEVICES
        depends on !S390 && !UML
        ---help---
          ISDN ("Integrated Services Digital Network", called RNIS in France)
index 2302fbe..9c6650e 100644 (file)
@@ -6,7 +6,7 @@ if ISDN_I4L
 
 config ISDN_PPP
        bool "Support synchronous PPP"
-       depends on INET && NETDEVICES
+       depends on INET
        select SLHC
        help
          Over digital connections such as ISDN, there is no need to
index 8c610fa..e2a945e 100644 (file)
@@ -1312,7 +1312,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg)
                        } else
                                return -EINVAL;
                        break;
-#ifdef CONFIG_NETDEVICES
                case IIOCNETGPN:
                        /* Get peer phone number of a connected
                         * isdn network interface */
@@ -1322,7 +1321,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg)
                                return isdn_net_getpeer(&phone, argp);
                        } else
                                return -EINVAL;
-#endif
                default:
                        return -EINVAL;
                }
@@ -1352,7 +1350,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg)
                case IIOCNETLCR:
                        printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
                        return -ENODEV;
-#ifdef CONFIG_NETDEVICES
                case IIOCNETAIF:
                        /* Add a network-interface */
                        if (arg) {
@@ -1491,7 +1488,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg)
                                return -EFAULT;
                        return isdn_net_force_hangup(name);
                        break;
-#endif                          /* CONFIG_NETDEVICES */
                case IIOCSETVER:
                        dev->net_verbose = arg;
                        printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
index 45135f6..5e7dc77 100644 (file)
@@ -315,8 +315,11 @@ static int run(struct mddev *mddev)
        }
        conf->nfaults = 0;
 
-       rdev_for_each(rdev, mddev)
+       rdev_for_each(rdev, mddev) {
                conf->rdev = rdev;
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
+       }
 
        md_set_array_sectors(mddev, faulty_size(mddev, 0, 0));
        mddev->private = conf;
index 8034fbd..636bae0 100644 (file)
@@ -2710,7 +2710,7 @@ static struct r1conf *setup_conf(struct mddev *mddev)
                    || disk_idx < 0)
                        continue;
                if (test_bit(Replacement, &rdev->flags))
-                       disk = conf->mirrors + conf->raid_disks + disk_idx;
+                       disk = conf->mirrors + mddev->raid_disks + disk_idx;
                else
                        disk = conf->mirrors + disk_idx;
 
index 906ccbd..d1295af 100644 (file)
@@ -1783,7 +1783,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
                clear_bit(Unmerged, &rdev->flags);
        }
        md_integrity_add_rdev(rdev, mddev);
-       if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+       if (mddev->queue && blk_queue_discard(bdev_get_queue(rdev->bdev)))
                queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
 
        print_conf(conf);
@@ -3613,11 +3613,14 @@ static int run(struct mddev *mddev)
                        discard_supported = true;
        }
 
-       if (discard_supported)
-               queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
-       else
-               queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
-
+       if (mddev->queue) {
+               if (discard_supported)
+                       queue_flag_set_unlocked(QUEUE_FLAG_DISCARD,
+                                               mddev->queue);
+               else
+                       queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD,
+                                                 mddev->queue);
+       }
        /* need to check that every block has at least one working mirror */
        if (!enough(conf, -1)) {
                printk(KERN_ERR "md/raid10:%s: not enough operational mirrors.\n",
index 660bbc5..4d50da6 100644 (file)
@@ -208,7 +208,7 @@ static unsigned long exynos5250_dwmmc_caps[4] = {
        MMC_CAP_CMD23,
 };
 
-static struct dw_mci_drv_data exynos5250_drv_data = {
+static const struct dw_mci_drv_data exynos5250_drv_data = {
        .caps                   = exynos5250_dwmmc_caps,
        .init                   = dw_mci_exynos_priv_init,
        .setup_clock            = dw_mci_exynos_setup_clock,
@@ -220,14 +220,14 @@ static struct dw_mci_drv_data exynos5250_drv_data = {
 
 static const struct of_device_id dw_mci_exynos_match[] = {
        { .compatible = "samsung,exynos5250-dw-mshc",
-                       .data = (void *)&exynos5250_drv_data, },
+                       .data = &exynos5250_drv_data, },
        {},
 };
-MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
+MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);
 
 int dw_mci_exynos_probe(struct platform_device *pdev)
 {
-       struct dw_mci_drv_data *drv_data;
+       const struct dw_mci_drv_data *drv_data;
        const struct of_device_id *match;
 
        match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node);
index c960ca7..917936b 100644 (file)
@@ -24,7 +24,7 @@
 #include "dw_mmc.h"
 
 int dw_mci_pltfm_register(struct platform_device *pdev,
-                               struct dw_mci_drv_data *drv_data)
+                               const struct dw_mci_drv_data *drv_data)
 {
        struct dw_mci *host;
        struct resource *regs;
@@ -50,8 +50,8 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
        if (!host->regs)
                return -ENOMEM;
 
-       if (host->drv_data->init) {
-               ret = host->drv_data->init(host);
+       if (drv_data && drv_data->init) {
+               ret = drv_data->init(host);
                if (ret)
                        return ret;
        }
index 301f245..2ac37b8 100644 (file)
@@ -13,7 +13,7 @@
 #define _DW_MMC_PLTFM_H_
 
 extern int dw_mci_pltfm_register(struct platform_device *pdev,
-                               struct dw_mci_drv_data *drv_data);
+                               const struct dw_mci_drv_data *drv_data);
 extern int __devexit dw_mci_pltfm_remove(struct platform_device *pdev);
 extern const struct dev_pm_ops dw_mci_pltfm_pmops;
 
index c2828f3..c0667c8 100644 (file)
@@ -232,6 +232,7 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
 {
        struct mmc_data *data;
        struct dw_mci_slot *slot = mmc_priv(mmc);
+       struct dw_mci_drv_data *drv_data = slot->host->drv_data;
        u32 cmdr;
        cmd->error = -EINPROGRESS;
 
@@ -261,8 +262,8 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
                        cmdr |= SDMMC_CMD_DAT_WR;
        }
 
-       if (slot->host->drv_data->prepare_command)
-               slot->host->drv_data->prepare_command(slot->host, &cmdr);
+       if (drv_data && drv_data->prepare_command)
+               drv_data->prepare_command(slot->host, &cmdr);
 
        return cmdr;
 }
@@ -434,7 +435,7 @@ static int dw_mci_idmac_init(struct dw_mci *host)
        return 0;
 }
 
-static struct dw_mci_dma_ops dw_mci_idmac_ops = {
+static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
        .init = dw_mci_idmac_init,
        .start = dw_mci_idmac_start_dma,
        .stop = dw_mci_idmac_stop_dma,
@@ -772,6 +773,7 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct dw_mci_slot *slot = mmc_priv(mmc);
+       struct dw_mci_drv_data *drv_data = slot->host->drv_data;
        u32 regs;
 
        /* set default 1 bit mode */
@@ -807,8 +809,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                slot->clock = ios->clock;
        }
 
-       if (slot->host->drv_data->set_ios)
-               slot->host->drv_data->set_ios(slot->host, ios);
+       if (drv_data && drv_data->set_ios)
+               drv_data->set_ios(slot->host, ios);
 
        switch (ios->power_mode) {
        case MMC_POWER_UP:
@@ -1815,6 +1817,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 {
        struct mmc_host *mmc;
        struct dw_mci_slot *slot;
+       struct dw_mci_drv_data *drv_data = host->drv_data;
        int ctrl_id, ret;
        u8 bus_width;
 
@@ -1854,8 +1857,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        } else {
                ctrl_id = to_platform_device(host->dev)->id;
        }
-       if (host->drv_data && host->drv_data->caps)
-               mmc->caps |= host->drv_data->caps[ctrl_id];
+       if (drv_data && drv_data->caps)
+               mmc->caps |= drv_data->caps[ctrl_id];
 
        if (host->pdata->caps2)
                mmc->caps2 = host->pdata->caps2;
@@ -1867,10 +1870,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        else
                bus_width = 1;
 
-       if (host->drv_data->setup_bus) {
+       if (drv_data && drv_data->setup_bus) {
                struct device_node *slot_np;
                slot_np = dw_mci_of_find_slot_node(host->dev, slot->id);
-               ret = host->drv_data->setup_bus(host, slot_np, bus_width);
+               ret = drv_data->setup_bus(host, slot_np, bus_width);
                if (ret)
                        goto err_setup_bus;
        }
@@ -1968,7 +1971,7 @@ static void dw_mci_init_dma(struct dw_mci *host)
        /* Determine which DMA interface to use */
 #ifdef CONFIG_MMC_DW_IDMAC
        host->dma_ops = &dw_mci_idmac_ops;
-       dev_info(&host->dev, "Using internal DMA controller.\n");
+       dev_info(host->dev, "Using internal DMA controller.\n");
 #endif
 
        if (!host->dma_ops)
@@ -2035,6 +2038,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
        struct dw_mci_board *pdata;
        struct device *dev = host->dev;
        struct device_node *np = dev->of_node;
+       struct dw_mci_drv_data *drv_data = host->drv_data;
        int idx, ret;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -2062,8 +2066,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 
        of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
 
-       if (host->drv_data->parse_dt) {
-               ret = host->drv_data->parse_dt(host);
+       if (drv_data && drv_data->parse_dt) {
+               ret = drv_data->parse_dt(host);
                if (ret)
                        return ERR_PTR(ret);
        }
@@ -2080,6 +2084,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 
 int dw_mci_probe(struct dw_mci *host)
 {
+       struct dw_mci_drv_data *drv_data = host->drv_data;
        int width, i, ret = 0;
        u32 fifo_size;
        int init_slots = 0;
@@ -2127,8 +2132,8 @@ int dw_mci_probe(struct dw_mci *host)
        else
                host->bus_hz = clk_get_rate(host->ciu_clk);
 
-       if (host->drv_data->setup_clock) {
-               ret = host->drv_data->setup_clock(host);
+       if (drv_data && drv_data->setup_clock) {
+               ret = drv_data->setup_clock(host);
                if (ret) {
                        dev_err(host->dev,
                                "implementation specific clock setup failed\n");
@@ -2228,6 +2233,21 @@ int dw_mci_probe(struct dw_mci *host)
        else
                host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
 
+       /*
+        * Enable interrupts for command done, data over, data empty, card det,
+        * receive ready and error such as transmit, receive timeout, crc error
+        */
+       mci_writel(host, RINTSTS, 0xFFFFFFFF);
+       mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
+                  SDMMC_INT_TXDR | SDMMC_INT_RXDR |
+                  DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
+       mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
+
+       dev_info(host->dev, "DW MMC controller at irq %d, "
+                "%d bit host data width, "
+                "%u deep fifo\n",
+                host->irq, width, fifo_size);
+
        /* We need at least one slot to succeed */
        for (i = 0; i < host->num_slots; i++) {
                ret = dw_mci_init_slot(host, i);
@@ -2257,20 +2277,6 @@ int dw_mci_probe(struct dw_mci *host)
        else
                host->data_offset = DATA_240A_OFFSET;
 
-       /*
-        * Enable interrupts for command done, data over, data empty, card det,
-        * receive ready and error such as transmit, receive timeout, crc error
-        */
-       mci_writel(host, RINTSTS, 0xFFFFFFFF);
-       mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
-                  SDMMC_INT_TXDR | SDMMC_INT_RXDR |
-                  DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
-       mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
-
-       dev_info(host->dev, "DW MMC controller at irq %d, "
-                "%d bit host data width, "
-                "%u deep fifo\n",
-                host->irq, width, fifo_size);
        if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
                dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
 
index 565c2e4..6290b7f 100644 (file)
@@ -1134,4 +1134,4 @@ module_platform_driver(mxcmci_driver);
 MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");
 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-mmc");
+MODULE_ALIAS("platform:mxc-mmc");
index 54bfd0c..fedd258 100644 (file)
@@ -178,7 +178,8 @@ struct omap_hsmmc_host {
 
 static int omap_hsmmc_card_detect(struct device *dev, int slot)
 {
-       struct omap_mmc_platform_data *mmc = dev->platform_data;
+       struct omap_hsmmc_host *host = dev_get_drvdata(dev);
+       struct omap_mmc_platform_data *mmc = host->pdata;
 
        /* NOTE: assumes card detect signal is active-low */
        return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
@@ -186,7 +187,8 @@ static int omap_hsmmc_card_detect(struct device *dev, int slot)
 
 static int omap_hsmmc_get_wp(struct device *dev, int slot)
 {
-       struct omap_mmc_platform_data *mmc = dev->platform_data;
+       struct omap_hsmmc_host *host = dev_get_drvdata(dev);
+       struct omap_mmc_platform_data *mmc = host->pdata;
 
        /* NOTE: assumes write protect signal is active-high */
        return gpio_get_value_cansleep(mmc->slots[0].gpio_wp);
@@ -194,7 +196,8 @@ static int omap_hsmmc_get_wp(struct device *dev, int slot)
 
 static int omap_hsmmc_get_cover_state(struct device *dev, int slot)
 {
-       struct omap_mmc_platform_data *mmc = dev->platform_data;
+       struct omap_hsmmc_host *host = dev_get_drvdata(dev);
+       struct omap_mmc_platform_data *mmc = host->pdata;
 
        /* NOTE: assumes card detect signal is active-low */
        return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
@@ -204,7 +207,8 @@ static int omap_hsmmc_get_cover_state(struct device *dev, int slot)
 
 static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot)
 {
-       struct omap_mmc_platform_data *mmc = dev->platform_data;
+       struct omap_hsmmc_host *host = dev_get_drvdata(dev);
+       struct omap_mmc_platform_data *mmc = host->pdata;
 
        disable_irq(mmc->slots[0].card_detect_irq);
        return 0;
@@ -212,7 +216,8 @@ static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot)
 
 static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)
 {
-       struct omap_mmc_platform_data *mmc = dev->platform_data;
+       struct omap_hsmmc_host *host = dev_get_drvdata(dev);
+       struct omap_mmc_platform_data *mmc = host->pdata;
 
        enable_irq(mmc->slots[0].card_detect_irq);
        return 0;
@@ -2009,9 +2014,9 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev)
                clk_put(host->dbclk);
        }
 
-       mmc_free_host(host->mmc);
+       omap_hsmmc_gpio_free(host->pdata);
        iounmap(host->base);
-       omap_hsmmc_gpio_free(pdev->dev.platform_data);
+       mmc_free_host(host->mmc);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res)
index 90140eb..8fd50a2 100644 (file)
@@ -19,6 +19,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/err.h>
@@ -84,30 +85,32 @@ static int __devinit sdhci_dove_probe(struct platform_device *pdev)
        struct sdhci_dove_priv *priv;
        int ret;
 
-       ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
-       if (ret)
-               goto sdhci_dove_register_fail;
-
        priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_dove_priv),
                            GFP_KERNEL);
        if (!priv) {
                dev_err(&pdev->dev, "unable to allocate private data");
-               ret = -ENOMEM;
-               goto sdhci_dove_allocate_fail;
+               return -ENOMEM;
        }
 
+       priv->clk = clk_get(&pdev->dev, NULL);
+       if (!IS_ERR(priv->clk))
+               clk_prepare_enable(priv->clk);
+
+       ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
+       if (ret)
+               goto sdhci_dove_register_fail;
+
        host = platform_get_drvdata(pdev);
        pltfm_host = sdhci_priv(host);
        pltfm_host->priv = priv;
 
-       priv->clk = clk_get(&pdev->dev, NULL);
-       if (!IS_ERR(priv->clk))
-               clk_prepare_enable(priv->clk);
        return 0;
 
-sdhci_dove_allocate_fail:
-       sdhci_pltfm_unregister(pdev);
 sdhci_dove_register_fail:
+       if (!IS_ERR(priv->clk)) {
+               clk_disable_unprepare(priv->clk);
+               clk_put(priv->clk);
+       }
        return ret;
 }
 
@@ -117,14 +120,13 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev)
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_dove_priv *priv = pltfm_host->priv;
 
-       if (priv->clk) {
-               if (!IS_ERR(priv->clk)) {
-                       clk_disable_unprepare(priv->clk);
-                       clk_put(priv->clk);
-               }
-               devm_kfree(&pdev->dev, priv->clk);
+       sdhci_pltfm_unregister(pdev);
+
+       if (!IS_ERR(priv->clk)) {
+               clk_disable_unprepare(priv->clk);
+               clk_put(priv->clk);
        }
-       return sdhci_pltfm_unregister(pdev);
+       return 0;
 }
 
 static const struct of_device_id sdhci_dove_of_match_table[] __devinitdata = {
index ae5fcbf..63d219f 100644 (file)
@@ -169,6 +169,16 @@ static void esdhc_of_resume(struct sdhci_host *host)
 }
 #endif
 
+static void esdhc_of_platform_init(struct sdhci_host *host)
+{
+       u32 vvn;
+
+       vvn = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
+       vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
+       if (vvn == VENDOR_V_22)
+               host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
+}
+
 static struct sdhci_ops sdhci_esdhc_ops = {
        .read_l = esdhc_readl,
        .read_w = esdhc_readw,
@@ -180,6 +190,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
        .enable_dma = esdhc_of_enable_dma,
        .get_max_clock = esdhc_of_get_max_clock,
        .get_min_clock = esdhc_of_get_min_clock,
+       .platform_init = esdhc_of_platform_init,
 #ifdef CONFIG_PM
        .platform_suspend = esdhc_of_suspend,
        .platform_resume = esdhc_of_resume,
index 4bb74b0..04936f3 100644 (file)
@@ -1196,7 +1196,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
                return ERR_PTR(-ENODEV);
        }
 
-       if (pci_resource_len(pdev, bar) != 0x100) {
+       if (pci_resource_len(pdev, bar) < 0x100) {
                dev_err(&pdev->dev, "Invalid iomem size. You may "
                        "experience problems.\n");
        }
index 65551a9..2716445 100644 (file)
@@ -150,6 +150,13 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
                goto err_remap;
        }
 
+       /*
+        * Some platforms need to probe the controller to be able to
+        * determine which caps should be used.
+        */
+       if (host->ops && host->ops->platform_init)
+               host->ops->platform_init(host);
+
        platform_set_drvdata(pdev, host);
 
        return host;
index 2903949..a54dd5d 100644 (file)
@@ -211,8 +211,8 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
        if (ourhost->cur_clk != best_src) {
                struct clk *clk = ourhost->clk_bus[best_src];
 
-               clk_enable(clk);
-               clk_disable(ourhost->clk_bus[ourhost->cur_clk]);
+               clk_prepare_enable(clk);
+               clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]);
 
                /* turn clock off to card before changing clock source */
                writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
@@ -607,7 +607,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        }
 
        /* enable the local io clock and keep it running for the moment. */
-       clk_enable(sc->clk_io);
+       clk_prepare_enable(sc->clk_io);
 
        for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
                struct clk *clk;
@@ -638,7 +638,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        }
 
 #ifndef CONFIG_PM_RUNTIME
-       clk_enable(sc->clk_bus[sc->cur_clk]);
+       clk_prepare_enable(sc->clk_bus[sc->cur_clk]);
 #endif
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -747,13 +747,14 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
                sdhci_s3c_setup_card_detect_gpio(sc);
 
 #ifdef CONFIG_PM_RUNTIME
-       clk_disable(sc->clk_io);
+       if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
+               clk_disable_unprepare(sc->clk_io);
 #endif
        return 0;
 
  err_req_regs:
 #ifndef CONFIG_PM_RUNTIME
-       clk_disable(sc->clk_bus[sc->cur_clk]);
+       clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);
 #endif
        for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
                if (sc->clk_bus[ptr]) {
@@ -762,7 +763,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        }
 
  err_no_busclks:
-       clk_disable(sc->clk_io);
+       clk_disable_unprepare(sc->clk_io);
        clk_put(sc->clk_io);
 
  err_io_clk:
@@ -794,7 +795,8 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
                gpio_free(sc->ext_cd_gpio);
 
 #ifdef CONFIG_PM_RUNTIME
-       clk_enable(sc->clk_io);
+       if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
+               clk_prepare_enable(sc->clk_io);
 #endif
        sdhci_remove_host(host, 1);
 
@@ -802,14 +804,14 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
 
 #ifndef CONFIG_PM_RUNTIME
-       clk_disable(sc->clk_bus[sc->cur_clk]);
+       clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);
 #endif
        for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
                if (sc->clk_bus[ptr]) {
                        clk_put(sc->clk_bus[ptr]);
                }
        }
-       clk_disable(sc->clk_io);
+       clk_disable_unprepare(sc->clk_io);
        clk_put(sc->clk_io);
 
        if (pdev->dev.of_node) {
@@ -849,8 +851,8 @@ static int sdhci_s3c_runtime_suspend(struct device *dev)
 
        ret = sdhci_runtime_suspend_host(host);
 
-       clk_disable(ourhost->clk_bus[ourhost->cur_clk]);
-       clk_disable(busclk);
+       clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]);
+       clk_disable_unprepare(busclk);
        return ret;
 }
 
@@ -861,8 +863,8 @@ static int sdhci_s3c_runtime_resume(struct device *dev)
        struct clk *busclk = ourhost->clk_io;
        int ret;
 
-       clk_enable(busclk);
-       clk_enable(ourhost->clk_bus[ourhost->cur_clk]);
+       clk_prepare_enable(busclk);
+       clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]);
        ret = sdhci_runtime_resume_host(host);
        return ret;
 }
index 7922adb..c7851c0 100644 (file)
@@ -1315,16 +1315,19 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
                 */
                if ((host->flags & SDHCI_NEEDS_RETUNING) &&
                    !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
-                       /* eMMC uses cmd21 while sd and sdio use cmd19 */
-                       tuning_opcode = mmc->card->type == MMC_TYPE_MMC ?
-                               MMC_SEND_TUNING_BLOCK_HS200 :
-                               MMC_SEND_TUNING_BLOCK;
-                       spin_unlock_irqrestore(&host->lock, flags);
-                       sdhci_execute_tuning(mmc, tuning_opcode);
-                       spin_lock_irqsave(&host->lock, flags);
-
-                       /* Restore original mmc_request structure */
-                       host->mrq = mrq;
+                       if (mmc->card) {
+                               /* eMMC uses cmd21 but sd and sdio use cmd19 */
+                               tuning_opcode =
+                                       mmc->card->type == MMC_TYPE_MMC ?
+                                       MMC_SEND_TUNING_BLOCK_HS200 :
+                                       MMC_SEND_TUNING_BLOCK;
+                               spin_unlock_irqrestore(&host->lock, flags);
+                               sdhci_execute_tuning(mmc, tuning_opcode);
+                               spin_lock_irqsave(&host->lock, flags);
+
+                               /* Restore original mmc_request structure */
+                               host->mrq = mrq;
+                       }
                }
 
                if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
@@ -2837,6 +2840,9 @@ int sdhci_add_host(struct sdhci_host *host)
        if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
                mmc->caps |= MMC_CAP_4_BIT_DATA;
 
+       if (host->quirks2 & SDHCI_QUIRK2_HOST_NO_CMD23)
+               mmc->caps &= ~MMC_CAP_CMD23;
+
        if (caps[0] & SDHCI_CAN_DO_HISPD)
                mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
@@ -2846,9 +2852,12 @@ int sdhci_add_host(struct sdhci_host *host)
 
        /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
        host->vqmmc = regulator_get(mmc_dev(mmc), "vqmmc");
-       if (IS_ERR(host->vqmmc)) {
-               pr_info("%s: no vqmmc regulator found\n", mmc_hostname(mmc));
-               host->vqmmc = NULL;
+       if (IS_ERR_OR_NULL(host->vqmmc)) {
+               if (PTR_ERR(host->vqmmc) < 0) {
+                       pr_info("%s: no vqmmc regulator found\n",
+                               mmc_hostname(mmc));
+                       host->vqmmc = NULL;
+               }
        }
        else if (regulator_is_supported_voltage(host->vqmmc, 1800000, 1800000))
                regulator_enable(host->vqmmc);
@@ -2904,9 +2913,12 @@ int sdhci_add_host(struct sdhci_host *host)
        ocr_avail = 0;
 
        host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
-       if (IS_ERR(host->vmmc)) {
-               pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
-               host->vmmc = NULL;
+       if (IS_ERR_OR_NULL(host->vmmc)) {
+               if (PTR_ERR(host->vmmc) < 0) {
+                       pr_info("%s: no vmmc regulator found\n",
+                               mmc_hostname(mmc));
+                       host->vmmc = NULL;
+               }
        } else
                regulator_enable(host->vmmc);
 
index 97653ea..71a4a7e 100644 (file)
@@ -278,6 +278,7 @@ struct sdhci_ops {
        void    (*hw_reset)(struct sdhci_host *host);
        void    (*platform_suspend)(struct sdhci_host *host);
        void    (*platform_resume)(struct sdhci_host *host);
+       void    (*platform_init)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
index 11d2bc3..d25bc97 100644 (file)
@@ -1466,9 +1466,9 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, NULL);
 
+       clk_disable(host->hclk);
        mmc_free_host(host->mmc);
        pm_runtime_put_sync(&pdev->dev);
-       clk_disable(host->hclk);
        pm_runtime_disable(&pdev->dev);
 
        return 0;
index 9144557..92623ac 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/gpio.h>
 #include <linux/io.h>
 #include <linux/platform_data/atmel.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <mach/cpu.h>
 
@@ -1370,6 +1371,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        struct resource *mem;
        struct mtd_part_parser_data ppdata = {};
        int res;
+       struct pinctrl *pinctrl;
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem) {
@@ -1414,6 +1416,13 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        nand_chip->IO_ADDR_W = host->io_base;
        nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl)) {
+               dev_err(host->dev, "Failed to request pinctrl\n");
+               res = PTR_ERR(pinctrl);
+               goto err_ecc_ioremap;
+       }
+
        if (gpio_is_valid(host->board.rdy_pin)) {
                res = gpio_request(host->board.rdy_pin, "nand_rdy");
                if (res < 0) {
index dc15d24..ef8d2a0 100644 (file)
@@ -1060,7 +1060,7 @@ static ssize_t bonding_store_primary(struct device *d,
                goto out;
        }
 
-       sscanf(buf, "%16s", ifname); /* IFNAMSIZ */
+       sscanf(buf, "%15s", ifname); /* IFNAMSIZ */
 
        /* check to see if we are clearing primary */
        if (!strlen(ifname) || buf[0] == '\n') {
@@ -1237,7 +1237,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
                goto out;
        }
 
-       sscanf(buf, "%16s", ifname); /* IFNAMSIZ */
+       sscanf(buf, "%15s", ifname); /* IFNAMSIZ */
 
        /* check to see if we are clearing active */
        if (!strlen(ifname) || buf[0] == '\n') {
index c65295d..6e5bdd1 100644 (file)
@@ -1702,7 +1702,7 @@ static int bnx2x_set_eee(struct net_device *dev, struct ethtool_eee *edata)
                                      SHMEM_EEE_ADV_STATUS_SHIFT);
        if ((advertised != (eee_cfg & SHMEM_EEE_ADV_STATUS_MASK))) {
                DP(BNX2X_MSG_ETHTOOL,
-                  "Direct manipulation of EEE advertisment is not supported\n");
+                  "Direct manipulation of EEE advertisement is not supported\n");
                return -EINVAL;
        }
 
index e2e45ee..f6cfdc6 100644 (file)
 #define LINK_20GTFD            LINK_STATUS_SPEED_AND_DUPLEX_20GTFD
 #define LINK_20GXFD            LINK_STATUS_SPEED_AND_DUPLEX_20GXFD
 
-
+#define LINK_UPDATE_MASK \
+                       (LINK_STATUS_SPEED_AND_DUPLEX_MASK | \
+                        LINK_STATUS_LINK_UP | \
+                        LINK_STATUS_PHYSICAL_LINK_FLAG | \
+                        LINK_STATUS_AUTO_NEGOTIATE_COMPLETE | \
+                        LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK | \
+                        LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK | \
+                        LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK | \
+                        LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE | \
+                        LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE)
 
 #define SFP_EEPROM_CON_TYPE_ADDR               0x2
        #define SFP_EEPROM_CON_TYPE_VAL_LC      0x7
@@ -3295,6 +3304,21 @@ static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
               DEFAULT_PHY_DEV_ADDR);
 }
 
+static void bnx2x_xgxs_specific_func(struct bnx2x_phy *phy,
+                                    struct link_params *params,
+                                    u32 action)
+{
+       struct bnx2x *bp = params->bp;
+       switch (action) {
+       case PHY_INIT:
+               /* Set correct devad */
+               REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + params->port*0x18, 0);
+               REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
+                      phy->def_md_devad);
+               break;
+       }
+}
+
 static void bnx2x_xgxs_deassert(struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
@@ -3309,10 +3333,8 @@ static void bnx2x_xgxs_deassert(struct link_params *params)
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
        udelay(500);
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
-
-       REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 0);
-       REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
-              params->phy[INT_PHY].def_md_devad);
+       bnx2x_xgxs_specific_func(&params->phy[INT_PHY], params,
+                                PHY_INIT);
 }
 
 static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
@@ -3545,14 +3567,11 @@ static void bnx2x_warpcore_set_lpi_passthrough(struct bnx2x_phy *phy,
 static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
                                        struct link_params *params,
                                        struct link_vars *vars) {
-       u16 val16 = 0, lane, i;
+       u16 lane, i, cl72_ctrl, an_adv = 0;
+       u16 ucode_ver;
        struct bnx2x *bp = params->bp;
        static struct bnx2x_reg_set reg_set[] = {
                {MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7},
-               {MDIO_AN_DEVAD, MDIO_WC_REG_PAR_DET_10G_CTRL, 0},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0xff},
-               {MDIO_WC_DEVAD, MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0x5555},
                {MDIO_PMA_DEVAD, MDIO_WC_REG_IEEE0BLK_AUTONEGNP, 0x0},
                {MDIO_WC_DEVAD, MDIO_WC_REG_RX66_CONTROL, 0x7415},
                {MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_MISC2, 0x6190},
@@ -3565,12 +3584,19 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
                bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
                                 reg_set[i].val);
 
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+               MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, &cl72_ctrl);
+       cl72_ctrl &= 0xf8ff;
+       cl72_ctrl |= 0x3800;
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+               MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, cl72_ctrl);
+
        /* Check adding advertisement for 1G KX */
        if (((vars->line_speed == SPEED_AUTO_NEG) &&
             (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
            (vars->line_speed == SPEED_1000)) {
                u32 addr = MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2;
-               val16 |= (1<<5);
+               an_adv |= (1<<5);
 
                /* Enable CL37 1G Parallel Detect */
                bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD, addr, 0x1);
@@ -3580,11 +3606,14 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
             (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
            (vars->line_speed ==  SPEED_10000)) {
                /* Check adding advertisement for 10G KR */
-               val16 |= (1<<7);
+               an_adv |= (1<<7);
                /* Enable 10G Parallel Detect */
+               CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
+                                 MDIO_AER_BLOCK_AER_REG, 0);
+
                bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
                                 MDIO_WC_REG_PAR_DET_10G_CTRL, 1);
-
+               bnx2x_set_aer_mmd(params, phy);
                DP(NETIF_MSG_LINK, "Advertize 10G\n");
        }
 
@@ -3604,7 +3633,7 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
 
        /* Advertised speeds */
        bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
-                        MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, val16);
+                        MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, an_adv);
 
        /* Advertised and set FEC (Forward Error Correction) */
        bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
@@ -3628,9 +3657,10 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
        /* Set KR Autoneg Work-Around flag for Warpcore version older than D108
         */
        bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
-                       MDIO_WC_REG_UC_INFO_B1_VERSION, &val16);
-       if (val16 < 0xd108) {
-               DP(NETIF_MSG_LINK, "Enable AN KR work-around\n");
+                       MDIO_WC_REG_UC_INFO_B1_VERSION, &ucode_ver);
+       if (ucode_ver < 0xd108) {
+               DP(NETIF_MSG_LINK, "Enable AN KR work-around. WC ver:0x%x\n",
+                              ucode_ver);
                vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
        }
        bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
@@ -3651,21 +3681,16 @@ static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy,
                                      struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
-       u16 i;
+       u16 val16, i, lane;
        static struct bnx2x_reg_set reg_set[] = {
                /* Disable Autoneg */
                {MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7},
-               {MDIO_AN_DEVAD, MDIO_WC_REG_PAR_DET_10G_CTRL, 0},
                {MDIO_WC_DEVAD, MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
                        0x3f00},
                {MDIO_AN_DEVAD, MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, 0},
                {MDIO_AN_DEVAD, MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0},
                {MDIO_WC_DEVAD, MDIO_WC_REG_DIGITAL3_UP1, 0x1},
                {MDIO_WC_DEVAD, MDIO_WC_REG_DIGITAL5_MISC7, 0xa},
-               /* Disable CL36 PCS Tx */
-               {MDIO_WC_DEVAD, MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0x0},
-               /* Double Wide Single Data Rate @ pll rate */
-               {MDIO_WC_DEVAD, MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0xFFFF},
                /* Leave cl72 training enable, needed for KR */
                {MDIO_PMA_DEVAD,
                MDIO_WC_REG_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150,
@@ -3676,11 +3701,24 @@ static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy,
                bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
                                 reg_set[i].val);
 
-       /* Leave CL72 enabled */
-       bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
-                                MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
-                                0x3800);
+       lane = bnx2x_get_warpcore_lane(phy, params);
+       /* Global registers */
+       CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
+                         MDIO_AER_BLOCK_AER_REG, 0);
+       /* Disable CL36 PCS Tx */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_XGXSBLK1_LANECTRL0, &val16);
+       val16 &= ~(0x0011 << lane);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_XGXSBLK1_LANECTRL0, val16);
 
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_XGXSBLK1_LANECTRL1, &val16);
+       val16 |= (0x0303 << (lane << 1));
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_XGXSBLK1_LANECTRL1, val16);
+       /* Restore AER */
+       bnx2x_set_aer_mmd(params, phy);
        /* Set speed via PMA/PMD register */
        bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
                         MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040);
@@ -4303,7 +4341,7 @@ static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy,
                                      struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
-       u16 val16;
+       u16 val16, lane;
        bnx2x_sfp_e3_set_transmitter(params, phy, 0);
        bnx2x_set_mdio_clk(bp, params->chip_id, params->port);
        bnx2x_set_aer_mmd(params, phy);
@@ -4340,6 +4378,30 @@ static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy,
                         MDIO_WC_REG_XGXSBLK1_LANECTRL2,
                         val16 & 0xff00);
 
+       lane = bnx2x_get_warpcore_lane(phy, params);
+       /* Disable CL36 PCS Tx */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_XGXSBLK1_LANECTRL0, &val16);
+       val16 |= (0x11 << lane);
+       if (phy->flags & FLAGS_WC_DUAL_MODE)
+               val16 |= (0x22 << lane);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_XGXSBLK1_LANECTRL0, val16);
+
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_XGXSBLK1_LANECTRL1, &val16);
+       val16 &= ~(0x0303 << (lane << 1));
+       val16 |= (0x0101 << (lane << 1));
+       if (phy->flags & FLAGS_WC_DUAL_MODE) {
+               val16 &= ~(0x0c0c << (lane << 1));
+               val16 |= (0x0404 << (lane << 1));
+       }
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_XGXSBLK1_LANECTRL1, val16);
+       /* Restore AER */
+       bnx2x_set_aer_mmd(params, phy);
+
 }
 
 static void bnx2x_set_warpcore_loopback(struct bnx2x_phy *phy,
@@ -6296,15 +6358,7 @@ static int bnx2x_update_link_down(struct link_params *params,
        vars->mac_type = MAC_TYPE_NONE;
 
        /* Update shared memory */
-       vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK |
-                              LINK_STATUS_LINK_UP |
-                              LINK_STATUS_PHYSICAL_LINK_FLAG |
-                              LINK_STATUS_AUTO_NEGOTIATE_COMPLETE |
-                              LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK |
-                              LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK |
-                              LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK |
-                              LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE |
-                              LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE);
+       vars->link_status &= ~LINK_UPDATE_MASK;
        vars->line_speed = 0;
        bnx2x_update_mng(params, vars->link_status);
 
@@ -6452,6 +6506,7 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
        u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
        u8 active_external_phy = INT_PHY;
        vars->phy_flags &= ~PHY_HALF_OPEN_CONN_FLAG;
+       vars->link_status &= ~LINK_UPDATE_MASK;
        for (phy_index = INT_PHY; phy_index < params->num_phys;
              phy_index++) {
                phy_vars[phy_index].flow_ctrl = 0;
@@ -7579,7 +7634,7 @@ static void bnx2x_warpcore_power_module(struct link_params *params,
 static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
                                                 struct link_params *params,
                                                 u16 addr, u8 byte_cnt,
-                                                u8 *o_buf)
+                                                u8 *o_buf, u8 is_init)
 {
        int rc = 0;
        u8 i, j = 0, cnt = 0;
@@ -7596,10 +7651,10 @@ static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
        /* 4 byte aligned address */
        addr32 = addr & (~0x3);
        do {
-               if (cnt == I2C_WA_PWR_ITER) {
+               if ((!is_init) && (cnt == I2C_WA_PWR_ITER)) {
                        bnx2x_warpcore_power_module(params, phy, 0);
                        /* Note that 100us are not enough here */
-                       usleep_range(1000,1000);
+                       usleep_range(1000, 2000);
                        bnx2x_warpcore_power_module(params, phy, 1);
                }
                rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt,
@@ -7719,7 +7774,7 @@ int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
        break;
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
                rc = bnx2x_warpcore_read_sfp_module_eeprom(phy, params, addr,
-                                                          byte_cnt, o_buf);
+                                                          byte_cnt, o_buf, 0);
        break;
        }
        return rc;
@@ -7923,6 +7978,7 @@ static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
 
 {
        u8 val;
+       int rc;
        struct bnx2x *bp = params->bp;
        u16 timeout;
        /* Initialization time after hot-plug may take up to 300ms for
@@ -7930,8 +7986,14 @@ static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
         */
 
        for (timeout = 0; timeout < 60; timeout++) {
-               if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
-                   == 0) {
+               if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
+                       rc = bnx2x_warpcore_read_sfp_module_eeprom(phy,
+                                                                  params, 1,
+                                                                  1, &val, 1);
+               else
+                       rc = bnx2x_read_sfp_module_eeprom(phy, params, 1, 1,
+                                                         &val);
+               if (rc == 0) {
                        DP(NETIF_MSG_LINK,
                           "SFP+ module initialization took %d ms\n",
                           timeout * 5);
@@ -7939,7 +8001,8 @@ static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
                }
                usleep_range(5000, 10000);
        }
-       return -EINVAL;
+       rc = bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val);
+       return rc;
 }
 
 static void bnx2x_8727_power_module(struct bnx2x *bp,
@@ -9878,7 +9941,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
                else
                        rc = bnx2x_8483x_disable_eee(phy, params, vars);
                if (rc) {
-                       DP(NETIF_MSG_LINK, "Failed to set EEE advertisment\n");
+                       DP(NETIF_MSG_LINK, "Failed to set EEE advertisement\n");
                        return rc;
                }
        } else {
@@ -10993,7 +11056,7 @@ static struct bnx2x_phy phy_xgxs = {
        .format_fw_ver  = (format_fw_ver_t)NULL,
        .hw_reset       = (hw_reset_t)NULL,
        .set_link_led   = (set_link_led_t)NULL,
-       .phy_specific_func = (phy_specific_func_t)NULL
+       .phy_specific_func = (phy_specific_func_t)bnx2x_xgxs_specific_func
 };
 static struct bnx2x_phy phy_warpcore = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
@@ -11465,6 +11528,11 @@ static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
                        phy->media_type = ETH_PHY_BASE_T;
                        break;
                case PORT_HW_CFG_NET_SERDES_IF_XFI:
+                       phy->supported &= (SUPPORTED_1000baseT_Full |
+                                          SUPPORTED_10000baseT_Full |
+                                          SUPPORTED_FIBRE |
+                                          SUPPORTED_Pause |
+                                          SUPPORTED_Asym_Pause);
                        phy->media_type = ETH_PHY_XFP_FIBER;
                        break;
                case PORT_HW_CFG_NET_SERDES_IF_SFI:
@@ -12919,7 +12987,7 @@ static u8 bnx2x_analyze_link_error(struct link_params *params,
                DP(NETIF_MSG_LINK, "Analyze TX Fault\n");
                break;
        default:
-               DP(NETIF_MSG_LINK, "Analyze UNKOWN\n");
+               DP(NETIF_MSG_LINK, "Analyze UNKNOWN\n");
        }
        DP(NETIF_MSG_LINK, "Link changed:[%x %x]->%x\n", vars->link_up,
           old_status, status);
index d5648fc..bd1fd3d 100644 (file)
@@ -6794,8 +6794,9 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
 
        bnx2x_init_block(bp, BLOCK_DORQ, init_phase);
 
+       bnx2x_init_block(bp, BLOCK_BRB1, init_phase);
+
        if (CHIP_IS_E1(bp) || CHIP_IS_E1H(bp)) {
-               bnx2x_init_block(bp, BLOCK_BRB1, init_phase);
 
                if (IS_MF(bp))
                        low = ((bp->flags & ONE_PORT_FLAG) ? 160 : 246);
@@ -11902,7 +11903,15 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
        /* disable FCOE L2 queue for E1x */
        if (CHIP_IS_E1x(bp))
                bp->flags |= NO_FCOE_FLAG;
-
+       /* disable FCOE for 57840 device, until FW supports it */
+       switch (ent->driver_data) {
+       case BCM57840_O:
+       case BCM57840_4_10:
+       case BCM57840_2_20:
+       case BCM57840_MFO:
+       case BCM57840_MF:
+               bp->flags |= NO_FCOE_FLAG;
+       }
 #endif
 
 
index c1cde11..0df1284 100644 (file)
@@ -3416,16 +3416,6 @@ static int adap_init0_config(struct adapter *adapter, int reset)
                         finicsum, cfcsum);
 
        /*
-        * If we're a pure NIC driver then disable all offloading facilities.
-        * This will allow the firmware to optimize aspects of the hardware
-        * configuration which will result in improved performance.
-        */
-       caps_cmd.ofldcaps = 0;
-       caps_cmd.iscsicaps = 0;
-       caps_cmd.rdmacaps = 0;
-       caps_cmd.fcoecaps = 0;
-
-       /*
         * And now tell the firmware to use the configuration we just loaded.
         */
        caps_cmd.op_to_write =
index 32eec15..730ae2c 100644 (file)
@@ -2519,6 +2519,7 @@ int t4_fw_bye(struct adapter *adap, unsigned int mbox)
 {
        struct fw_bye_cmd c;
 
+       memset(&c, 0, sizeof(c));
        INIT_CMD(c, BYE, WRITE);
        return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
 }
@@ -2535,6 +2536,7 @@ int t4_early_init(struct adapter *adap, unsigned int mbox)
 {
        struct fw_initialize_cmd c;
 
+       memset(&c, 0, sizeof(c));
        INIT_CMD(c, INITIALIZE, WRITE);
        return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
 }
@@ -2551,6 +2553,7 @@ int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset)
 {
        struct fw_reset_cmd c;
 
+       memset(&c, 0, sizeof(c));
        INIT_CMD(c, RESET, WRITE);
        c.val = htonl(reset);
        return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
@@ -2828,7 +2831,7 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size,
                     HOSTPAGESIZEPF7(sge_hps));
 
        t4_set_reg_field(adap, SGE_CONTROL,
-                        INGPADBOUNDARY(INGPADBOUNDARY_MASK) |
+                        INGPADBOUNDARY_MASK |
                         EGRSTATUSPAGESIZE_MASK,
                         INGPADBOUNDARY(fl_align_log - 5) |
                         EGRSTATUSPAGESIZE(stat_len != 64));
@@ -3278,6 +3281,7 @@ int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid,
 {
        struct fw_vi_enable_cmd c;
 
+       memset(&c, 0, sizeof(c));
        c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST |
                             FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid));
        c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_LED | FW_LEN16(c));
index 1d03dcd..19ac096 100644 (file)
@@ -1353,8 +1353,11 @@ static int gfar_restore(struct device *dev)
        struct gfar_private *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->ndev;
 
-       if (!netif_running(ndev))
+       if (!netif_running(ndev)) {
+               netif_device_attach(ndev);
+
                return 0;
+       }
 
        gfar_init_bds(ndev);
        init_registers(ndev);
index 56b20d1..116f0e9 100644 (file)
@@ -2673,6 +2673,9 @@ static int ixgbe_get_ts_info(struct net_device *dev,
        case ixgbe_mac_X540:
        case ixgbe_mac_82599EB:
                info->so_timestamping =
+                       SOF_TIMESTAMPING_TX_SOFTWARE |
+                       SOF_TIMESTAMPING_RX_SOFTWARE |
+                       SOF_TIMESTAMPING_SOFTWARE |
                        SOF_TIMESTAMPING_TX_HARDWARE |
                        SOF_TIMESTAMPING_RX_HARDWARE |
                        SOF_TIMESTAMPING_RAW_HARDWARE;
index f8064df..92317e9 100644 (file)
@@ -1948,10 +1948,10 @@ jme_close(struct net_device *netdev)
 
        JME_NAPI_DISABLE(jme);
 
-       tasklet_disable(&jme->linkch_task);
-       tasklet_disable(&jme->txclean_task);
-       tasklet_disable(&jme->rxclean_task);
-       tasklet_disable(&jme->rxempty_task);
+       tasklet_kill(&jme->linkch_task);
+       tasklet_kill(&jme->txclean_task);
+       tasklet_kill(&jme->rxclean_task);
+       tasklet_kill(&jme->rxempty_task);
 
        jme_disable_rx_engine(jme);
        jme_disable_tx_engine(jme);
index 9b9c2ac..d19a143 100644 (file)
@@ -4026,7 +4026,7 @@ static void __devexit skge_remove(struct pci_dev *pdev)
        dev0 = hw->dev[0];
        unregister_netdev(dev0);
 
-       tasklet_disable(&hw->phy_task);
+       tasklet_kill(&hw->phy_task);
 
        spin_lock_irq(&hw->hw_lock);
        hw->intr_mask = 0;
index 318fee9..e558edd 100644 (file)
@@ -5407,8 +5407,8 @@ static int netdev_close(struct net_device *dev)
                /* Delay for receive task to stop scheduling itself. */
                msleep(2000 / HZ);
 
-               tasklet_disable(&hw_priv->rx_tasklet);
-               tasklet_disable(&hw_priv->tx_tasklet);
+               tasklet_kill(&hw_priv->rx_tasklet);
+               tasklet_kill(&hw_priv->tx_tasklet);
                free_irq(dev->irq, hw_priv->dev);
 
                transmit_cleanup(hw_priv, 0);
index 53743f7..af8b414 100644 (file)
@@ -1524,6 +1524,7 @@ static int lpc_eth_drv_remove(struct platform_device *pdev)
                                  pldat->dma_buff_base_p);
        free_irq(ndev->irq, ndev);
        iounmap(pldat->net_base);
+       mdiobus_unregister(pldat->mii_bus);
        mdiobus_free(pldat->mii_bus);
        clk_disable(pldat->clk);
        clk_put(pldat->clk);
index e7ff886..927aa33 100644 (file)
@@ -3827,6 +3827,8 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
        void __iomem *ioaddr = tp->mmio_addr;
 
        switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_25:
+       case RTL_GIGA_MAC_VER_26:
        case RTL_GIGA_MAC_VER_29:
        case RTL_GIGA_MAC_VER_30:
        case RTL_GIGA_MAC_VER_32:
@@ -4519,6 +4521,9 @@ static void rtl_set_rx_mode(struct net_device *dev)
                mc_filter[1] = swab32(data);
        }
 
+       if (tp->mac_version == RTL_GIGA_MAC_VER_35)
+               mc_filter[1] = mc_filter[0] = 0xffffffff;
+
        RTL_W32(MAR0 + 4, mc_filter[1]);
        RTL_W32(MAR0 + 0, mc_filter[0]);
 
index 0793299..1d04754 100644 (file)
@@ -990,7 +990,7 @@ static int axienet_stop(struct net_device *ndev)
        axienet_setoptions(ndev, lp->options &
                           ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
 
-       tasklet_disable(&lp->dma_err_tasklet);
+       tasklet_kill(&lp->dma_err_tasklet);
 
        free_irq(lp->tx_irq, ndev);
        free_irq(lp->rx_irq, ndev);
index daec9b0..6428fcb 100644 (file)
@@ -234,6 +234,7 @@ void free_mdio_bitbang(struct mii_bus *bus)
        struct mdiobb_ctrl *ctrl = bus->priv;
 
        module_put(ctrl->ops->owner);
+       mdiobus_unregister(bus);
        mdiobus_free(bus);
 }
 EXPORT_SYMBOL(free_mdio_bitbang);
index c81e278..08d55b6 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/usb/cdc.h>
 #include <linux/usb/usbnet.h>
 #include <linux/gfp.h>
+#include <linux/if_vlan.h>
 
 
 /*
@@ -92,7 +93,7 @@ static int eem_bind(struct usbnet *dev, struct usb_interface *intf)
 
        /* no jumbogram (16K) support for now */
 
-       dev->net->hard_header_len += EEM_HEAD + ETH_FCS_LEN;
+       dev->net->hard_header_len += EEM_HEAD + ETH_FCS_LEN + VLAN_HLEN;
        dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
 
        return 0;
index 7479a57..3286166 100644 (file)
@@ -1344,6 +1344,7 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
                } else {
                        u32 csum_preamble = smsc95xx_calc_csum_preamble(skb);
                        skb_push(skb, 4);
+                       cpu_to_le32s(&csum_preamble);
                        memcpy(skb->data, &csum_preamble, 4);
                }
        }
index cb04f90..edb81ed 100644 (file)
@@ -359,10 +359,12 @@ static enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb,
 void usbnet_defer_kevent (struct usbnet *dev, int work)
 {
        set_bit (work, &dev->flags);
-       if (!schedule_work (&dev->kevent))
-               netdev_err(dev->net, "kevent %d may have been dropped\n", work);
-       else
+       if (!schedule_work (&dev->kevent)) {
+               if (net_ratelimit())
+                       netdev_err(dev->net, "kevent %d may have been dropped\n", work);
+       } else {
                netdev_dbg(dev->net, "kevent %d scheduled\n", work);
+       }
 }
 EXPORT_SYMBOL_GPL(usbnet_defer_kevent);
 
index ce9d4f2..0ae1bcc 100644 (file)
@@ -744,28 +744,43 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
 
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+               u32 buf_size;
 
-               tbi = tq->buf_info + tq->tx_ring.next2fill;
-               tbi->map_type = VMXNET3_MAP_PAGE;
-               tbi->dma_addr = skb_frag_dma_map(&adapter->pdev->dev, frag,
-                                                0, skb_frag_size(frag),
-                                                DMA_TO_DEVICE);
+               buf_offset = 0;
+               len = skb_frag_size(frag);
+               while (len) {
+                       tbi = tq->buf_info + tq->tx_ring.next2fill;
+                       if (len < VMXNET3_MAX_TX_BUF_SIZE) {
+                               buf_size = len;
+                               dw2 |= len;
+                       } else {
+                               buf_size = VMXNET3_MAX_TX_BUF_SIZE;
+                               /* spec says that for TxDesc.len, 0 == 2^14 */
+                       }
+                       tbi->map_type = VMXNET3_MAP_PAGE;
+                       tbi->dma_addr = skb_frag_dma_map(&adapter->pdev->dev, frag,
+                                                        buf_offset, buf_size,
+                                                        DMA_TO_DEVICE);
 
-               tbi->len = skb_frag_size(frag);
+                       tbi->len = buf_size;
 
-               gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
-               BUG_ON(gdesc->txd.gen == tq->tx_ring.gen);
+                       gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
+                       BUG_ON(gdesc->txd.gen == tq->tx_ring.gen);
 
-               gdesc->txd.addr = cpu_to_le64(tbi->dma_addr);
-               gdesc->dword[2] = cpu_to_le32(dw2 | skb_frag_size(frag));
-               gdesc->dword[3] = 0;
+                       gdesc->txd.addr = cpu_to_le64(tbi->dma_addr);
+                       gdesc->dword[2] = cpu_to_le32(dw2);
+                       gdesc->dword[3] = 0;
 
-               dev_dbg(&adapter->netdev->dev,
-                       "txd[%u]: 0x%llu %u %u\n",
-                       tq->tx_ring.next2fill, le64_to_cpu(gdesc->txd.addr),
-                       le32_to_cpu(gdesc->dword[2]), gdesc->dword[3]);
-               vmxnet3_cmd_ring_adv_next2fill(&tq->tx_ring);
-               dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT;
+                       dev_dbg(&adapter->netdev->dev,
+                               "txd[%u]: 0x%llu %u %u\n",
+                               tq->tx_ring.next2fill, le64_to_cpu(gdesc->txd.addr),
+                               le32_to_cpu(gdesc->dword[2]), gdesc->dword[3]);
+                       vmxnet3_cmd_ring_adv_next2fill(&tq->tx_ring);
+                       dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT;
+
+                       len -= buf_size;
+                       buf_offset += buf_size;
+               }
        }
 
        ctx->eop_txd = gdesc;
@@ -886,6 +901,18 @@ vmxnet3_prepare_tso(struct sk_buff *skb,
        }
 }
 
+static int txd_estimate(const struct sk_buff *skb)
+{
+       int count = VMXNET3_TXD_NEEDED(skb_headlen(skb)) + 1;
+       int i;
+
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+
+               count += VMXNET3_TXD_NEEDED(skb_frag_size(frag));
+       }
+       return count;
+}
 
 /*
  * Transmits a pkt thru a given tq
@@ -914,9 +941,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
        union Vmxnet3_GenericDesc tempTxDesc;
 #endif
 
-       /* conservatively estimate # of descriptors to use */
-       count = VMXNET3_TXD_NEEDED(skb_headlen(skb)) +
-               skb_shinfo(skb)->nr_frags + 1;
+       count = txd_estimate(skb);
 
        ctx.ipv4 = (vlan_get_protocol(skb) == cpu_to_be16(ETH_P_IP));
 
index 607976c..7b4adde 100644 (file)
@@ -816,7 +816,7 @@ static void vxlan_cleanup(unsigned long arg)
                                = container_of(p, struct vxlan_fdb, hlist);
                        unsigned long timeout;
 
-                       if (f->state == NUD_PERMANENT)
+                       if (f->state & NUD_PERMANENT)
                                continue;
 
                        timeout = f->used + vxlan->age_interval * HZ;
index 378bd70..741918a 100644 (file)
@@ -312,6 +312,7 @@ static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
        }
 
        bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
+       bf->bf_next = NULL;
        list_del(&bf->list);
 
        spin_unlock_bh(&sc->tx.txbuflock);
@@ -393,7 +394,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0, seq_first;
        u32 ba[WME_BA_BMP_SIZE >> 5];
        int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
-       bool rc_update = true;
+       bool rc_update = true, isba;
        struct ieee80211_tx_rate rates[4];
        struct ath_frame_info *fi;
        int nframes;
@@ -437,13 +438,17 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
        tid = ATH_AN_2_TID(an, tidno);
        seq_first = tid->seq_start;
+       isba = ts->ts_flags & ATH9K_TX_BA;
 
        /*
         * The hardware occasionally sends a tx status for the wrong TID.
         * In this case, the BA status cannot be considered valid and all
         * subframes need to be retransmitted
+        *
+        * Only BlockAcks have a TID and therefore normal Acks cannot be
+        * checked
         */
-       if (tidno != ts->tid)
+       if (isba && tidno != ts->tid)
                txok = false;
 
        isaggr = bf_isaggr(bf);
@@ -1774,6 +1779,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
        list_add_tail(&bf->list, &bf_head);
        bf->bf_state.bf_type = 0;
 
+       bf->bf_next = NULL;
        bf->bf_lastbf = bf;
        ath_tx_fill_desc(sc, bf, txq, fi->framelen);
        ath_tx_txqaddbuf(sc, txq, &bf_head, false);
index 192251a..282eede 100644 (file)
@@ -382,7 +382,7 @@ static void cancel_transfers(struct b43legacy_pioqueue *queue)
 {
        struct b43legacy_pio_txpacket *packet, *tmp_packet;
 
-       tasklet_disable(&queue->txtask);
+       tasklet_kill(&queue->txtask);
 
        list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
                free_txpacket(packet, 0);
index 01dc889..59474ae 100644 (file)
@@ -2449,7 +2449,7 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev)
        /*
         * Check if temperature compensation is supported.
         */
-       if (tssi_bounds[4] == 0xff)
+       if (tssi_bounds[4] == 0xff || step == 0xff)
                return 0;
 
        /*
index 6241fd0..a543746 100644 (file)
@@ -320,10 +320,7 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
                } else
                        next = dev->bus_list.next;
 
-               /* Run device routines with the device locked */
-               device_lock(&dev->dev);
                retval = cb(dev, userdata);
-               device_unlock(&dev->dev);
                if (retval)
                        break;
        }
index 94c6e2a..6c94fc9 100644 (file)
@@ -398,6 +398,8 @@ static void pci_device_shutdown(struct device *dev)
        struct pci_dev *pci_dev = to_pci_dev(dev);
        struct pci_driver *drv = pci_dev->driver;
 
+       pm_runtime_resume(dev);
+
        if (drv && drv->shutdown)
                drv->shutdown(pci_dev);
        pci_msi_shutdown(pci_dev);
@@ -408,16 +410,6 @@ static void pci_device_shutdown(struct device *dev)
         * continue to do DMA
         */
        pci_disable_device(pci_dev);
-
-       /*
-        * Devices may be enabled to wake up by runtime PM, but they need not
-        * be supposed to wake up the system from its "power off" state (e.g.
-        * ACPI S5).  Therefore disable wakeup for all devices that aren't
-        * supposed to wake up the system at this point.  The state argument
-        * will be ignored by pci_enable_wake().
-        */
-       if (!device_may_wakeup(dev))
-               pci_enable_wake(pci_dev, PCI_UNKNOWN, false);
 }
 
 #ifdef CONFIG_PM
index 02d107b..f39378d 100644 (file)
@@ -458,40 +458,6 @@ boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 struct device_attribute vga_attr = __ATTR_RO(boot_vga);
 
-static void
-pci_config_pm_runtime_get(struct pci_dev *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct device *parent = dev->parent;
-
-       if (parent)
-               pm_runtime_get_sync(parent);
-       pm_runtime_get_noresume(dev);
-       /*
-        * pdev->current_state is set to PCI_D3cold during suspending,
-        * so wait until suspending completes
-        */
-       pm_runtime_barrier(dev);
-       /*
-        * Only need to resume devices in D3cold, because config
-        * registers are still accessible for devices suspended but
-        * not in D3cold.
-        */
-       if (pdev->current_state == PCI_D3cold)
-               pm_runtime_resume(dev);
-}
-
-static void
-pci_config_pm_runtime_put(struct pci_dev *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct device *parent = dev->parent;
-
-       pm_runtime_put(dev);
-       if (parent)
-               pm_runtime_put_sync(parent);
-}
-
 static ssize_t
 pci_read_config(struct file *filp, struct kobject *kobj,
                struct bin_attribute *bin_attr,
index 5485883..aabf647 100644 (file)
@@ -1858,6 +1858,38 @@ bool pci_dev_run_wake(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pci_dev_run_wake);
 
+void pci_config_pm_runtime_get(struct pci_dev *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device *parent = dev->parent;
+
+       if (parent)
+               pm_runtime_get_sync(parent);
+       pm_runtime_get_noresume(dev);
+       /*
+        * pdev->current_state is set to PCI_D3cold during suspending,
+        * so wait until suspending completes
+        */
+       pm_runtime_barrier(dev);
+       /*
+        * Only need to resume devices in D3cold, because config
+        * registers are still accessible for devices suspended but
+        * not in D3cold.
+        */
+       if (pdev->current_state == PCI_D3cold)
+               pm_runtime_resume(dev);
+}
+
+void pci_config_pm_runtime_put(struct pci_dev *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device *parent = dev->parent;
+
+       pm_runtime_put(dev);
+       if (parent)
+               pm_runtime_put_sync(parent);
+}
+
 /**
  * pci_pm_init - Initialize PM functions of given PCI device
  * @dev: PCI device to handle.
index bacbcba..fd92aab 100644 (file)
@@ -72,6 +72,8 @@ 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 platform_pci_wakeup_init(struct pci_dev *dev);
 extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
index 06bad96..af4e31c 100644 (file)
@@ -213,6 +213,7 @@ static int report_error_detected(struct pci_dev *dev, void *data)
        struct aer_broadcast_data *result_data;
        result_data = (struct aer_broadcast_data *) data;
 
+       device_lock(&dev->dev);
        dev->error_state = result_data->state;
 
        if (!dev->driver ||
@@ -231,12 +232,14 @@ static int report_error_detected(struct pci_dev *dev, void *data)
                                   dev->driver ?
                                   "no AER-aware driver" : "no driver");
                }
-               return 0;
+               goto out;
        }
 
        err_handler = dev->driver->err_handler;
        vote = err_handler->error_detected(dev, result_data->state);
        result_data->result = merge_result(result_data->result, vote);
+out:
+       device_unlock(&dev->dev);
        return 0;
 }
 
@@ -247,14 +250,17 @@ static int report_mmio_enabled(struct pci_dev *dev, void *data)
        struct aer_broadcast_data *result_data;
        result_data = (struct aer_broadcast_data *) data;
 
+       device_lock(&dev->dev);
        if (!dev->driver ||
                !dev->driver->err_handler ||
                !dev->driver->err_handler->mmio_enabled)
-               return 0;
+               goto out;
 
        err_handler = dev->driver->err_handler;
        vote = err_handler->mmio_enabled(dev);
        result_data->result = merge_result(result_data->result, vote);
+out:
+       device_unlock(&dev->dev);
        return 0;
 }
 
@@ -265,14 +271,17 @@ static int report_slot_reset(struct pci_dev *dev, void *data)
        struct aer_broadcast_data *result_data;
        result_data = (struct aer_broadcast_data *) data;
 
+       device_lock(&dev->dev);
        if (!dev->driver ||
                !dev->driver->err_handler ||
                !dev->driver->err_handler->slot_reset)
-               return 0;
+               goto out;
 
        err_handler = dev->driver->err_handler;
        vote = err_handler->slot_reset(dev);
        result_data->result = merge_result(result_data->result, vote);
+out:
+       device_unlock(&dev->dev);
        return 0;
 }
 
@@ -280,15 +289,18 @@ static int report_resume(struct pci_dev *dev, void *data)
 {
        const struct pci_error_handlers *err_handler;
 
+       device_lock(&dev->dev);
        dev->error_state = pci_channel_io_normal;
 
        if (!dev->driver ||
                !dev->driver->err_handler ||
                !dev->driver->err_handler->resume)
-               return 0;
+               goto out;
 
        err_handler = dev->driver->err_handler;
        err_handler->resume(dev);
+out:
+       device_unlock(&dev->dev);
        return 0;
 }
 
index d03a7a3..ed129b4 100644 (file)
@@ -272,7 +272,8 @@ static int get_port_device_capability(struct pci_dev *dev)
        }
 
        /* Hot-Plug Capable */
-       if (cap_mask & PCIE_PORT_SERVICE_HP) {
+       if ((cap_mask & PCIE_PORT_SERVICE_HP) &&
+           dev->pcie_flags_reg & PCI_EXP_FLAGS_SLOT) {
                pcie_capability_read_dword(dev, PCI_EXP_SLTCAP, &reg32);
                if (reg32 & PCI_EXP_SLTCAP_HPC) {
                        services |= PCIE_PORT_SERVICE_HP;
index eb907a8..9b8505c 100644 (file)
@@ -76,6 +76,8 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
        if (!access_ok(VERIFY_WRITE, buf, cnt))
                return -EINVAL;
 
+       pci_config_pm_runtime_get(dev);
+
        if ((pos & 1) && cnt) {
                unsigned char val;
                pci_user_read_config_byte(dev, pos, &val);
@@ -121,6 +123,8 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
                cnt--;
        }
 
+       pci_config_pm_runtime_put(dev);
+
        *ppos = pos;
        return nbytes;
 }
@@ -146,6 +150,8 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof
        if (!access_ok(VERIFY_READ, buf, cnt))
                return -EINVAL;
 
+       pci_config_pm_runtime_get(dev);
+
        if ((pos & 1) && cnt) {
                unsigned char val;
                __get_user(val, buf);
@@ -191,6 +197,8 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof
                cnt--;
        }
 
+       pci_config_pm_runtime_put(dev);
+
        *ppos = pos;
        i_size_write(ino, dp->size);
        return nbytes;
index 7bf914d..6d5a50b 100644 (file)
@@ -26,6 +26,15 @@ config DEBUG_PINCTRL
        help
          Say Y here to add some extra checks and diagnostics to PINCTRL calls.
 
+config PINCTRL_AT91
+       bool "AT91 pinctrl driver"
+       depends on OF
+       depends on ARCH_AT91
+       select PINMUX
+       select PINCONF
+       help
+         Say Y here to enable the at91 pinctrl driver
+
 config PINCTRL_BCM2835
        bool
        select PINMUX
@@ -143,8 +152,8 @@ config PINCTRL_SINGLE
          This selects the device tree based generic pinctrl driver.
 
 config PINCTRL_SIRF
-       bool "CSR SiRFprimaII pin controller driver"
-       depends on ARCH_PRIMA2
+       bool "CSR SiRFprimaII/SiRFmarco pin controller driver"
+       depends on ARCH_SIRF
        select PINMUX
 
 config PINCTRL_TEGRA
@@ -179,34 +188,16 @@ config PINCTRL_COH901
 
 config PINCTRL_SAMSUNG
        bool "Samsung pinctrl driver"
+       depends on OF && GPIOLIB
        select PINMUX
        select PINCONF
 
 config PINCTRL_EXYNOS4
        bool "Pinctrl driver data for Exynos4 SoC"
+       depends on OF && GPIOLIB
        select PINCTRL_SAMSUNG
 
-config PINCTRL_MVEBU
-       bool
-       depends on ARCH_MVEBU
-       select PINMUX
-       select PINCONF
-
-config PINCTRL_DOVE
-       bool
-       select PINCTRL_MVEBU
-
-config PINCTRL_KIRKWOOD
-       bool
-       select PINCTRL_MVEBU
-
-config PINCTRL_ARMADA_370
-       bool
-       select PINCTRL_MVEBU
-
-config PINCTRL_ARMADA_XP
-       bool
-       select PINCTRL_MVEBU
+source "drivers/pinctrl/mvebu/Kconfig"
 
 source "drivers/pinctrl/spear/Kconfig"
 
index f395ba5..f95f5ed 100644 (file)
@@ -9,6 +9,7 @@ ifeq ($(CONFIG_OF),y)
 obj-$(CONFIG_PINCTRL)          += devicetree.o
 endif
 obj-$(CONFIG_GENERIC_PINCONF)  += pinconf-generic.o
+obj-$(CONFIG_PINCTRL_AT91)     += pinctrl-at91.o
 obj-$(CONFIG_PINCTRL_BCM2835)  += pinctrl-bcm2835.o
 obj-$(CONFIG_PINCTRL_IMX)      += pinctrl-imx.o
 obj-$(CONFIG_PINCTRL_IMX35)    += pinctrl-imx35.o
@@ -36,12 +37,8 @@ obj-$(CONFIG_PINCTRL_U300)   += pinctrl-u300.o
 obj-$(CONFIG_PINCTRL_COH901)   += pinctrl-coh901.o
 obj-$(CONFIG_PINCTRL_SAMSUNG)  += pinctrl-samsung.o
 obj-$(CONFIG_PINCTRL_EXYNOS4)  += pinctrl-exynos.o
-obj-$(CONFIG_PINCTRL_MVEBU)    += pinctrl-mvebu.o
-obj-$(CONFIG_PINCTRL_DOVE)     += pinctrl-dove.o
-obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o
-obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
-obj-$(CONFIG_PINCTRL_ARMADA_XP)  += pinctrl-armada-xp.o
 obj-$(CONFIG_PINCTRL_XWAY)     += pinctrl-xway.o
 obj-$(CONFIG_PINCTRL_LANTIQ)   += pinctrl-lantiq.o
 
+obj-$(CONFIG_PLAT_ORION)        += mvebu/
 obj-$(CONFIG_PLAT_SPEAR)       += spear/
index 2e39c04..71db586 100644 (file)
@@ -345,6 +345,33 @@ void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
 }
 EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges);
 
+struct pinctrl_dev *find_pinctrl_and_add_gpio_range(const char *devname,
+               struct pinctrl_gpio_range *range)
+{
+       struct pinctrl_dev *pctldev = get_pinctrl_dev_from_devname(devname);
+
+       if (!pctldev)
+               return NULL;
+
+       pinctrl_add_gpio_range(pctldev, range);
+       return pctldev;
+}
+EXPORT_SYMBOL_GPL(find_pinctrl_and_add_gpio_range);
+
+/**
+ * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller
+ * @pctldev: pin controller device to remove the range from
+ * @range: the GPIO range to remove
+ */
+void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
+                              struct pinctrl_gpio_range *range)
+{
+       mutex_lock(&pinctrl_mutex);
+       list_del(&range->node);
+       mutex_unlock(&pinctrl_mutex);
+}
+EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
+
 /**
  * pinctrl_get_group_selector() - returns the group selector for a group
  * @pctldev: the pin controller handling the group
@@ -563,6 +590,8 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
                return -EPROBE_DEFER;
        }
 
+       setting->dev_name = map->dev_name;
+
        switch (map->type) {
        case PIN_MAP_TYPE_MUX_GROUP:
                ret = pinmux_map_to_setting(map, setting);
index 1f40ff6..12f5694 100644 (file)
@@ -105,12 +105,14 @@ struct pinctrl_setting_configs {
  * @type: the type of setting
  * @pctldev: pin control device handling to be programmed. Not used for
  *   PIN_MAP_TYPE_DUMMY_STATE.
+ * @dev_name: the name of the device using this state
  * @data: Data specific to the setting type
  */
 struct pinctrl_setting {
        struct list_head node;
        enum pinctrl_map_type type;
        struct pinctrl_dev *pctldev;
+       const char *dev_name;
        union {
                struct pinctrl_setting_mux mux;
                struct pinctrl_setting_configs configs;
index fcb1de4..fe2d1af 100644 (file)
@@ -106,6 +106,17 @@ static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
        return NULL;
 }
 
+struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
+{
+       struct pinctrl_dev *pctldev;
+
+       pctldev = find_pinctrl_by_of_node(np);
+       if (!pctldev)
+               return NULL;
+
+       return pctldev;
+}
+
 static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
                                struct device_node *np_config)
 {
diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig
new file mode 100644 (file)
index 0000000..366fa54
--- /dev/null
@@ -0,0 +1,24 @@
+if PLAT_ORION
+
+config PINCTRL_MVEBU
+       bool
+       select PINMUX
+       select PINCONF
+
+config PINCTRL_DOVE
+       bool
+       select PINCTRL_MVEBU
+
+config PINCTRL_KIRKWOOD
+       bool
+       select PINCTRL_MVEBU
+
+config PINCTRL_ARMADA_370
+       bool
+       select PINCTRL_MVEBU
+
+config PINCTRL_ARMADA_XP
+       bool
+       select PINCTRL_MVEBU
+
+endif
diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile
new file mode 100644 (file)
index 0000000..37c2532
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_PINCTRL_MVEBU)    += pinctrl-mvebu.o
+obj-$(CONFIG_PINCTRL_DOVE)     += pinctrl-dove.o
+obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o
+obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
+obj-$(CONFIG_PINCTRL_ARMADA_XP)  += pinctrl-armada-xp.o
similarity index 99%
rename from drivers/pinctrl/pinctrl-mvebu.c
rename to drivers/pinctrl/mvebu/pinctrl-mvebu.c
index 8e6266c..6c44b7e 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
 
-#include "core.h"
 #include "pinctrl-mvebu.h"
 
 #define MPPS_PER_REG   8
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
new file mode 100644 (file)
index 0000000..b9e2cbd
--- /dev/null
@@ -0,0 +1,1510 @@
+/*
+ * at91 pinctrl driver based on at91 pinmux core
+ *
+ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2 only
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+/* Since we request GPIOs from ourself */
+#include <linux/pinctrl/consumer.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/at91_pio.h>
+
+#include "core.h"
+
+#define MAX_NB_GPIO_PER_BANK   32
+
+struct at91_pinctrl_mux_ops;
+
+struct at91_gpio_chip {
+       struct gpio_chip        chip;
+       struct pinctrl_gpio_range range;
+       struct at91_gpio_chip   *next;          /* Bank sharing same clock */
+       int                     pioc_hwirq;     /* PIO bank interrupt identifier on AIC */
+       int                     pioc_virq;      /* PIO bank Linux virtual interrupt */
+       int                     pioc_idx;       /* PIO bank index */
+       void __iomem            *regbase;       /* PIO bank virtual address */
+       struct clk              *clock;         /* associated clock */
+       struct irq_domain       *domain;        /* associated irq domain */
+       struct at91_pinctrl_mux_ops *ops;       /* ops */
+};
+
+#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
+
+static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS];
+
+static int gpio_banks;
+
+#define PULL_UP                (1 << 0)
+#define MULTI_DRIVE    (1 << 1)
+
+/**
+ * struct at91_pmx_func - describes AT91 pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ * @ngroups: the number of groups
+ */
+struct at91_pmx_func {
+       const char      *name;
+       const char      **groups;
+       unsigned        ngroups;
+};
+
+enum at91_mux {
+       AT91_MUX_GPIO = 0,
+       AT91_MUX_PERIPH_A = 1,
+       AT91_MUX_PERIPH_B = 2,
+       AT91_MUX_PERIPH_C = 3,
+       AT91_MUX_PERIPH_D = 4,
+};
+
+/**
+ * struct at91_pmx_pin - describes an At91 pin mux
+ * @bank: the bank of the pin
+ * @pin: the pin number in the @bank
+ * @mux: the mux mode : gpio or periph_x of the pin i.e. alternate function.
+ * @conf: the configuration of the pin: PULL_UP, MULTIDRIVE etc...
+ */
+struct at91_pmx_pin {
+       uint32_t        bank;
+       uint32_t        pin;
+       enum at91_mux   mux;
+       unsigned long   conf;
+};
+
+/**
+ * struct at91_pin_group - describes an At91 pin group
+ * @name: the name of this specific pin group
+ * @pins_conf: the mux mode for each pin in this group. The size of this
+ *     array is the same as pins.
+ * @pins: an array of discrete physical pins used in this group, taken
+ *     from the driver-local pin enumeration space
+ * @npins: the number of pins in this group array, i.e. the number of
+ *     elements in .pins so we can iterate over that array
+ */
+struct at91_pin_group {
+       const char              *name;
+       struct at91_pmx_pin     *pins_conf;
+       unsigned int            *pins;
+       unsigned                npins;
+};
+
+/**
+ * struct at91_pinctrl_mux_ops - describes an At91 mux ops group
+ * on new IP with support for periph C and D the way to mux in
+ * periph A and B has changed
+ * So provide the right call back
+ * if not present means the IP does not support it
+ * @get_periph: return the periph mode configured
+ * @mux_A_periph: mux as periph A
+ * @mux_B_periph: mux as periph B
+ * @mux_C_periph: mux as periph C
+ * @mux_D_periph: mux as periph D
+ * @irq_type: return irq type
+ */
+struct at91_pinctrl_mux_ops {
+       enum at91_mux (*get_periph)(void __iomem *pio, unsigned mask);
+       void (*mux_A_periph)(void __iomem *pio, unsigned mask);
+       void (*mux_B_periph)(void __iomem *pio, unsigned mask);
+       void (*mux_C_periph)(void __iomem *pio, unsigned mask);
+       void (*mux_D_periph)(void __iomem *pio, unsigned mask);
+       /* irq */
+       int (*irq_type)(struct irq_data *d, unsigned type);
+};
+
+static int gpio_irq_type(struct irq_data *d, unsigned type);
+static int alt_gpio_irq_type(struct irq_data *d, unsigned type);
+
+struct at91_pinctrl {
+       struct device           *dev;
+       struct pinctrl_dev      *pctl;
+
+       int                     nbanks;
+
+       uint32_t                *mux_mask;
+       int                     nmux;
+
+       struct at91_pmx_func    *functions;
+       int                     nfunctions;
+
+       struct at91_pin_group   *groups;
+       int                     ngroups;
+
+       struct at91_pinctrl_mux_ops *ops;
+};
+
+static const inline struct at91_pin_group *at91_pinctrl_find_group_by_name(
+                               const struct at91_pinctrl *info,
+                               const char *name)
+{
+       const struct at91_pin_group *grp = NULL;
+       int i;
+
+       for (i = 0; i < info->ngroups; i++) {
+               if (strcmp(info->groups[i].name, name))
+                       continue;
+
+               grp = &info->groups[i];
+               dev_dbg(info->dev, "%s: %d 0:%d\n", name, grp->npins, grp->pins[0]);
+               break;
+       }
+
+       return grp;
+}
+
+static int at91_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->ngroups;
+}
+
+static const char *at91_get_group_name(struct pinctrl_dev *pctldev,
+                                      unsigned selector)
+{
+       struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->groups[selector].name;
+}
+
+static int at91_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+                              const unsigned **pins,
+                              unsigned *npins)
+{
+       struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       if (selector >= info->ngroups)
+               return -EINVAL;
+
+       *pins = info->groups[selector].pins;
+       *npins = info->groups[selector].npins;
+
+       return 0;
+}
+
+static void at91_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+                  unsigned offset)
+{
+       seq_printf(s, "%s", dev_name(pctldev->dev));
+}
+
+static int at91_dt_node_to_map(struct pinctrl_dev *pctldev,
+                       struct device_node *np,
+                       struct pinctrl_map **map, unsigned *num_maps)
+{
+       struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       const struct at91_pin_group *grp;
+       struct pinctrl_map *new_map;
+       struct device_node *parent;
+       int map_num = 1;
+       int i;
+
+       /*
+        * first find the group of this node and check if we need create
+        * config maps for pins
+        */
+       grp = at91_pinctrl_find_group_by_name(info, np->name);
+       if (!grp) {
+               dev_err(info->dev, "unable to find group for node %s\n",
+                       np->name);
+               return -EINVAL;
+       }
+
+       map_num += grp->npins;
+       new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num, GFP_KERNEL);
+       if (!new_map)
+               return -ENOMEM;
+
+       *map = new_map;
+       *num_maps = map_num;
+
+       /* create mux map */
+       parent = of_get_parent(np);
+       if (!parent) {
+               kfree(new_map);
+               return -EINVAL;
+       }
+       new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+       new_map[0].data.mux.function = parent->name;
+       new_map[0].data.mux.group = np->name;
+       of_node_put(parent);
+
+       /* create config map */
+       new_map++;
+       for (i = 0; i < grp->npins; i++) {
+               new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
+               new_map[i].data.configs.group_or_pin =
+                               pin_get_name(pctldev, grp->pins[i]);
+               new_map[i].data.configs.configs = &grp->pins_conf[i].conf;
+               new_map[i].data.configs.num_configs = 1;
+       }
+
+       dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
+               (*map)->data.mux.function, (*map)->data.mux.group, map_num);
+
+       return 0;
+}
+
+static void at91_dt_free_map(struct pinctrl_dev *pctldev,
+                               struct pinctrl_map *map, unsigned num_maps)
+{
+}
+
+static 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,
+       .pin_dbg_show           = at91_pin_dbg_show,
+       .dt_node_to_map         = at91_dt_node_to_map,
+       .dt_free_map            = at91_dt_free_map,
+};
+
+static void __iomem * pin_to_controller(struct at91_pinctrl *info,
+                                unsigned int bank)
+{
+       return gpio_chips[bank]->regbase;
+}
+
+static inline int pin_to_bank(unsigned pin)
+{
+       return pin /= MAX_NB_GPIO_PER_BANK;
+}
+
+static unsigned pin_to_mask(unsigned int pin)
+{
+       return 1 << pin;
+}
+
+static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask)
+{
+       writel_relaxed(mask, pio + PIO_IDR);
+}
+
+static unsigned at91_mux_get_pullup(void __iomem *pio, unsigned pin)
+{
+       return (readl_relaxed(pio + PIO_PUSR) >> pin) & 0x1;
+}
+
+static void at91_mux_set_pullup(void __iomem *pio, unsigned mask, bool on)
+{
+       writel_relaxed(mask, pio + (on ? PIO_PUER : PIO_PUDR));
+}
+
+static unsigned at91_mux_get_multidrive(void __iomem *pio, unsigned pin)
+{
+       return (readl_relaxed(pio + PIO_MDSR) >> pin) & 0x1;
+}
+
+static void at91_mux_set_multidrive(void __iomem *pio, unsigned mask, bool on)
+{
+       writel_relaxed(mask, pio + (on ? PIO_MDER : PIO_MDDR));
+}
+
+static void at91_mux_set_A_periph(void __iomem *pio, unsigned mask)
+{
+       writel_relaxed(mask, pio + PIO_ASR);
+}
+
+static void at91_mux_set_B_periph(void __iomem *pio, unsigned mask)
+{
+       writel_relaxed(mask, pio + PIO_BSR);
+}
+
+static void at91_mux_pio3_set_A_periph(void __iomem *pio, unsigned mask)
+{
+
+       writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask,
+                                               pio + PIO_ABCDSR1);
+       writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask,
+                                               pio + PIO_ABCDSR2);
+}
+
+static void at91_mux_pio3_set_B_periph(void __iomem *pio, unsigned mask)
+{
+       writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask,
+                                               pio + PIO_ABCDSR1);
+       writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask,
+                                               pio + PIO_ABCDSR2);
+}
+
+static void at91_mux_pio3_set_C_periph(void __iomem *pio, unsigned mask)
+{
+       writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1);
+       writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
+}
+
+static void at91_mux_pio3_set_D_periph(void __iomem *pio, unsigned mask)
+{
+       writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1);
+       writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
+}
+
+static enum at91_mux at91_mux_pio3_get_periph(void __iomem *pio, unsigned mask)
+{
+       unsigned select;
+
+       if (readl_relaxed(pio + PIO_PSR) & mask)
+               return AT91_MUX_GPIO;
+
+       select = !!(readl_relaxed(pio + PIO_ABCDSR1) & mask);
+       select |= (!!(readl_relaxed(pio + PIO_ABCDSR2) & mask) << 1);
+
+       return select + 1;
+}
+
+static enum at91_mux at91_mux_get_periph(void __iomem *pio, unsigned mask)
+{
+       unsigned select;
+
+       if (readl_relaxed(pio + PIO_PSR) & mask)
+               return AT91_MUX_GPIO;
+
+       select = readl_relaxed(pio + PIO_ABSR) & mask;
+
+       return select + 1;
+}
+
+static struct at91_pinctrl_mux_ops at91rm9200_ops = {
+       .get_periph     = at91_mux_get_periph,
+       .mux_A_periph   = at91_mux_set_A_periph,
+       .mux_B_periph   = at91_mux_set_B_periph,
+       .irq_type       = gpio_irq_type,
+};
+
+static struct at91_pinctrl_mux_ops at91sam9x5_ops = {
+       .get_periph     = at91_mux_pio3_get_periph,
+       .mux_A_periph   = at91_mux_pio3_set_A_periph,
+       .mux_B_periph   = at91_mux_pio3_set_B_periph,
+       .mux_C_periph   = at91_mux_pio3_set_C_periph,
+       .mux_D_periph   = at91_mux_pio3_set_D_periph,
+       .irq_type       = alt_gpio_irq_type,
+};
+
+static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pin)
+{
+       if (pin->mux) {
+               dev_dbg(dev, "pio%c%d configured as periph%c with conf = 0x%lu\n",
+                       pin->bank + 'A', pin->pin, pin->mux - 1 + 'A', pin->conf);
+       } else {
+               dev_dbg(dev, "pio%c%d configured as gpio with conf = 0x%lu\n",
+                       pin->bank + 'A', pin->pin, pin->conf);
+       }
+}
+
+static int pin_check_config(struct at91_pinctrl *info, const char* name,
+                           int index, const struct at91_pmx_pin *pin)
+{
+       int mux;
+
+       /* check if it's a valid config */
+       if (pin->bank >= info->nbanks) {
+               dev_err(info->dev, "%s: pin conf %d bank_id %d >= nbanks %d\n",
+                       name, index, pin->bank, info->nbanks);
+               return -EINVAL;
+       }
+
+       if (pin->pin >= MAX_NB_GPIO_PER_BANK) {
+               dev_err(info->dev, "%s: pin conf %d pin_bank_id %d >= %d\n",
+                       name, index, pin->pin, MAX_NB_GPIO_PER_BANK);
+               return -EINVAL;
+       }
+
+       if (!pin->mux)
+               return 0;
+
+       mux = pin->mux - 1;
+
+       if (mux >= info->nmux) {
+               dev_err(info->dev, "%s: pin conf %d mux_id %d >= nmux %d\n",
+                       name, index, mux, info->nmux);
+               return -EINVAL;
+       }
+
+       if (!(info->mux_mask[pin->bank * info->nmux + mux] & 1 << pin->pin)) {
+               dev_err(info->dev, "%s: pin conf %d mux_id %d not supported for pio%c%d\n",
+                       name, index, mux, pin->bank + 'A', pin->pin);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void at91_mux_gpio_disable(void __iomem *pio, unsigned mask)
+{
+       writel_relaxed(mask, pio + PIO_PDR);
+}
+
+static void at91_mux_gpio_enable(void __iomem *pio, unsigned mask, bool input)
+{
+       writel_relaxed(mask, pio + PIO_PER);
+       writel_relaxed(mask, pio + (input ? PIO_ODR : PIO_OER));
+}
+
+static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
+                          unsigned group)
+{
+       struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf;
+       const struct at91_pmx_pin *pin;
+       uint32_t npins = info->groups[group].npins;
+       int i, ret;
+       unsigned mask;
+       void __iomem *pio;
+
+       dev_dbg(info->dev, "enable function %s group %s\n",
+               info->functions[selector].name, info->groups[group].name);
+
+       /* first check that all the pins of the group are valid with a valid
+        * paramter */
+       for (i = 0; i < npins; i++) {
+               pin = &pins_conf[i];
+               ret = pin_check_config(info, info->groups[group].name, i, pin);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < npins; i++) {
+               pin = &pins_conf[i];
+               at91_pin_dbg(info->dev, pin);
+               pio = pin_to_controller(info, pin->bank);
+               mask = pin_to_mask(pin->pin);
+               at91_mux_disable_interrupt(pio, mask);
+               switch(pin->mux) {
+               case AT91_MUX_GPIO:
+                       at91_mux_gpio_enable(pio, mask, 1);
+                       break;
+               case AT91_MUX_PERIPH_A:
+                       info->ops->mux_A_periph(pio, mask);
+                       break;
+               case AT91_MUX_PERIPH_B:
+                       info->ops->mux_B_periph(pio, mask);
+                       break;
+               case AT91_MUX_PERIPH_C:
+                       if (!info->ops->mux_C_periph)
+                               return -EINVAL;
+                       info->ops->mux_C_periph(pio, mask);
+                       break;
+               case AT91_MUX_PERIPH_D:
+                       if (!info->ops->mux_D_periph)
+                               return -EINVAL;
+                       info->ops->mux_D_periph(pio, mask);
+                       break;
+               }
+               if (pin->mux)
+                       at91_mux_gpio_disable(pio, mask);
+       }
+
+       return 0;
+}
+
+static void at91_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
+                          unsigned group)
+{
+       struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf;
+       const struct at91_pmx_pin *pin;
+       uint32_t npins = info->groups[group].npins;
+       int i;
+       unsigned mask;
+       void __iomem *pio;
+
+       for (i = 0; i < npins; i++) {
+               pin = &pins_conf[i];
+               at91_pin_dbg(info->dev, pin);
+               pio = pin_to_controller(info, pin->bank);
+               mask = pin_to_mask(pin->pin);
+               at91_mux_gpio_enable(pio, mask, 1);
+       }
+}
+
+static int at91_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+       struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->nfunctions;
+}
+
+static const char *at91_pmx_get_func_name(struct pinctrl_dev *pctldev,
+                                         unsigned selector)
+{
+       struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->functions[selector].name;
+}
+
+static int at91_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+                              const char * const **groups,
+                              unsigned * const num_groups)
+{
+       struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       *groups = info->functions[selector].groups;
+       *num_groups = info->functions[selector].ngroups;
+
+       return 0;
+}
+
+static int at91_gpio_request_enable(struct pinctrl_dev *pctldev,
+                                   struct pinctrl_gpio_range *range,
+                                   unsigned offset)
+{
+       struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+       struct at91_gpio_chip *at91_chip;
+       struct gpio_chip *chip;
+       unsigned mask;
+
+       if (!range) {
+               dev_err(npct->dev, "invalid range\n");
+               return -EINVAL;
+       }
+       if (!range->gc) {
+               dev_err(npct->dev, "missing GPIO chip in range\n");
+               return -EINVAL;
+       }
+       chip = range->gc;
+       at91_chip = container_of(chip, struct at91_gpio_chip, chip);
+
+       dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
+
+       mask = 1 << (offset - chip->base);
+
+       dev_dbg(npct->dev, "enable pin %u as PIO%c%d 0x%x\n",
+               offset, 'A' + range->id, offset - chip->base, mask);
+
+       writel_relaxed(mask, at91_chip->regbase + PIO_PER);
+
+       return 0;
+}
+
+static void at91_gpio_disable_free(struct pinctrl_dev *pctldev,
+                                  struct pinctrl_gpio_range *range,
+                                  unsigned offset)
+{
+       struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+       dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset);
+       /* Set the pin to some default state, GPIO is usually default */
+}
+
+static 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,
+       .enable                 = at91_pmx_enable,
+       .disable                = at91_pmx_disable,
+       .gpio_request_enable    = at91_gpio_request_enable,
+       .gpio_disable_free      = at91_gpio_disable_free,
+};
+
+static int at91_pinconf_get(struct pinctrl_dev *pctldev,
+                            unsigned pin_id, unsigned long *config)
+{
+       struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       void __iomem *pio;
+       unsigned pin;
+
+       dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, *config);
+       pio = pin_to_controller(info, pin_to_bank(pin_id));
+       pin = pin_id % MAX_NB_GPIO_PER_BANK;
+
+       if (at91_mux_get_multidrive(pio, pin))
+               *config |= MULTI_DRIVE;
+
+       if (at91_mux_get_pullup(pio, pin))
+               *config |= PULL_UP;
+
+       return 0;
+}
+
+static int at91_pinconf_set(struct pinctrl_dev *pctldev,
+                            unsigned pin_id, unsigned long config)
+{
+       struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       unsigned mask;
+       void __iomem *pio;
+
+       dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config);
+       pio = pin_to_controller(info, pin_to_bank(pin_id));
+       mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK);
+
+       at91_mux_set_pullup(pio, mask, config & PULL_UP);
+       at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
+       return 0;
+}
+
+static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+                                  struct seq_file *s, unsigned pin_id)
+{
+
+}
+
+static void at91_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+                                        struct seq_file *s, unsigned group)
+{
+}
+
+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,
+       .pin_config_group_dbg_show      = at91_pinconf_group_dbg_show,
+};
+
+static struct pinctrl_desc at91_pinctrl_desc = {
+       .pctlops        = &at91_pctrl_ops,
+       .pmxops         = &at91_pmx_ops,
+       .confops        = &at91_pinconf_ops,
+       .owner          = THIS_MODULE,
+};
+
+static const char *gpio_compat = "atmel,at91rm9200-gpio";
+
+static void __devinit at91_pinctrl_child_count(struct at91_pinctrl *info,
+                                             struct device_node *np)
+{
+       struct device_node *child;
+
+       for_each_child_of_node(np, child) {
+               if (of_device_is_compatible(child, gpio_compat)) {
+                       info->nbanks++;
+               } else {
+                       info->nfunctions++;
+                       info->ngroups += of_get_child_count(child);
+               }
+       }
+}
+
+static int __devinit at91_pinctrl_mux_mask(struct at91_pinctrl *info,
+                                         struct device_node *np)
+{
+       int ret = 0;
+       int size;
+       const const __be32 *list;
+
+       list = of_get_property(np, "atmel,mux-mask", &size);
+       if (!list) {
+               dev_err(info->dev, "can not read the mux-mask of %d\n", size);
+               return -EINVAL;
+       }
+
+       size /= sizeof(*list);
+       if (!size || size % info->nbanks) {
+               dev_err(info->dev, "wrong mux mask array should be by %d\n", info->nbanks);
+               return -EINVAL;
+       }
+       info->nmux = size / info->nbanks;
+
+       info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL);
+       if (!info->mux_mask) {
+               dev_err(info->dev, "could not alloc mux_mask\n");
+               return -ENOMEM;
+       }
+
+       ret = of_property_read_u32_array(np, "atmel,mux-mask",
+                                         info->mux_mask, size);
+       if (ret)
+               dev_err(info->dev, "can not read the mux-mask of %d\n", size);
+       return ret;
+}
+
+static int __devinit at91_pinctrl_parse_groups(struct device_node *np,
+                               struct at91_pin_group *grp,
+                               struct at91_pinctrl *info,
+                               u32 index)
+{
+       struct at91_pmx_pin *pin;
+       int size;
+       const const __be32 *list;
+       int i, j;
+
+       dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+
+       /* Initialise group */
+       grp->name = np->name;
+
+       /*
+        * the binding format is atmel,pins = <bank pin mux CONFIG ...>,
+        * do sanity check and calculate pins number
+        */
+       list = of_get_property(np, "atmel,pins", &size);
+       /* we do not check return since it's safe node passed down */
+       size /= sizeof(*list);
+       if (!size || size % 4) {
+               dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n");
+               return -EINVAL;
+       }
+
+       grp->npins = size / 4;
+       pin = grp->pins_conf = devm_kzalloc(info->dev, grp->npins * sizeof(struct at91_pmx_pin),
+                               GFP_KERNEL);
+       grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
+                               GFP_KERNEL);
+       if (!grp->pins_conf || !grp->pins)
+               return -ENOMEM;
+
+       for (i = 0, j = 0; i < size; i += 4, j++) {
+               pin->bank = be32_to_cpu(*list++);
+               pin->pin = be32_to_cpu(*list++);
+               grp->pins[j] = pin->bank * MAX_NB_GPIO_PER_BANK + pin->pin;
+               pin->mux = be32_to_cpu(*list++);
+               pin->conf = be32_to_cpu(*list++);
+
+               at91_pin_dbg(info->dev, pin);
+               pin++;
+       }
+
+       return 0;
+}
+
+static int __devinit at91_pinctrl_parse_functions(struct device_node *np,
+                       struct at91_pinctrl *info, u32 index)
+{
+       struct device_node *child;
+       struct at91_pmx_func *func;
+       struct at91_pin_group *grp;
+       int ret;
+       static u32 grp_index;
+       u32 i = 0;
+
+       dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+
+       func = &info->functions[index];
+
+       /* Initialise function */
+       func->name = np->name;
+       func->ngroups = of_get_child_count(np);
+       if (func->ngroups <= 0) {
+               dev_err(info->dev, "no groups defined\n");
+               return -EINVAL;
+       }
+       func->groups = devm_kzalloc(info->dev,
+                       func->ngroups * sizeof(char *), GFP_KERNEL);
+       if (!func->groups)
+               return -ENOMEM;
+
+       for_each_child_of_node(np, child) {
+               func->groups[i] = child->name;
+               grp = &info->groups[grp_index++];
+               ret = at91_pinctrl_parse_groups(child, grp, info, i++);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static struct of_device_id at91_pinctrl_of_match[] __devinitdata = {
+       { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops },
+       { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops },
+       { /* sentinel */ }
+};
+
+static int __devinit at91_pinctrl_probe_dt(struct platform_device *pdev,
+                                          struct at91_pinctrl *info)
+{
+       int ret = 0;
+       int i, j;
+       uint32_t *tmp;
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *child;
+
+       if (!np)
+               return -ENODEV;
+
+       info->dev = &pdev->dev;
+       info->ops = (struct at91_pinctrl_mux_ops*)
+               of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
+       at91_pinctrl_child_count(info, np);
+
+       if (info->nbanks < 1) {
+               dev_err(&pdev->dev, "you need to specify atleast one gpio-controller\n");
+               return -EINVAL;
+       }
+
+       ret = at91_pinctrl_mux_mask(info, np);
+       if (ret)
+               return ret;
+
+       dev_dbg(&pdev->dev, "nmux = %d\n", info->nmux);
+
+       dev_dbg(&pdev->dev, "mux-mask\n");
+       tmp = info->mux_mask;
+       for (i = 0; i < info->nbanks; i++) {
+               for (j = 0; j < info->nmux; j++, tmp++) {
+                       dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]);
+               }
+       }
+
+       dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
+       dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
+       info->functions = devm_kzalloc(&pdev->dev, info->nfunctions * sizeof(struct at91_pmx_func),
+                                       GFP_KERNEL);
+       if (!info->functions)
+               return -ENOMEM;
+
+       info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct at91_pin_group),
+                                       GFP_KERNEL);
+       if (!info->groups)
+               return -ENOMEM;
+
+       dev_dbg(&pdev->dev, "nbanks = %d\n", info->nbanks);
+       dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
+       dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
+
+       i = 0;
+
+       for_each_child_of_node(np, child) {
+               if (of_device_is_compatible(child, gpio_compat))
+                       continue;
+               ret = at91_pinctrl_parse_functions(child, info, i++);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to parse function\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int __devinit at91_pinctrl_probe(struct platform_device *pdev)
+{
+       struct at91_pinctrl *info;
+       struct pinctrl_pin_desc *pdesc;
+       int ret, i, j ,k;
+
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       ret = at91_pinctrl_probe_dt(pdev, info);
+       if (ret)
+               return ret;
+
+       /*
+        * We need all the GPIO drivers to probe FIRST, or we will not be able
+        * to obtain references to the struct gpio_chip * for them, and we
+        * need this to proceed.
+        */
+       for (i = 0; i < info->nbanks; i++) {
+               if (!gpio_chips[i]) {
+                       dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
+                       devm_kfree(&pdev->dev, info);
+                       return -EPROBE_DEFER;
+               }
+       }
+
+       at91_pinctrl_desc.name = dev_name(&pdev->dev);
+       at91_pinctrl_desc.npins = info->nbanks * MAX_NB_GPIO_PER_BANK;
+       at91_pinctrl_desc.pins = pdesc =
+               devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL);
+
+       if (!at91_pinctrl_desc.pins)
+               return -ENOMEM;
+
+       for (i = 0 , k = 0; i < info->nbanks; i++) {
+               for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) {
+                       pdesc->number = k;
+                       pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j);
+                       pdesc++;
+               }
+       }
+
+       platform_set_drvdata(pdev, info);
+       info->pctl = pinctrl_register(&at91_pinctrl_desc, &pdev->dev, info);
+
+       if (!info->pctl) {
+               dev_err(&pdev->dev, "could not register AT91 pinctrl driver\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* We will handle a range of GPIO pins */
+       for (i = 0; i < info->nbanks; i++)
+               pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range);
+
+       dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n");
+
+       return 0;
+
+err:
+       return ret;
+}
+
+static int __devexit at91_pinctrl_remove(struct platform_device *pdev)
+{
+       struct at91_pinctrl *info = platform_get_drvdata(pdev);
+
+       pinctrl_unregister(info->pctl);
+
+       return 0;
+}
+
+static int at91_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;
+       int bank = chip->base / chip->ngpio;
+
+       dev_dbg(chip->dev, "%s:%d pio%c%d(%d)\n", __func__, __LINE__,
+                'A' + bank, offset, gpio);
+
+       return pinctrl_request_gpio(gpio);
+}
+
+static void at91_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       int gpio = chip->base + offset;
+
+       pinctrl_free_gpio(gpio);
+}
+
+static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+       void __iomem *pio = at91_gpio->regbase;
+       unsigned mask = 1 << offset;
+
+       writel_relaxed(mask, pio + PIO_ODR);
+       return 0;
+}
+
+static int at91_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+       void __iomem *pio = at91_gpio->regbase;
+       unsigned mask = 1 << offset;
+       u32 pdsr;
+
+       pdsr = readl_relaxed(pio + PIO_PDSR);
+       return (pdsr & mask) != 0;
+}
+
+static void at91_gpio_set(struct gpio_chip *chip, unsigned offset,
+                               int val)
+{
+       struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+       void __iomem *pio = at91_gpio->regbase;
+       unsigned mask = 1 << offset;
+
+       writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
+}
+
+static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+                               int val)
+{
+       struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+       void __iomem *pio = at91_gpio->regbase;
+       unsigned mask = 1 << offset;
+
+       writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
+       writel_relaxed(mask, pio + PIO_OER);
+
+       return 0;
+}
+
+static int at91_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+       int virq;
+
+       if (offset < chip->ngpio)
+               virq = irq_create_mapping(at91_gpio->domain, offset);
+       else
+               virq = -ENXIO;
+
+       dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+                               chip->label, offset + chip->base, virq);
+       return virq;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+       enum at91_mux mode;
+       int i;
+       struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+       void __iomem *pio = at91_gpio->regbase;
+
+       for (i = 0; i < chip->ngpio; i++) {
+               unsigned pin = chip->base + i;
+               unsigned mask = pin_to_mask(pin);
+               const char *gpio_label;
+               u32 pdsr;
+
+               gpio_label = gpiochip_is_requested(chip, i);
+               if (!gpio_label)
+                       continue;
+               mode = at91_gpio->ops->get_periph(pio, mask);
+               seq_printf(s, "[%s] GPIO%s%d: ",
+                          gpio_label, chip->label, i);
+               if (mode == AT91_MUX_GPIO) {
+                       pdsr = readl_relaxed(pio + PIO_PDSR);
+
+                       seq_printf(s, "[gpio] %s\n",
+                                  pdsr & mask ?
+                                  "set" : "clear");
+               } else {
+                       seq_printf(s, "[periph %c]\n",
+                                  mode + 'A' - 1);
+               }
+       }
+}
+#else
+#define at91_gpio_dbg_show     NULL
+#endif
+
+/* Several AIC controller irqs are dispatched through this GPIO handler.
+ * To use any AT91_PIN_* as an externally triggered IRQ, first call
+ * at91_set_gpio_input() then maybe enable its glitch filter.
+ * Then just request_irq() with the pin ID; it works like any ARM IRQ
+ * handler.
+ * First implementation always triggers on rising and falling edges
+ * whereas the newer PIO3 can be additionally configured to trigger on
+ * level, edge with any polarity.
+ *
+ * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after
+ * configuring them with at91_set_a_periph() or at91_set_b_periph().
+ * IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering.
+ */
+
+static void gpio_irq_mask(struct irq_data *d)
+{
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       void __iomem    *pio = at91_gpio->regbase;
+       unsigned        mask = 1 << d->hwirq;
+
+       if (pio)
+               writel_relaxed(mask, pio + PIO_IDR);
+}
+
+static void gpio_irq_unmask(struct irq_data *d)
+{
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       void __iomem    *pio = at91_gpio->regbase;
+       unsigned        mask = 1 << d->hwirq;
+
+       if (pio)
+               writel_relaxed(mask, pio + PIO_IER);
+}
+
+static int gpio_irq_type(struct irq_data *d, unsigned type)
+{
+       switch (type) {
+       case IRQ_TYPE_NONE:
+       case IRQ_TYPE_EDGE_BOTH:
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+/* Alternate irq type for PIO3 support */
+static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
+{
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       void __iomem    *pio = at91_gpio->regbase;
+       unsigned        mask = 1 << d->hwirq;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               writel_relaxed(mask, pio + PIO_ESR);
+               writel_relaxed(mask, pio + PIO_REHLSR);
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               writel_relaxed(mask, pio + PIO_ESR);
+               writel_relaxed(mask, pio + PIO_FELLSR);
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               writel_relaxed(mask, pio + PIO_LSR);
+               writel_relaxed(mask, pio + PIO_FELLSR);
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               writel_relaxed(mask, pio + PIO_LSR);
+               writel_relaxed(mask, pio + PIO_REHLSR);
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               /*
+                * disable additional interrupt modes:
+                * fall back to default behavior
+                */
+               writel_relaxed(mask, pio + PIO_AIMDR);
+               return 0;
+       case IRQ_TYPE_NONE:
+       default:
+               pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq));
+               return -EINVAL;
+       }
+
+       /* enable additional interrupt modes */
+       writel_relaxed(mask, pio + PIO_AIMER);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
+{
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       unsigned        bank = at91_gpio->pioc_idx;
+
+       if (unlikely(bank >= MAX_GPIO_BANKS))
+               return -EINVAL;
+
+       irq_set_irq_wake(at91_gpio->pioc_virq, state);
+
+       return 0;
+}
+#else
+#define gpio_irq_set_wake      NULL
+#endif
+
+static struct irq_chip gpio_irqchip = {
+       .name           = "GPIO",
+       .irq_disable    = gpio_irq_mask,
+       .irq_mask       = gpio_irq_mask,
+       .irq_unmask     = gpio_irq_unmask,
+       /* .irq_set_type is set dynamically */
+       .irq_set_wake   = gpio_irq_set_wake,
+};
+
+static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct irq_data *idata = irq_desc_get_irq_data(desc);
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
+       void __iomem    *pio = at91_gpio->regbase;
+       unsigned long   isr;
+       int             n;
+
+       chained_irq_enter(chip, desc);
+       for (;;) {
+               /* Reading ISR acks pending (edge triggered) GPIO interrupts.
+                * When there none are pending, we're finished unless we need
+                * to process multiple banks (like ID_PIOCDE on sam9263).
+                */
+               isr = readl_relaxed(pio + PIO_ISR) & readl_relaxed(pio + PIO_IMR);
+               if (!isr) {
+                       if (!at91_gpio->next)
+                               break;
+                       at91_gpio = at91_gpio->next;
+                       pio = at91_gpio->regbase;
+                       continue;
+               }
+
+               for_each_set_bit(n, &isr, BITS_PER_LONG) {
+                       generic_handle_irq(irq_find_mapping(at91_gpio->domain, n));
+               }
+       }
+       chained_irq_exit(chip, desc);
+       /* now it may re-trigger */
+}
+
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpio_lock_class;
+
+static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+                                                       irq_hw_number_t hw)
+{
+       struct at91_gpio_chip   *at91_gpio = h->host_data;
+
+       irq_set_lockdep_class(virq, &gpio_lock_class);
+
+       /*
+        * Can use the "simple" and not "edge" handler since it's
+        * shorter, and the AIC handles interrupts sanely.
+        */
+       irq_set_chip_and_handler(virq, &gpio_irqchip,
+                                handle_simple_irq);
+       set_irq_flags(virq, IRQF_VALID);
+       irq_set_chip_data(virq, at91_gpio);
+
+       return 0;
+}
+
+static int at91_gpio_irq_domain_xlate(struct irq_domain *d,
+                                     struct device_node *ctrlr,
+                                     const u32 *intspec, unsigned int intsize,
+                                     irq_hw_number_t *out_hwirq,
+                                     unsigned int *out_type)
+{
+       struct at91_gpio_chip *at91_gpio = d->host_data;
+       int ret;
+       int pin = at91_gpio->chip.base + intspec[0];
+
+       if (WARN_ON(intsize < 2))
+               return -EINVAL;
+       *out_hwirq = intspec[0];
+       *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+
+       ret = gpio_request(pin, ctrlr->full_name);
+       if (ret)
+               return ret;
+
+       ret = gpio_direction_input(pin);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static struct irq_domain_ops at91_gpio_ops = {
+       .map    = at91_gpio_irq_map,
+       .xlate  = at91_gpio_irq_domain_xlate,
+};
+
+static int at91_gpio_of_irq_setup(struct device_node *node,
+                                 struct at91_gpio_chip *at91_gpio)
+{
+       struct at91_gpio_chip   *prev = NULL;
+       struct irq_data         *d = irq_get_irq_data(at91_gpio->pioc_virq);
+
+       at91_gpio->pioc_hwirq = irqd_to_hwirq(d);
+
+       /* Setup proper .irq_set_type function */
+       gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type;
+
+       /* Disable irqs of this PIO controller */
+       writel_relaxed(~0, at91_gpio->regbase + PIO_IDR);
+
+       /* Setup irq domain */
+       at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
+                                               &at91_gpio_ops, at91_gpio);
+       if (!at91_gpio->domain)
+               panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
+                       at91_gpio->pioc_idx);
+
+       /* Setup chained handler */
+       if (at91_gpio->pioc_idx)
+               prev = gpio_chips[at91_gpio->pioc_idx - 1];
+
+       /* The toplevel handler handles one bank of GPIOs, except
+        * on some SoC it can handles up to three...
+        * We only set up the handler for the first of the list.
+        */
+       if (prev && prev->next == at91_gpio)
+               return 0;
+
+       irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
+       irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
+
+       return 0;
+}
+
+/* This structure is replicated for each GPIO block allocated at probe time */
+static struct gpio_chip at91_gpio_template = {
+       .request                = at91_gpio_request,
+       .free                   = at91_gpio_free,
+       .direction_input        = at91_gpio_direction_input,
+       .get                    = at91_gpio_get,
+       .direction_output       = at91_gpio_direction_output,
+       .set                    = at91_gpio_set,
+       .to_irq                 = at91_gpio_to_irq,
+       .dbg_show               = at91_gpio_dbg_show,
+       .can_sleep              = 0,
+       .ngpio                  = MAX_NB_GPIO_PER_BANK,
+};
+
+static void __devinit at91_gpio_probe_fixup(void)
+{
+       unsigned i;
+       struct at91_gpio_chip *at91_gpio, *last = NULL;
+
+       for (i = 0; i < gpio_banks; i++) {
+               at91_gpio = gpio_chips[i];
+
+               /*
+                * GPIO controller are grouped on some SoC:
+                * PIOC, PIOD and PIOE can share the same IRQ line
+                */
+               if (last && last->pioc_virq == at91_gpio->pioc_virq)
+                       last->next = at91_gpio;
+               last = at91_gpio;
+       }
+}
+
+static struct of_device_id at91_gpio_of_match[] __devinitdata = {
+       { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, },
+       { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops },
+       { /* sentinel */ }
+};
+
+static int __devinit at91_gpio_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct resource *res;
+       struct at91_gpio_chip *at91_chip = NULL;
+       struct gpio_chip *chip;
+       struct pinctrl_gpio_range *range;
+       int ret = 0;
+       int irq;
+       int alias_idx = of_alias_get_id(np, "gpio");
+       uint32_t ngpio;
+
+       BUG_ON(alias_idx >= ARRAY_SIZE(gpio_chips));
+       if (gpio_chips[alias_idx]) {
+               ret = -EBUSY;
+               goto err;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ret = -ENOENT;
+               goto err;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
+               goto err;
+       }
+
+       at91_chip = devm_kzalloc(&pdev->dev, sizeof(*at91_chip), GFP_KERNEL);
+       if (!at91_chip) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       at91_chip->regbase = devm_request_and_ioremap(&pdev->dev, res);
+       if (!at91_chip->regbase) {
+               dev_err(&pdev->dev, "failed to map registers, ignoring.\n");
+               ret = -EBUSY;
+               goto err;
+       }
+
+       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;
+
+       at91_chip->clock = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(at91_chip->clock)) {
+               dev_err(&pdev->dev, "failed to get clock, ignoring.\n");
+               goto err;
+       }
+
+       if (clk_prepare(at91_chip->clock))
+               goto clk_prep_err;
+
+       /* enable PIO controller's clock */
+       if (clk_enable(at91_chip->clock)) {
+               dev_err(&pdev->dev, "failed to enable clock, ignoring.\n");
+               goto clk_err;
+       }
+
+       at91_chip->chip = at91_gpio_template;
+
+       chip = &at91_chip->chip;
+       chip->of_node = np;
+       chip->label = dev_name(&pdev->dev);
+       chip->dev = &pdev->dev;
+       chip->owner = THIS_MODULE;
+       chip->base = alias_idx * MAX_NB_GPIO_PER_BANK;
+
+       if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
+               if (ngpio >= MAX_NB_GPIO_PER_BANK)
+                       pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
+                              alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
+               else
+                       chip->ngpio = ngpio;
+       }
+
+       range = &at91_chip->range;
+       range->name = chip->label;
+       range->id = alias_idx;
+       range->pin_base = range->base = range->id * MAX_NB_GPIO_PER_BANK;
+
+       range->npins = chip->ngpio;
+       range->gc = chip;
+
+       ret = gpiochip_add(chip);
+       if (ret)
+               goto clk_err;
+
+       gpio_chips[alias_idx] = at91_chip;
+       gpio_banks = max(gpio_banks, alias_idx + 1);
+
+       at91_gpio_probe_fixup();
+
+       at91_gpio_of_irq_setup(np, at91_chip);
+
+       dev_info(&pdev->dev, "at address %p\n", at91_chip->regbase);
+
+       return 0;
+
+clk_err:
+       clk_unprepare(at91_chip->clock);
+clk_prep_err:
+       clk_put(at91_chip->clock);
+err:
+       dev_err(&pdev->dev, "Failure %i for GPIO %i\n", ret, alias_idx);
+
+       return ret;
+}
+
+static struct platform_driver at91_gpio_driver = {
+       .driver = {
+               .name = "gpio-at91",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(at91_gpio_of_match),
+       },
+       .probe = at91_gpio_probe,
+};
+
+static struct platform_driver at91_pinctrl_driver = {
+       .driver = {
+               .name = "pinctrl-at91",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(at91_pinctrl_of_match),
+       },
+       .probe = at91_pinctrl_probe,
+       .remove = __devexit_p(at91_pinctrl_remove),
+};
+
+static int __init at91_pinctrl_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&at91_gpio_driver);
+       if (ret)
+               return ret;
+       return platform_driver_register(&at91_pinctrl_driver);
+}
+arch_initcall(at91_pinctrl_init);
+
+static void __exit at91_pinctrl_exit(void)
+{
+       platform_driver_unregister(&at91_pinctrl_driver);
+}
+
+module_exit(at91_pinctrl_exit);
+MODULE_AUTHOR("Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>");
+MODULE_DESCRIPTION("Atmel AT91 pinctrl driver");
+MODULE_LICENSE("GPL v2");
index b446c96..5c7daf9 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/io.h>
+#include <linux/irqdomain.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
@@ -64,10 +65,8 @@ struct u300_gpio {
        struct gpio_chip chip;
        struct list_head port_list;
        struct clk *clk;
-       struct resource *memres;
        void __iomem *base;
        struct device *dev;
-       int irq_base;
        u32 stride;
        /* Register offsets */
        u32 pcr;
@@ -83,6 +82,7 @@ struct u300_gpio_port {
        struct list_head node;
        struct u300_gpio *gpio;
        char name[8];
+       struct irq_domain *domain;
        int irq;
        int number;
        u8 toggle_edge_mode;
@@ -314,10 +314,30 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
        struct u300_gpio *gpio = to_u300_gpio(chip);
-       int retirq = gpio->irq_base + offset;
+       int portno = offset >> 3;
+       struct u300_gpio_port *port = NULL;
+       struct list_head *p;
+       int retirq;
+
+       list_for_each(p, &gpio->port_list) {
+               port = list_entry(p, struct u300_gpio_port, node);
+               if (port->number == portno)
+                       break;
+       }
+       if (port == NULL) {
+               dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n",
+                       offset);
+               return -EINVAL;
+       }
+
+       /*
+        * The local hwirqs on the port are the lower three bits, there
+        * are exactly 8 IRQs per port since they are 8-bit
+        */
+       retirq = irq_find_mapping(port->domain, (offset & 0x7));
 
-       dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset,
-               retirq);
+       dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n",
+               offset, retirq, port->number);
        return retirq;
 }
 
@@ -467,7 +487,7 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
 {
        struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
        struct u300_gpio *gpio = port->gpio;
-       int offset = d->irq - gpio->irq_base;
+       int offset = (port->number << 3) + d->hwirq;
        u32 val;
 
        if ((trigger & IRQF_TRIGGER_RISING) &&
@@ -503,10 +523,12 @@ static void u300_gpio_irq_enable(struct irq_data *d)
 {
        struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
        struct u300_gpio *gpio = port->gpio;
-       int offset = d->irq - gpio->irq_base;
+       int offset = (port->number << 3) + d->hwirq;
        u32 val;
        unsigned long flags;
 
+       dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n",
+                d->hwirq, port->name, offset);
        local_irq_save(flags);
        val = readl(U300_PIN_REG(offset, ien));
        writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
@@ -517,7 +539,7 @@ static void u300_gpio_irq_disable(struct irq_data *d)
 {
        struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
        struct u300_gpio *gpio = port->gpio;
-       int offset = d->irq - gpio->irq_base;
+       int offset = (port->number << 3) + d->hwirq;
        u32 val;
        unsigned long flags;
 
@@ -555,8 +577,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
                int irqoffset;
 
                for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) {
-                       int pin_irq = gpio->irq_base + (port->number << 3)
-                               + irqoffset;
+                       int pin_irq = irq_find_mapping(port->domain, irqoffset);
                        int offset = pinoffset + irqoffset;
 
                        dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n",
@@ -631,6 +652,8 @@ static inline void u300_gpio_free_ports(struct u300_gpio *gpio)
        list_for_each_safe(p, n, &gpio->port_list) {
                port = list_entry(p, struct u300_gpio_port, node);
                list_del(&port->node);
+               if (port->domain)
+                       irq_domain_remove(port->domain);
                kfree(port);
        }
 }
@@ -639,56 +662,46 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
 {
        struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev);
        struct u300_gpio *gpio;
+       struct resource *memres;
        int err = 0;
        int portno;
        u32 val;
        u32 ifr;
        int i;
 
-       gpio = kzalloc(sizeof(struct u300_gpio), GFP_KERNEL);
-       if (gpio == NULL) {
-               dev_err(&pdev->dev, "failed to allocate memory\n");
+       gpio = devm_kzalloc(&pdev->dev, sizeof(struct u300_gpio), GFP_KERNEL);
+       if (gpio == NULL)
                return -ENOMEM;
-       }
 
        gpio->chip = u300_gpio_chip;
        gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT;
-       gpio->irq_base = plat->gpio_irq_base;
        gpio->chip.dev = &pdev->dev;
        gpio->chip.base = plat->gpio_base;
        gpio->dev = &pdev->dev;
 
-       /* Get GPIO clock */
-       gpio->clk = clk_get(gpio->dev, NULL);
+       memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!memres) {
+               dev_err(gpio->dev, "could not get GPIO memory resource\n");
+               return -ENODEV;
+       }
+
+       gpio->base = devm_request_and_ioremap(&pdev->dev, memres);
+       if (!gpio->base) {
+               dev_err(gpio->dev, "could not get remap memory\n");
+               return -ENOMEM;
+       }
+
+       gpio->clk = devm_clk_get(gpio->dev, NULL);
        if (IS_ERR(gpio->clk)) {
                err = PTR_ERR(gpio->clk);
                dev_err(gpio->dev, "could not get GPIO clock\n");
-               goto err_no_clk;
+               return err;
        }
+
        err = clk_prepare_enable(gpio->clk);
        if (err) {
                dev_err(gpio->dev, "could not enable GPIO clock\n");
-               goto err_no_clk_enable;
-       }
-
-       gpio->memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!gpio->memres) {
-               dev_err(gpio->dev, "could not get GPIO memory resource\n");
-               err = -ENODEV;
-               goto err_no_resource;
-       }
-
-       if (!request_mem_region(gpio->memres->start,
-                               resource_size(gpio->memres),
-                               "GPIO Controller")) {
-               err = -ENODEV;
-               goto err_no_ioregion;
-       }
-
-       gpio->base = ioremap(gpio->memres->start, resource_size(gpio->memres));
-       if (!gpio->base) {
-               err = -ENOMEM;
-               goto err_no_ioremap;
+               return err;
        }
 
        dev_info(gpio->dev,
@@ -732,18 +745,26 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
                port->irq = platform_get_irq_byname(pdev,
                                                    port->name);
 
-               dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq,
+               dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq,
                        port->name);
 
+               port->domain = irq_domain_add_linear(pdev->dev.of_node,
+                                                    U300_GPIO_PINS_PER_PORT,
+                                                    &irq_domain_simple_ops,
+                                                    port);
+               if (!port->domain)
+                       goto err_no_domain;
+
                irq_set_chained_handler(port->irq, u300_gpio_irq_handler);
                irq_set_handler_data(port->irq, port);
 
                /* For each GPIO pin set the unique IRQ handler */
                for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) {
-                       int irqno = gpio->irq_base + (portno << 3) + i;
+                       int irqno = irq_create_mapping(port->domain, i);
 
-                       dev_dbg(gpio->dev, "handler for IRQ %d on %s\n",
-                               irqno, port->name);
+                       dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n",
+                               gpio->chip.base + (port->number << 3) + i,
+                               port->name, irqno);
                        irq_set_chip_and_handler(irqno, &u300_gpio_irqchip,
                                                 handle_simple_irq);
                        set_irq_flags(irqno, IRQF_VALID);
@@ -776,18 +797,10 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
 err_no_pinctrl:
        err = gpiochip_remove(&gpio->chip);
 err_no_chip:
+err_no_domain:
 err_no_port:
        u300_gpio_free_ports(gpio);
-       iounmap(gpio->base);
-err_no_ioremap:
-       release_mem_region(gpio->memres->start, resource_size(gpio->memres));
-err_no_ioregion:
-err_no_resource:
        clk_disable_unprepare(gpio->clk);
-err_no_clk_enable:
-       clk_put(gpio->clk);
-err_no_clk:
-       kfree(gpio);
        dev_info(&pdev->dev, "module ERROR:%d\n", err);
        return err;
 }
@@ -806,13 +819,8 @@ static int __exit u300_gpio_remove(struct platform_device *pdev)
                return err;
        }
        u300_gpio_free_ports(gpio);
-       iounmap(gpio->base);
-       release_mem_region(gpio->memres->start,
-                          resource_size(gpio->memres));
        clk_disable_unprepare(gpio->clk);
-       clk_put(gpio->clk);
        platform_set_drvdata(pdev, NULL);
-       kfree(gpio);
        return 0;
 }
 
index 21362f4..6ff6652 100644 (file)
@@ -36,6 +36,7 @@
 /* list of external wakeup controllers supported */
 static const struct of_device_id exynos_wkup_irq_ids[] = {
        { .compatible = "samsung,exynos4210-wakeup-eint", },
+       { }
 };
 
 static void exynos_gpio_irq_unmask(struct irq_data *irqd)
index 9ecacf3..a3905e5 100644 (file)
 #define SIRFSOC_NUM_PADS    622
 #define SIRFSOC_RSC_PIN_MUX 0x4
 
-#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
+#define SIRFSOC_GPIO_PAD_EN(g)         ((g)*0x100 + 0x84)
+#define SIRFSOC_GPIO_PAD_EN_CLR(g)     ((g)*0x100 + 0x90)
 #define SIRFSOC_GPIO_CTRL(g, i)                        ((g)*0x100 + (i)*4)
 #define SIRFSOC_GPIO_DSP_EN0                   (0x80)
-#define SIRFSOC_GPIO_PAD_EN(g)                 ((g)*0x100 + 0x84)
 #define SIRFSOC_GPIO_INT_STATUS(g)             ((g)*0x100 + 0x8C)
 
 #define SIRFSOC_GPIO_CTL_INTR_LOW_MASK         0x1
@@ -60,6 +60,7 @@ struct sirfsoc_gpio_bank {
        int id;
        int parent_irq;
        spinlock_t lock;
+       bool is_marco; /* for marco, some registers are different with prima2 */
 };
 
 static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS];
@@ -191,6 +192,7 @@ struct sirfsoc_pmx {
        struct pinctrl_dev *pmx;
        void __iomem *gpio_virtbase;
        void __iomem *rsc_virtbase;
+       bool is_marco;
 };
 
 /* SIRFSOC_GPIO_PAD_EN set */
@@ -1088,12 +1090,21 @@ static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector
 
        for (i = 0; i < mux->muxmask_counts; i++) {
                u32 muxval;
-               muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
-               if (enable)
-                       muxval = muxval & ~mask[i].mask;
-               else
-                       muxval = muxval | mask[i].mask;
-               writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+               if (!spmx->is_marco) {
+                       muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+                       if (enable)
+                               muxval = muxval & ~mask[i].mask;
+                       else
+                               muxval = muxval | mask[i].mask;
+                       writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+               } else {
+                       if (enable)
+                               writel(mask[i].mask, spmx->gpio_virtbase +
+                                       SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group));
+                       else
+                               writel(mask[i].mask, spmx->gpio_virtbase +
+                                       SIRFSOC_GPIO_PAD_EN(mask[i].group));
+               }
        }
 
        if (mux->funcmask && enable) {
@@ -1158,9 +1169,14 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
 
        spmx = pinctrl_dev_get_drvdata(pmxdev);
 
-       muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
-       muxval = muxval | (1 << (offset - range->pin_base));
-       writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+       if (!spmx->is_marco) {
+               muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+               muxval = muxval | (1 << (offset - range->pin_base));
+               writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+       } else {
+               writel(1 << (offset - range->pin_base), spmx->gpio_virtbase +
+                       SIRFSOC_GPIO_PAD_EN(group));
+       }
 
        return 0;
 }
@@ -1218,6 +1234,7 @@ static void __iomem *sirfsoc_rsc_of_iomap(void)
 {
        const struct of_device_id rsc_ids[]  = {
                { .compatible = "sirf,prima2-rsc" },
+               { .compatible = "sirf,marco-rsc" },
                {}
        };
        struct device_node *np;
@@ -1259,6 +1276,9 @@ static int __devinit sirfsoc_pinmux_probe(struct platform_device *pdev)
                goto out_no_rsc_remap;
        }
 
+       if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
+               spmx->is_marco = 1;
+
        /* Now register the pin controller and all pins it handles */
        spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx);
        if (!spmx->pmx) {
@@ -1287,6 +1307,7 @@ out_no_gpio_remap:
 
 static const struct of_device_id pinmux_ids[] __devinitconst = {
        { .compatible = "sirf,prima2-pinctrl" },
+       { .compatible = "sirf,marco-pinctrl" },
        {}
 };
 
@@ -1621,8 +1642,8 @@ static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset,
        spin_unlock_irqrestore(&bank->lock, flags);
 }
 
-int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,
-       irq_hw_number_t hwirq)
+static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+                               irq_hw_number_t hwirq)
 {
        struct sirfsoc_gpio_bank *bank = d->host_data;
 
@@ -1648,6 +1669,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
        struct sirfsoc_gpio_bank *bank;
        void *regs;
        struct platform_device *pdev;
+       bool is_marco = false;
 
        pdev = of_find_device_by_node(np);
        if (!pdev)
@@ -1657,6 +1679,9 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
        if (!regs)
                return -ENOMEM;
 
+       if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
+               is_marco = 1;
+
        for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
                bank = &sgpio_bank[i];
                spin_lock_init(&bank->lock);
@@ -1673,6 +1698,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
                bank->chip.gc.of_node = np;
                bank->chip.regs = regs;
                bank->id = i;
+               bank->is_marco = is_marco;
                bank->parent_irq = platform_get_irq(pdev, i);
                if (bank->parent_irq < 0) {
                        err = bank->parent_irq;
index 309f5b9..d756cce 100644 (file)
@@ -663,8 +663,6 @@ static const struct pinctrl_pin_desc u300_pads[] = {
 struct u300_pmx {
        struct device *dev;
        struct pinctrl_dev *pctl;
-       u32 phybase;
-       u32 physize;
        void __iomem *virtbase;
 };
 
@@ -1054,9 +1052,8 @@ static struct pinctrl_gpio_range *u300_match_gpio_range(unsigned pin)
        return NULL;
 }
 
-int u300_pin_config_get(struct pinctrl_dev *pctldev,
-                       unsigned pin,
-                       unsigned long *config)
+static int u300_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+                              unsigned long *config)
 {
        struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
 
@@ -1069,9 +1066,8 @@ int u300_pin_config_get(struct pinctrl_dev *pctldev,
                                    config);
 }
 
-int u300_pin_config_set(struct pinctrl_dev *pctldev,
-                       unsigned pin,
-                       unsigned long config)
+static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
+                              unsigned long config)
 {
        struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
        int ret;
@@ -1110,7 +1106,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
        struct u300_pmx *upmx;
        struct resource *res;
        struct gpio_chip *gpio_chip = dev_get_platdata(&pdev->dev);
-       int ret;
        int i;
 
        /* Create state holders etc for this driver */
@@ -1123,26 +1118,15 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
                return -ENOENT;
-       upmx->phybase = res->start;
-       upmx->physize = resource_size(res);
-
-       if (request_mem_region(upmx->phybase, upmx->physize,
-                              DRIVER_NAME) == NULL) {
-               ret = -ENOMEM;
-               goto out_no_memregion;
-       }
 
-       upmx->virtbase = ioremap(upmx->phybase, upmx->physize);
-       if (!upmx->virtbase) {
-               ret = -ENOMEM;
-               goto out_no_remap;
-       }
+       upmx->virtbase = devm_request_and_ioremap(&pdev->dev, res);
+       if (!upmx->virtbase)
+               return -ENOMEM;
 
        upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx);
        if (!upmx->pctl) {
                dev_err(&pdev->dev, "could not register U300 pinmux driver\n");
-               ret = -EINVAL;
-               goto out_no_pmx;
+               return -EINVAL;
        }
 
        /* We will handle a range of GPIO pins */
@@ -1156,14 +1140,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
        dev_info(&pdev->dev, "initialized U300 pin control driver\n");
 
        return 0;
-
-out_no_pmx:
-       iounmap(upmx->virtbase);
-out_no_remap:
-       platform_set_drvdata(pdev, NULL);
-out_no_memregion:
-       release_mem_region(upmx->phybase, upmx->physize);
-       return ret;
 }
 
 static int __devexit u300_pmx_remove(struct platform_device *pdev)
@@ -1171,8 +1147,6 @@ static int __devexit u300_pmx_remove(struct platform_device *pdev)
        struct u300_pmx *upmx = platform_get_drvdata(pdev);
 
        pinctrl_unregister(upmx->pctl);
-       iounmap(upmx->virtbase);
-       release_mem_region(upmx->phybase, upmx->physize);
        platform_set_drvdata(pdev, NULL);
 
        return 0;
index 9301a7a..0ef01ee 100644 (file)
@@ -314,14 +314,11 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
 {
        struct pinctrl_dev *pctldev = setting->pctldev;
        const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
-       const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
        char const * const *groups;
        unsigned num_groups;
        int ret;
        const char *group;
        int i;
-       const unsigned *pins;
-       unsigned num_pins;
 
        if (!pmxops) {
                dev_err(pctldev->dev, "does not support mux function\n");
@@ -376,53 +373,12 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
        }
        setting->data.mux.group = ret;
 
-       ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, &pins,
-                                     &num_pins);
-       if (ret) {
-               dev_err(pctldev->dev,
-                       "could not get pins for device %s group selector %d\n",
-                       pinctrl_dev_get_name(pctldev), setting->data.mux.group);
-                       return -ENODEV;
-       }
-
-       /* Try to allocate all pins in this group, one by one */
-       for (i = 0; i < num_pins; i++) {
-               ret = pin_request(pctldev, pins[i], map->dev_name, NULL);
-               if (ret) {
-                       dev_err(pctldev->dev,
-                               "could not request pin %d on device %s\n",
-                               pins[i], pinctrl_dev_get_name(pctldev));
-                       /* On error release all taken pins */
-                       i--; /* this pin just failed */
-                       for (; i >= 0; i--)
-                               pin_free(pctldev, pins[i], NULL);
-                       return -ENODEV;
-               }
-       }
-
        return 0;
 }
 
 void pinmux_free_setting(struct pinctrl_setting const *setting)
 {
-       struct pinctrl_dev *pctldev = setting->pctldev;
-       const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
-       const unsigned *pins;
-       unsigned num_pins;
-       int ret;
-       int i;
-
-       ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,
-                                     &pins, &num_pins);
-       if (ret) {
-               dev_err(pctldev->dev,
-                       "could not get pins for device %s group selector %d\n",
-                       pinctrl_dev_get_name(pctldev), setting->data.mux.group);
-               return;
-       }
-
-       for (i = 0; i < num_pins; i++)
-               pin_free(pctldev, pins[i], NULL);
+       /* This function is currently unused */
 }
 
 int pinmux_enable_setting(struct pinctrl_setting const *setting)
@@ -446,6 +402,22 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting)
                num_pins = 0;
        }
 
+       /* Try to allocate all pins in this group, one by one */
+       for (i = 0; i < num_pins; i++) {
+               ret = pin_request(pctldev, pins[i], setting->dev_name, NULL);
+               if (ret) {
+                       dev_err(pctldev->dev,
+                               "could not request pin %d on device %s\n",
+                               pins[i], pinctrl_dev_get_name(pctldev));
+                       /* On error release all taken pins */
+                       i--; /* this pin just failed */
+                       for (; i >= 0; i--)
+                               pin_free(pctldev, pins[i], NULL);
+                       return -ENODEV;
+               }
+       }
+
+       /* Now that we have acquired the pins, encode the mux setting */
        for (i = 0; i < num_pins; i++) {
                desc = pin_desc_get(pctldev, pins[i]);
                if (desc == NULL) {
@@ -482,6 +454,7 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting)
                num_pins = 0;
        }
 
+       /* Flag the descs that no setting is active */
        for (i = 0; i < num_pins; i++) {
                desc = pin_desc_get(pctldev, pins[i]);
                if (desc == NULL) {
@@ -493,6 +466,10 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting)
                desc->mux_setting = NULL;
        }
 
+       /* And release the pins */
+       for (i = 0; i < num_pins; i++)
+               pin_free(pctldev, pins[i], NULL);
+
        if (ops->disable)
                ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group);
 }
index 9155879..04d93e6 100644 (file)
@@ -25,20 +25,31 @@ config PINCTRL_SPEAR310
        bool "ST Microelectronics SPEAr310 SoC pin controller driver"
        depends on MACH_SPEAR310
        select PINCTRL_SPEAR3XX
+       select PINCTRL_SPEAR_PLGPIO
 
 config PINCTRL_SPEAR320
        bool "ST Microelectronics SPEAr320 SoC pin controller driver"
        depends on MACH_SPEAR320
        select PINCTRL_SPEAR3XX
+       select PINCTRL_SPEAR_PLGPIO
 
 config PINCTRL_SPEAR1310
        bool "ST Microelectronics SPEAr1310 SoC pin controller driver"
        depends on MACH_SPEAR1310
        select PINCTRL_SPEAR
+       select PINCTRL_SPEAR_PLGPIO
 
 config PINCTRL_SPEAR1340
        bool "ST Microelectronics SPEAr1340 SoC pin controller driver"
        depends on MACH_SPEAR1340
        select PINCTRL_SPEAR
+       select PINCTRL_SPEAR_PLGPIO
+
+config PINCTRL_SPEAR_PLGPIO
+       bool "SPEAr SoC PLGPIO Controller"
+       depends on GPIOLIB && PINCTRL_SPEAR
+       help
+         Say yes here to support PLGPIO controller on ST Microelectronics SPEAr
+         SoCs.
 
 endif
index b28a7ba..0e400eb 100644 (file)
@@ -1,5 +1,6 @@
 # SPEAr pinmux support
 
+obj-$(CONFIG_PINCTRL_SPEAR_PLGPIO)     += pinctrl-plgpio.o
 obj-$(CONFIG_PINCTRL_SPEAR)    += pinctrl-spear.o
 obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o
 obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o
diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c
new file mode 100644 (file)
index 0000000..1044ad3
--- /dev/null
@@ -0,0 +1,746 @@
+/*
+ * SPEAr platform PLGPIO driver
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/spinlock.h>
+#include <asm/mach/irq.h>
+
+#define MAX_GPIO_PER_REG               32
+#define PIN_OFFSET(pin)                        (pin % MAX_GPIO_PER_REG)
+#define REG_OFFSET(base, reg, pin)     (base + reg + (pin / MAX_GPIO_PER_REG) \
+                                                       * sizeof(int *))
+
+/*
+ * plgpio pins in all machines are not one to one mapped, bitwise with registers
+ * bits. These set of macros define register masks for which below functions
+ * (pin_to_offset and offset_to_pin) are required to be called.
+ */
+#define PTO_ENB_REG            0x001
+#define PTO_WDATA_REG          0x002
+#define PTO_DIR_REG            0x004
+#define PTO_IE_REG             0x008
+#define PTO_RDATA_REG          0x010
+#define PTO_MIS_REG            0x020
+
+struct plgpio_regs {
+       u32 enb;                /* enable register */
+       u32 wdata;              /* write data register */
+       u32 dir;                /* direction set register */
+       u32 rdata;              /* read data register */
+       u32 ie;                 /* interrupt enable register */
+       u32 mis;                /* mask interrupt status register */
+       u32 eit;                /* edge interrupt type */
+};
+
+/*
+ * struct plgpio: plgpio driver specific structure
+ *
+ * lock: lock for guarding gpio registers
+ * base: base address of plgpio block
+ * irq_base: irq number of plgpio0
+ * chip: gpio framework specific chip information structure
+ * p2o: function ptr for pin to offset conversion. This is required only for
+ *     machines where mapping b/w pin and offset is not 1-to-1.
+ * o2p: function ptr for offset to pin conversion. This is required only for
+ *     machines where mapping b/w pin and offset is not 1-to-1.
+ * p2o_regs: mask of registers for which p2o and o2p are applicable
+ * regs: register offsets
+ * csave_regs: context save registers for standby/sleep/hibernate cases
+ */
+struct plgpio {
+       spinlock_t              lock;
+       void __iomem            *base;
+       struct clk              *clk;
+       unsigned                irq_base;
+       struct irq_domain       *irq_domain;
+       struct gpio_chip        chip;
+       int                     (*p2o)(int pin);        /* pin_to_offset */
+       int                     (*o2p)(int offset);     /* offset_to_pin */
+       u32                     p2o_regs;
+       struct plgpio_regs      regs;
+#ifdef CONFIG_PM
+       struct plgpio_regs      *csave_regs;
+#endif
+};
+
+/* register manipulation inline functions */
+static inline u32 is_plgpio_set(void __iomem *base, u32 pin, u32 reg)
+{
+       u32 offset = PIN_OFFSET(pin);
+       void __iomem *reg_off = REG_OFFSET(base, reg, pin);
+       u32 val = readl_relaxed(reg_off);
+
+       return !!(val & (1 << offset));
+}
+
+static inline void plgpio_reg_set(void __iomem *base, u32 pin, u32 reg)
+{
+       u32 offset = PIN_OFFSET(pin);
+       void __iomem *reg_off = REG_OFFSET(base, reg, pin);
+       u32 val = readl_relaxed(reg_off);
+
+       writel_relaxed(val | (1 << offset), reg_off);
+}
+
+static inline void plgpio_reg_reset(void __iomem *base, u32 pin, u32 reg)
+{
+       u32 offset = PIN_OFFSET(pin);
+       void __iomem *reg_off = REG_OFFSET(base, reg, pin);
+       u32 val = readl_relaxed(reg_off);
+
+       writel_relaxed(val & ~(1 << offset), reg_off);
+}
+
+/* gpio framework specific routines */
+static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+       unsigned long flags;
+
+       /* get correct offset for "offset" pin */
+       if (plgpio->p2o && (plgpio->p2o_regs & PTO_DIR_REG)) {
+               offset = plgpio->p2o(offset);
+               if (offset == -1)
+                       return -EINVAL;
+       }
+
+       spin_lock_irqsave(&plgpio->lock, flags);
+       plgpio_reg_set(plgpio->base, offset, plgpio->regs.dir);
+       spin_unlock_irqrestore(&plgpio->lock, flags);
+
+       return 0;
+}
+
+static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset,
+               int value)
+{
+       struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+       unsigned long flags;
+       unsigned dir_offset = offset, wdata_offset = offset, tmp;
+
+       /* get correct offset for "offset" pin */
+       if (plgpio->p2o && (plgpio->p2o_regs & (PTO_DIR_REG | PTO_WDATA_REG))) {
+               tmp = plgpio->p2o(offset);
+               if (tmp == -1)
+                       return -EINVAL;
+
+               if (plgpio->p2o_regs & PTO_DIR_REG)
+                       dir_offset = tmp;
+               if (plgpio->p2o_regs & PTO_WDATA_REG)
+                       wdata_offset = tmp;
+       }
+
+       spin_lock_irqsave(&plgpio->lock, flags);
+       if (value)
+               plgpio_reg_set(plgpio->base, wdata_offset,
+                               plgpio->regs.wdata);
+       else
+               plgpio_reg_reset(plgpio->base, wdata_offset,
+                               plgpio->regs.wdata);
+
+       plgpio_reg_reset(plgpio->base, dir_offset, plgpio->regs.dir);
+       spin_unlock_irqrestore(&plgpio->lock, flags);
+
+       return 0;
+}
+
+static int plgpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+       struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+
+       if (offset >= chip->ngpio)
+               return -EINVAL;
+
+       /* get correct offset for "offset" pin */
+       if (plgpio->p2o && (plgpio->p2o_regs & PTO_RDATA_REG)) {
+               offset = plgpio->p2o(offset);
+               if (offset == -1)
+                       return -EINVAL;
+       }
+
+       return is_plgpio_set(plgpio->base, offset, plgpio->regs.rdata);
+}
+
+static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+
+       if (offset >= chip->ngpio)
+               return;
+
+       /* get correct offset for "offset" pin */
+       if (plgpio->p2o && (plgpio->p2o_regs & PTO_WDATA_REG)) {
+               offset = plgpio->p2o(offset);
+               if (offset == -1)
+                       return;
+       }
+
+       if (value)
+               plgpio_reg_set(plgpio->base, offset, plgpio->regs.wdata);
+       else
+               plgpio_reg_reset(plgpio->base, offset, plgpio->regs.wdata);
+}
+
+static int plgpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+       int gpio = chip->base + offset;
+       unsigned long flags;
+       int ret = 0;
+
+       if (offset >= chip->ngpio)
+               return -EINVAL;
+
+       ret = pinctrl_request_gpio(gpio);
+       if (ret)
+               return ret;
+
+       if (!IS_ERR(plgpio->clk)) {
+               ret = clk_prepare_enable(plgpio->clk);
+               if (ret)
+                       goto err0;
+       }
+
+       if (plgpio->regs.enb == -1)
+               return 0;
+
+       /*
+        * put gpio in IN mode before enabling it. This make enabling gpio safe
+        */
+       ret = plgpio_direction_input(chip, offset);
+       if (ret)
+               goto err1;
+
+       /* get correct offset for "offset" pin */
+       if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) {
+               offset = plgpio->p2o(offset);
+               if (offset == -1) {
+                       ret = -EINVAL;
+                       goto err1;
+               }
+       }
+
+       spin_lock_irqsave(&plgpio->lock, flags);
+       plgpio_reg_set(plgpio->base, offset, plgpio->regs.enb);
+       spin_unlock_irqrestore(&plgpio->lock, flags);
+       return 0;
+
+err1:
+       clk_disable_unprepare(plgpio->clk);
+err0:
+       pinctrl_free_gpio(gpio);
+       return ret;
+}
+
+static void plgpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+       int gpio = chip->base + offset;
+       unsigned long flags;
+
+       if (offset >= chip->ngpio)
+               return;
+
+       if (plgpio->regs.enb == -1)
+               goto disable_clk;
+
+       /* get correct offset for "offset" pin */
+       if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) {
+               offset = plgpio->p2o(offset);
+               if (offset == -1)
+                       return;
+       }
+
+       spin_lock_irqsave(&plgpio->lock, flags);
+       plgpio_reg_reset(plgpio->base, offset, plgpio->regs.enb);
+       spin_unlock_irqrestore(&plgpio->lock, flags);
+
+disable_clk:
+       if (!IS_ERR(plgpio->clk))
+               clk_disable_unprepare(plgpio->clk);
+
+       pinctrl_free_gpio(gpio);
+}
+
+static int plgpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+
+       if (plgpio->irq_base < 0)
+               return -EINVAL;
+
+       return irq_find_mapping(plgpio->irq_domain, offset);
+}
+
+/* PLGPIO IRQ */
+static void plgpio_irq_disable(struct irq_data *d)
+{
+       struct plgpio *plgpio = irq_data_get_irq_chip_data(d);
+       int offset = d->irq - plgpio->irq_base;
+       unsigned long flags;
+
+       /* get correct offset for "offset" pin */
+       if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) {
+               offset = plgpio->p2o(offset);
+               if (offset == -1)
+                       return;
+       }
+
+       spin_lock_irqsave(&plgpio->lock, flags);
+       plgpio_reg_set(plgpio->base, offset, plgpio->regs.ie);
+       spin_unlock_irqrestore(&plgpio->lock, flags);
+}
+
+static void plgpio_irq_enable(struct irq_data *d)
+{
+       struct plgpio *plgpio = irq_data_get_irq_chip_data(d);
+       int offset = d->irq - plgpio->irq_base;
+       unsigned long flags;
+
+       /* get correct offset for "offset" pin */
+       if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) {
+               offset = plgpio->p2o(offset);
+               if (offset == -1)
+                       return;
+       }
+
+       spin_lock_irqsave(&plgpio->lock, flags);
+       plgpio_reg_reset(plgpio->base, offset, plgpio->regs.ie);
+       spin_unlock_irqrestore(&plgpio->lock, flags);
+}
+
+static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger)
+{
+       struct plgpio *plgpio = irq_data_get_irq_chip_data(d);
+       int offset = d->irq - plgpio->irq_base;
+       void __iomem *reg_off;
+       unsigned int supported_type = 0, val;
+
+       if (offset >= plgpio->chip.ngpio)
+               return -EINVAL;
+
+       if (plgpio->regs.eit == -1)
+               supported_type = IRQ_TYPE_LEVEL_HIGH;
+       else
+               supported_type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+
+       if (!(trigger & supported_type))
+               return -EINVAL;
+
+       if (plgpio->regs.eit == -1)
+               return 0;
+
+       reg_off = REG_OFFSET(plgpio->base, plgpio->regs.eit, offset);
+       val = readl_relaxed(reg_off);
+
+       offset = PIN_OFFSET(offset);
+       if (trigger & IRQ_TYPE_EDGE_RISING)
+               writel_relaxed(val | (1 << offset), reg_off);
+       else
+               writel_relaxed(val & ~(1 << offset), reg_off);
+
+       return 0;
+}
+
+static struct irq_chip plgpio_irqchip = {
+       .name           = "PLGPIO",
+       .irq_enable     = plgpio_irq_enable,
+       .irq_disable    = plgpio_irq_disable,
+       .irq_set_type   = plgpio_irq_set_type,
+};
+
+static void plgpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+       struct plgpio *plgpio = irq_get_handler_data(irq);
+       struct irq_chip *irqchip = irq_desc_get_chip(desc);
+       int regs_count, count, pin, offset, i = 0;
+       unsigned long pending;
+
+       count = plgpio->chip.ngpio;
+       regs_count = DIV_ROUND_UP(count, MAX_GPIO_PER_REG);
+
+       chained_irq_enter(irqchip, desc);
+       /* check all plgpio MIS registers for a possible interrupt */
+       for (; i < regs_count; i++) {
+               pending = readl_relaxed(plgpio->base + plgpio->regs.mis +
+                               i * sizeof(int *));
+               if (!pending)
+                       continue;
+
+               /* clear interrupts */
+               writel_relaxed(~pending, plgpio->base + plgpio->regs.mis +
+                               i * sizeof(int *));
+               /*
+                * clear extra bits in last register having gpios < MAX/REG
+                * ex: Suppose there are max 102 plgpios. then last register
+                * must have only (102 - MAX_GPIO_PER_REG * 3) = 6 relevant bits
+                * so, we must not take other 28 bits into consideration for
+                * checking interrupt. so clear those bits.
+                */
+               count = count - i * MAX_GPIO_PER_REG;
+               if (count < MAX_GPIO_PER_REG)
+                       pending &= (1 << count) - 1;
+
+               for_each_set_bit(offset, &pending, MAX_GPIO_PER_REG) {
+                       /* get correct pin for "offset" */
+                       if (plgpio->o2p && (plgpio->p2o_regs & PTO_MIS_REG)) {
+                               pin = plgpio->o2p(offset);
+                               if (pin == -1)
+                                       continue;
+                       } else
+                               pin = offset;
+
+                       /* get correct irq line number */
+                       pin = i * MAX_GPIO_PER_REG + pin;
+                       generic_handle_irq(plgpio_to_irq(&plgpio->chip, pin));
+               }
+       }
+       chained_irq_exit(irqchip, desc);
+}
+
+/*
+ * pin to offset and offset to pin converter functions
+ *
+ * In spear310 there is inconsistency among bit positions in plgpio regiseters,
+ * for different plgpio pins. For example: for pin 27, bit offset is 23, pin
+ * 28-33 are not supported, pin 95 has offset bit 95, bit 100 has offset bit 1
+ */
+static int spear310_p2o(int pin)
+{
+       int offset = pin;
+
+       if (pin <= 27)
+               offset += 4;
+       else if (pin <= 33)
+               offset = -1;
+       else if (pin <= 97)
+               offset -= 2;
+       else if (pin <= 101)
+               offset = 101 - pin;
+       else
+               offset = -1;
+
+       return offset;
+}
+
+int spear310_o2p(int offset)
+{
+       if (offset <= 3)
+               return 101 - offset;
+       else if (offset <= 31)
+               return offset - 4;
+       else
+               return offset + 2;
+}
+
+static int __devinit plgpio_probe_dt(struct platform_device *pdev,
+               struct plgpio *plgpio)
+{
+       struct device_node *np = pdev->dev.of_node;
+       int ret = -EINVAL;
+       u32 val;
+
+       if (of_machine_is_compatible("st,spear310")) {
+               plgpio->p2o = spear310_p2o;
+               plgpio->o2p = spear310_o2p;
+               plgpio->p2o_regs = PTO_WDATA_REG | PTO_DIR_REG | PTO_IE_REG |
+                       PTO_RDATA_REG | PTO_MIS_REG;
+       }
+
+       if (!of_property_read_u32(np, "st-plgpio,ngpio", &val)) {
+               plgpio->chip.ngpio = val;
+       } else {
+               dev_err(&pdev->dev, "DT: Invalid ngpio field\n");
+               goto end;
+       }
+
+       if (!of_property_read_u32(np, "st-plgpio,enb-reg", &val))
+               plgpio->regs.enb = val;
+       else
+               plgpio->regs.enb = -1;
+
+       if (!of_property_read_u32(np, "st-plgpio,wdata-reg", &val)) {
+               plgpio->regs.wdata = val;
+       } else {
+               dev_err(&pdev->dev, "DT: Invalid wdata reg\n");
+               goto end;
+       }
+
+       if (!of_property_read_u32(np, "st-plgpio,dir-reg", &val)) {
+               plgpio->regs.dir = val;
+       } else {
+               dev_err(&pdev->dev, "DT: Invalid dir reg\n");
+               goto end;
+       }
+
+       if (!of_property_read_u32(np, "st-plgpio,ie-reg", &val)) {
+               plgpio->regs.ie = val;
+       } else {
+               dev_err(&pdev->dev, "DT: Invalid ie reg\n");
+               goto end;
+       }
+
+       if (!of_property_read_u32(np, "st-plgpio,rdata-reg", &val)) {
+               plgpio->regs.rdata = val;
+       } else {
+               dev_err(&pdev->dev, "DT: Invalid rdata reg\n");
+               goto end;
+       }
+
+       if (!of_property_read_u32(np, "st-plgpio,mis-reg", &val)) {
+               plgpio->regs.mis = val;
+       } else {
+               dev_err(&pdev->dev, "DT: Invalid mis reg\n");
+               goto end;
+       }
+
+       if (!of_property_read_u32(np, "st-plgpio,eit-reg", &val))
+               plgpio->regs.eit = val;
+       else
+               plgpio->regs.eit = -1;
+
+       return 0;
+
+end:
+       return ret;
+}
+static int __devinit plgpio_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct plgpio *plgpio;
+       struct resource *res;
+       int ret, irq, i;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n");
+               return -EBUSY;
+       }
+
+       plgpio = devm_kzalloc(&pdev->dev, sizeof(*plgpio), GFP_KERNEL);
+       if (!plgpio) {
+               dev_err(&pdev->dev, "memory allocation fail\n");
+               return -ENOMEM;
+       }
+
+       plgpio->base = devm_request_and_ioremap(&pdev->dev, res);
+       if (!plgpio->base) {
+               dev_err(&pdev->dev, "request and ioremap fail\n");
+               return -ENOMEM;
+       }
+
+       ret = plgpio_probe_dt(pdev, plgpio);
+       if (ret) {
+               dev_err(&pdev->dev, "DT probe failed\n");
+               return ret;
+       }
+
+       plgpio->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(plgpio->clk))
+               dev_warn(&pdev->dev, "clk_get() failed, work without it\n");
+
+#ifdef CONFIG_PM
+       plgpio->csave_regs = devm_kzalloc(&pdev->dev,
+                       sizeof(*plgpio->csave_regs) *
+                       DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG),
+                       GFP_KERNEL);
+       if (!plgpio->csave_regs) {
+               dev_err(&pdev->dev, "csave registers memory allocation fail\n");
+               return -ENOMEM;
+       }
+#endif
+
+       platform_set_drvdata(pdev, plgpio);
+       spin_lock_init(&plgpio->lock);
+
+       plgpio->irq_base = -1;
+       plgpio->chip.base = -1;
+       plgpio->chip.request = plgpio_request;
+       plgpio->chip.free = plgpio_free;
+       plgpio->chip.direction_input = plgpio_direction_input;
+       plgpio->chip.direction_output = plgpio_direction_output;
+       plgpio->chip.get = plgpio_get_value;
+       plgpio->chip.set = plgpio_set_value;
+       plgpio->chip.to_irq = plgpio_to_irq;
+       plgpio->chip.label = dev_name(&pdev->dev);
+       plgpio->chip.dev = &pdev->dev;
+       plgpio->chip.owner = THIS_MODULE;
+
+       ret = gpiochip_add(&plgpio->chip);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to add gpio chip\n");
+               return ret;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_info(&pdev->dev, "irqs not supported\n");
+               return 0;
+       }
+
+       plgpio->irq_base = irq_alloc_descs(-1, 0, plgpio->chip.ngpio, 0);
+       if (IS_ERR_VALUE(plgpio->irq_base)) {
+               /* we would not support irq for gpio */
+               dev_warn(&pdev->dev, "couldn't allocate irq base\n");
+               return 0;
+       }
+
+       plgpio->irq_domain = irq_domain_add_legacy(np, plgpio->chip.ngpio,
+                       plgpio->irq_base, 0, &irq_domain_simple_ops, NULL);
+       if (WARN_ON(!plgpio->irq_domain)) {
+               dev_err(&pdev->dev, "irq domain init failed\n");
+               irq_free_descs(plgpio->irq_base, plgpio->chip.ngpio);
+               ret = -ENXIO;
+               goto remove_gpiochip;
+       }
+
+       irq_set_chained_handler(irq, plgpio_irq_handler);
+       for (i = 0; i < plgpio->chip.ngpio; i++) {
+               irq_set_chip_and_handler(i + plgpio->irq_base, &plgpio_irqchip,
+                               handle_simple_irq);
+               set_irq_flags(i + plgpio->irq_base, IRQF_VALID);
+               irq_set_chip_data(i + plgpio->irq_base, plgpio);
+       }
+
+       irq_set_handler_data(irq, plgpio);
+       dev_info(&pdev->dev, "PLGPIO registered with IRQs\n");
+
+       return 0;
+
+remove_gpiochip:
+       dev_info(&pdev->dev, "Remove gpiochip\n");
+       if (gpiochip_remove(&plgpio->chip))
+               dev_err(&pdev->dev, "unable to remove gpiochip\n");
+
+       return ret;
+}
+
+#ifdef CONFIG_PM
+static int plgpio_suspend(struct device *dev)
+{
+       struct plgpio *plgpio = dev_get_drvdata(dev);
+       int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG);
+       void __iomem *off;
+
+       for (i = 0; i < reg_count; i++) {
+               off = plgpio->base + i * sizeof(int *);
+
+               if (plgpio->regs.enb != -1)
+                       plgpio->csave_regs[i].enb =
+                               readl_relaxed(plgpio->regs.enb + off);
+               if (plgpio->regs.eit != -1)
+                       plgpio->csave_regs[i].eit =
+                               readl_relaxed(plgpio->regs.eit + off);
+               plgpio->csave_regs[i].wdata = readl_relaxed(plgpio->regs.wdata +
+                               off);
+               plgpio->csave_regs[i].dir = readl_relaxed(plgpio->regs.dir +
+                               off);
+               plgpio->csave_regs[i].ie = readl_relaxed(plgpio->regs.ie + off);
+       }
+
+       return 0;
+}
+
+/*
+ * This is used to correct the values in end registers. End registers contain
+ * extra bits that might be used for other purpose in platform. So, we shouldn't
+ * overwrite these bits. This macro, reads given register again, preserves other
+ * bit values (non-plgpio bits), and retain captured value (plgpio bits).
+ */
+#define plgpio_prepare_reg(__reg, _off, _mask, _tmp)           \
+{                                                              \
+       _tmp = readl_relaxed(plgpio->regs.__reg + _off);                \
+       _tmp &= ~_mask;                                         \
+       plgpio->csave_regs[i].__reg =                           \
+               _tmp | (plgpio->csave_regs[i].__reg & _mask);   \
+}
+
+static int plgpio_resume(struct device *dev)
+{
+       struct plgpio *plgpio = dev_get_drvdata(dev);
+       int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG);
+       void __iomem *off;
+       u32 mask, tmp;
+
+       for (i = 0; i < reg_count; i++) {
+               off = plgpio->base + i * sizeof(int *);
+
+               if (i == reg_count - 1) {
+                       mask = (1 << (plgpio->chip.ngpio - i *
+                                               MAX_GPIO_PER_REG)) - 1;
+
+                       if (plgpio->regs.enb != -1)
+                               plgpio_prepare_reg(enb, off, mask, tmp);
+
+                       if (plgpio->regs.eit != -1)
+                               plgpio_prepare_reg(eit, off, mask, tmp);
+
+                       plgpio_prepare_reg(wdata, off, mask, tmp);
+                       plgpio_prepare_reg(dir, off, mask, tmp);
+                       plgpio_prepare_reg(ie, off, mask, tmp);
+               }
+
+               writel_relaxed(plgpio->csave_regs[i].wdata, plgpio->regs.wdata +
+                               off);
+               writel_relaxed(plgpio->csave_regs[i].dir, plgpio->regs.dir +
+                               off);
+
+               if (plgpio->regs.eit != -1)
+                       writel_relaxed(plgpio->csave_regs[i].eit,
+                                       plgpio->regs.eit + off);
+
+               writel_relaxed(plgpio->csave_regs[i].ie, plgpio->regs.ie + off);
+
+               if (plgpio->regs.enb != -1)
+                       writel_relaxed(plgpio->csave_regs[i].enb,
+                                       plgpio->regs.enb + off);
+       }
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(plgpio_dev_pm_ops, plgpio_suspend, plgpio_resume);
+
+static const struct of_device_id plgpio_of_match[] = {
+       { .compatible = "st,spear-plgpio" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, plgpio_of_match);
+
+static struct platform_driver plgpio_driver = {
+       .probe = plgpio_probe,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "spear-plgpio",
+               .pm = &plgpio_dev_pm_ops,
+               .of_match_table = of_match_ptr(plgpio_of_match),
+       },
+};
+
+static int __init plgpio_init(void)
+{
+       return platform_driver_register(&plgpio_driver);
+}
+subsys_initcall(plgpio_init);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
+MODULE_DESCRIPTION("ST Microlectronics SPEAr PLGPIO driver");
+MODULE_LICENSE("GPL");
index 5d4f44f..cbca6dc 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_gpio.h>
 #include <linux/pinctrl/machine.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
@@ -38,6 +39,28 @@ static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg)
        writel_relaxed(val, pmx->vbase + reg);
 }
 
+static void muxregs_endisable(struct spear_pmx *pmx,
+               struct spear_muxreg *muxregs, u8 count, bool enable)
+{
+       struct spear_muxreg *muxreg;
+       u32 val, temp, j;
+
+       for (j = 0; j < count; j++) {
+               muxreg = &muxregs[j];
+
+               val = pmx_readl(pmx, muxreg->reg);
+               val &= ~muxreg->mask;
+
+               if (enable)
+                       temp = muxreg->val;
+               else
+                       temp = ~muxreg->val;
+
+               val |= muxreg->mask & temp;
+               pmx_writel(pmx, val, muxreg->reg);
+       }
+}
+
 static int set_mode(struct spear_pmx *pmx, int mode)
 {
        struct spear_pmx_mode *pmx_mode = NULL;
@@ -70,6 +93,17 @@ static int set_mode(struct spear_pmx *pmx, int mode)
        return 0;
 }
 
+void __devinit
+pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
+               unsigned count, u16 reg)
+{
+       int i = 0, j = 0;
+
+       for (; i < count; i++)
+               for (; j < gpio_pingroup[i].nmuxregs; j++)
+                       gpio_pingroup[i].muxregs[j].reg = reg;
+}
+
 void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg)
 {
        struct spear_pingroup *pgroup;
@@ -216,9 +250,7 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev,
        struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
        const struct spear_pingroup *pgroup;
        const struct spear_modemux *modemux;
-       struct spear_muxreg *muxreg;
-       u32 val, temp;
-       int i, j;
+       int i;
        bool found = false;
 
        pgroup = pmx->machdata->groups[group];
@@ -233,20 +265,8 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev,
                }
 
                found = true;
-               for (j = 0; j < modemux->nmuxregs; j++) {
-                       muxreg = &modemux->muxregs[j];
-
-                       val = pmx_readl(pmx, muxreg->reg);
-                       val &= ~muxreg->mask;
-
-                       if (enable)
-                               temp = muxreg->val;
-                       else
-                               temp = ~muxreg->val;
-
-                       val |= temp;
-                       pmx_writel(pmx, val, muxreg->reg);
-               }
+               muxregs_endisable(pmx, modemux->muxregs, modemux->nmuxregs,
+                               enable);
        }
 
        if (!found) {
@@ -270,12 +290,65 @@ static void spear_pinctrl_disable(struct pinctrl_dev *pctldev,
        spear_pinctrl_endisable(pctldev, function, group, false);
 }
 
+/* gpio with pinmux */
+static struct spear_gpio_pingroup *get_gpio_pingroup(struct spear_pmx *pmx,
+               unsigned pin)
+{
+       struct spear_gpio_pingroup *gpio_pingroup;
+       int i = 0, j;
+
+       if (!pmx->machdata->gpio_pingroups)
+               return NULL;
+
+       for (; i < pmx->machdata->ngpio_pingroups; i++) {
+               gpio_pingroup = &pmx->machdata->gpio_pingroups[i];
+
+               for (j = 0; j < gpio_pingroup->npins; j++) {
+                       if (gpio_pingroup->pins[j] == pin)
+                               return gpio_pingroup;
+               }
+       }
+
+       return ERR_PTR(-EINVAL);
+}
+
+static int gpio_request_endisable(struct pinctrl_dev *pctldev,
+               struct pinctrl_gpio_range *range, unsigned offset, bool enable)
+{
+       struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       struct spear_gpio_pingroup *gpio_pingroup;
+
+       gpio_pingroup = get_gpio_pingroup(pmx, offset);
+       if (IS_ERR(gpio_pingroup))
+               return PTR_ERR(gpio_pingroup);
+
+       if (gpio_pingroup)
+               muxregs_endisable(pmx, gpio_pingroup->muxregs,
+                               gpio_pingroup->nmuxregs, enable);
+
+       return 0;
+}
+
+static int gpio_request_enable(struct pinctrl_dev *pctldev,
+               struct pinctrl_gpio_range *range, unsigned offset)
+{
+       return gpio_request_endisable(pctldev, range, offset, true);
+}
+
+static void gpio_disable_free(struct pinctrl_dev *pctldev,
+               struct pinctrl_gpio_range *range, unsigned offset)
+{
+       gpio_request_endisable(pctldev, range, offset, false);
+}
+
 static 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,
        .enable = spear_pinctrl_enable,
        .disable = spear_pinctrl_disable,
+       .gpio_request_enable = gpio_request_enable,
+       .gpio_disable_free = gpio_disable_free,
 };
 
 static struct pinctrl_desc spear_pinctrl_desc = {
index d950eb7..94f142c 100644 (file)
@@ -12,6 +12,7 @@
 #ifndef __PINMUX_SPEAR_H__
 #define __PINMUX_SPEAR_H__
 
+#include <linux/gpio.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/types.h>
 
@@ -46,6 +47,44 @@ struct spear_muxreg {
        u32 val;
 };
 
+struct spear_gpio_pingroup {
+       const unsigned *pins;
+       unsigned npins;
+       struct spear_muxreg *muxregs;
+       u8 nmuxregs;
+};
+
+/* ste: set to enable */
+#define DEFINE_MUXREG(__pins, __muxreg, __mask, __ste)         \
+static struct spear_muxreg __pins##_muxregs[] = {              \
+       {                                                       \
+               .reg = __muxreg,                                \
+               .mask = __mask,                                 \
+               .val = __ste ? __mask : 0,                      \
+       },                                                      \
+}
+
+#define DEFINE_2_MUXREG(__pins, __muxreg1, __muxreg2, __mask, __ste1, __ste2) \
+static struct spear_muxreg __pins##_muxregs[] = {              \
+       {                                                       \
+               .reg = __muxreg1,                               \
+               .mask = __mask,                                 \
+               .val = __ste1 ? __mask : 0,                     \
+       }, {                                                    \
+               .reg = __muxreg2,                               \
+               .mask = __mask,                                 \
+               .val = __ste2 ? __mask : 0,                     \
+       },                                                      \
+}
+
+#define GPIO_PINGROUP(__pins)                                  \
+       {                                                       \
+               .pins = __pins,                                 \
+               .npins = ARRAY_SIZE(__pins),                    \
+               .muxregs = __pins##_muxregs,                    \
+               .nmuxregs = ARRAY_SIZE(__pins##_muxregs),       \
+       }
+
 /**
  * struct spear_modemux - SPEAr mode mux configuration
  * @modes: mode ids supported by this group of muxregs
@@ -100,6 +139,8 @@ struct spear_function {
  * @nfunctions: The numbmer of entries in @functions.
  * @groups: An array describing all pin groups the pin SoC supports.
  * @ngroups: The numbmer of entries in @groups.
+ * @gpio_pingroups: gpio pingroups
+ * @ngpio_pingroups: gpio pingroups count
  *
  * @modes_supported: Does SoC support modes
  * @mode: mode configured from probe
@@ -113,6 +154,8 @@ struct spear_pinctrl_machdata {
        unsigned nfunctions;
        struct spear_pingroup **groups;
        unsigned ngroups;
+       struct spear_gpio_pingroup *gpio_pingroups;
+       unsigned ngpio_pingroups;
 
        bool modes_supported;
        u16 mode;
@@ -136,6 +179,9 @@ struct spear_pmx {
 
 /* exported routines */
 void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg);
+void __devinit
+pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
+               unsigned count, u16 reg);
 int __devinit spear_pinctrl_probe(struct platform_device *pdev,
                struct spear_pinctrl_machdata *machdata);
 int __devexit spear_pinctrl_remove(struct platform_device *pdev);
index d6cca8c..30134f7 100644 (file)
@@ -25,8 +25,8 @@ static const struct pinctrl_pin_desc spear1310_pins[] = {
 };
 
 /* registers */
-#define PERIP_CFG                                      0x32C
-       #define MCIF_SEL_SHIFT                          3
+#define PERIP_CFG                                      0x3B0
+       #define MCIF_SEL_SHIFT                          5
        #define MCIF_SEL_SD                             (0x1 << MCIF_SEL_SHIFT)
        #define MCIF_SEL_CF                             (0x2 << MCIF_SEL_SHIFT)
        #define MCIF_SEL_XD                             (0x3 << MCIF_SEL_SHIFT)
@@ -164,6 +164,10 @@ static const struct pinctrl_pin_desc spear1310_pins[] = {
        #define PMX_SSP0_CS0_MASK                       (1 << 29)
        #define PMX_SSP0_CS1_2_MASK                     (1 << 30)
 
+#define PAD_DIRECTION_SEL_0                            0x65C
+#define PAD_DIRECTION_SEL_1                            0x660
+#define PAD_DIRECTION_SEL_2                            0x664
+
 /* combined macros */
 #define PMX_GMII_MASK          (PMX_GMIICLK_MASK |                     \
                                PMX_GMIICOL_CRS_XFERER_MIITXCLK_MASK |  \
@@ -237,6 +241,10 @@ static struct spear_muxreg i2c0_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_I2C0_MASK,
                .val = PMX_I2C0_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_I2C0_MASK,
+               .val = PMX_I2C0_MASK,
        },
 };
 
@@ -269,6 +277,10 @@ static struct spear_muxreg ssp0_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_SSP0_MASK,
                .val = PMX_SSP0_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_SSP0_MASK,
+               .val = PMX_SSP0_MASK,
        },
 };
 
@@ -294,6 +306,10 @@ static struct spear_muxreg ssp0_cs0_muxreg[] = {
                .reg = PAD_FUNCTION_EN_2,
                .mask = PMX_SSP0_CS0_MASK,
                .val = PMX_SSP0_CS0_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_SSP0_CS0_MASK,
+               .val = PMX_SSP0_CS0_MASK,
        },
 };
 
@@ -319,6 +335,10 @@ static struct spear_muxreg ssp0_cs1_2_muxreg[] = {
                .reg = PAD_FUNCTION_EN_2,
                .mask = PMX_SSP0_CS1_2_MASK,
                .val = PMX_SSP0_CS1_2_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_SSP0_CS1_2_MASK,
+               .val = PMX_SSP0_CS1_2_MASK,
        },
 };
 
@@ -352,6 +372,10 @@ static struct spear_muxreg i2s0_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_I2S0_MASK,
                .val = PMX_I2S0_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_I2S0_MASK,
+               .val = PMX_I2S0_MASK,
        },
 };
 
@@ -384,6 +408,10 @@ static struct spear_muxreg i2s1_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_I2S1_MASK,
                .val = PMX_I2S1_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_I2S1_MASK,
+               .val = PMX_I2S1_MASK,
        },
 };
 
@@ -418,6 +446,10 @@ static struct spear_muxreg clcd_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_CLCD1_MASK,
                .val = PMX_CLCD1_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_CLCD1_MASK,
+               .val = PMX_CLCD1_MASK,
        },
 };
 
@@ -443,6 +475,10 @@ static struct spear_muxreg clcd_high_res_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_CLCD2_MASK,
                .val = PMX_CLCD2_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_CLCD2_MASK,
+               .val = PMX_CLCD2_MASK,
        },
 };
 
@@ -461,7 +497,7 @@ static struct spear_pingroup clcd_high_res_pingroup = {
        .nmodemuxs = ARRAY_SIZE(clcd_high_res_modemux),
 };
 
-static const char *const clcd_grps[] = { "clcd_grp", "clcd_high_res" };
+static const char *const clcd_grps[] = { "clcd_grp", "clcd_high_res_grp" };
 static struct spear_function clcd_function = {
        .name = "clcd",
        .groups = clcd_grps,
@@ -479,6 +515,14 @@ static struct spear_muxreg arm_gpio_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_EGPIO_1_GRP_MASK,
                .val = PMX_EGPIO_1_GRP_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_EGPIO_0_GRP_MASK,
+               .val = PMX_EGPIO_0_GRP_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_EGPIO_1_GRP_MASK,
+               .val = PMX_EGPIO_1_GRP_MASK,
        },
 };
 
@@ -511,6 +555,10 @@ static struct spear_muxreg smi_2_chips_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_SMI_MASK,
                .val = PMX_SMI_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_SMI_MASK,
+               .val = PMX_SMI_MASK,
        },
 };
 
@@ -539,6 +587,14 @@ static struct spear_muxreg smi_4_chips_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_SMINCS2_MASK | PMX_SMINCS3_MASK,
                .val = PMX_SMINCS2_MASK | PMX_SMINCS3_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_SMI_MASK,
+               .val = PMX_SMI_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_SMINCS2_MASK | PMX_SMINCS3_MASK,
+               .val = PMX_SMINCS2_MASK | PMX_SMINCS3_MASK,
        },
 };
 
@@ -573,6 +629,10 @@ static struct spear_muxreg gmii_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_GMII_MASK,
                .val = PMX_GMII_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_GMII_MASK,
+               .val = PMX_GMII_MASK,
        },
 };
 
@@ -615,6 +675,18 @@ static struct spear_muxreg rgmii_muxreg[] = {
                .reg = PAD_FUNCTION_EN_2,
                .mask = PMX_RGMII_REG2_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_RGMII_REG0_MASK,
+               .val = PMX_RGMII_REG0_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_RGMII_REG1_MASK,
+               .val = PMX_RGMII_REG1_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_RGMII_REG2_MASK,
+               .val = PMX_RGMII_REG2_MASK,
        },
 };
 
@@ -649,6 +721,10 @@ static struct spear_muxreg smii_0_1_2_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_SMII_0_1_2_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_SMII_0_1_2_MASK,
+               .val = PMX_SMII_0_1_2_MASK,
        },
 };
 
@@ -681,6 +757,10 @@ static struct spear_muxreg ras_mii_txclk_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_NFCE2_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_NFCE2_MASK,
+               .val = PMX_NFCE2_MASK,
        },
 };
 
@@ -721,6 +801,14 @@ static struct spear_muxreg nand_8bit_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_NAND8BIT_1_MASK,
                .val = PMX_NAND8BIT_1_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_NAND8BIT_0_MASK,
+               .val = PMX_NAND8BIT_0_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_NAND8BIT_1_MASK,
+               .val = PMX_NAND8BIT_1_MASK,
        },
 };
 
@@ -747,6 +835,10 @@ static struct spear_muxreg nand_16bit_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_NAND16BIT_1_MASK,
                .val = PMX_NAND16BIT_1_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_NAND16BIT_1_MASK,
+               .val = PMX_NAND16BIT_1_MASK,
        },
 };
 
@@ -772,6 +864,10 @@ static struct spear_muxreg nand_4_chips_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_NAND_4CHIPS_MASK,
                .val = PMX_NAND_4CHIPS_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_NAND_4CHIPS_MASK,
+               .val = PMX_NAND_4CHIPS_MASK,
        },
 };
 
@@ -833,6 +929,10 @@ static struct spear_muxreg keyboard_rowcol6_8_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_KBD_ROWCOL68_MASK,
                .val = PMX_KBD_ROWCOL68_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_KBD_ROWCOL68_MASK,
+               .val = PMX_KBD_ROWCOL68_MASK,
        },
 };
 
@@ -866,6 +966,10 @@ static struct spear_muxreg uart0_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_UART0_MASK,
                .val = PMX_UART0_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_UART0_MASK,
+               .val = PMX_UART0_MASK,
        },
 };
 
@@ -891,6 +995,10 @@ static struct spear_muxreg uart0_modem_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_UART0_MODEM_MASK,
                .val = PMX_UART0_MODEM_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_UART0_MODEM_MASK,
+               .val = PMX_UART0_MODEM_MASK,
        },
 };
 
@@ -923,6 +1031,10 @@ static struct spear_muxreg gpt0_tmr0_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_GPT0_TMR0_MASK,
                .val = PMX_GPT0_TMR0_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_GPT0_TMR0_MASK,
+               .val = PMX_GPT0_TMR0_MASK,
        },
 };
 
@@ -948,6 +1060,10 @@ static struct spear_muxreg gpt0_tmr1_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_GPT0_TMR1_MASK,
                .val = PMX_GPT0_TMR1_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_GPT0_TMR1_MASK,
+               .val = PMX_GPT0_TMR1_MASK,
        },
 };
 
@@ -980,6 +1096,10 @@ static struct spear_muxreg gpt1_tmr0_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_GPT1_TMR0_MASK,
                .val = PMX_GPT1_TMR0_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_GPT1_TMR0_MASK,
+               .val = PMX_GPT1_TMR0_MASK,
        },
 };
 
@@ -1005,6 +1125,10 @@ static struct spear_muxreg gpt1_tmr1_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_GPT1_TMR1_MASK,
                .val = PMX_GPT1_TMR1_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_GPT1_TMR1_MASK,
+               .val = PMX_GPT1_TMR1_MASK,
        },
 };
 
@@ -1049,6 +1173,20 @@ static const unsigned mcif_pins[] = { 86, 87, 88, 89, 90, 91, 92, 93, 213, 214,
                .reg = PAD_FUNCTION_EN_2,                       \
                .mask = PMX_MCIFALL_2_MASK,                     \
                .val = PMX_MCIFALL_2_MASK,                      \
+       }, {                                                    \
+               .reg = PAD_DIRECTION_SEL_0,                     \
+               .mask = PMX_MCI_DATA8_15_MASK,                  \
+               .val = PMX_MCI_DATA8_15_MASK,                   \
+       }, {                                                    \
+               .reg = PAD_DIRECTION_SEL_1,                     \
+               .mask = PMX_MCIFALL_1_MASK | PMX_NFWPRT1_MASK | \
+                       PMX_NFWPRT2_MASK,                       \
+               .val = PMX_MCIFALL_1_MASK | PMX_NFWPRT1_MASK |  \
+                       PMX_NFWPRT2_MASK,                       \
+       }, {                                                    \
+               .reg = PAD_DIRECTION_SEL_2,                     \
+               .mask = PMX_MCIFALL_2_MASK,                     \
+               .val = PMX_MCIFALL_2_MASK,                      \
        }
 
 /* sdhci device */
@@ -1154,6 +1292,10 @@ static struct spear_muxreg touch_xy_muxreg[] = {
                .reg = PAD_FUNCTION_EN_2,
                .mask = PMX_TOUCH_XY_MASK,
                .val = PMX_TOUCH_XY_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_TOUCH_XY_MASK,
+               .val = PMX_TOUCH_XY_MASK,
        },
 };
 
@@ -1187,6 +1329,10 @@ static struct spear_muxreg uart1_dis_i2c_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_I2C0_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_I2C0_MASK,
+               .val = PMX_I2C0_MASK,
        },
 };
 
@@ -1213,6 +1359,12 @@ static struct spear_muxreg uart1_dis_sd_muxreg[] = {
                .mask = PMX_MCIDATA1_MASK |
                        PMX_MCIDATA2_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_MCIDATA1_MASK |
+                       PMX_MCIDATA2_MASK,
+               .val = PMX_MCIDATA1_MASK |
+                       PMX_MCIDATA2_MASK,
        },
 };
 
@@ -1246,6 +1398,10 @@ static struct spear_muxreg uart2_3_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_I2S0_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_I2S0_MASK,
+               .val = PMX_I2S0_MASK,
        },
 };
 
@@ -1278,6 +1434,10 @@ static struct spear_muxreg uart4_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_I2S0_MASK | PMX_CLCD1_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_I2S0_MASK | PMX_CLCD1_MASK,
+               .val = PMX_I2S0_MASK | PMX_CLCD1_MASK,
        },
 };
 
@@ -1310,6 +1470,10 @@ static struct spear_muxreg uart5_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_CLCD1_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_CLCD1_MASK,
+               .val = PMX_CLCD1_MASK,
        },
 };
 
@@ -1344,6 +1508,10 @@ static struct spear_muxreg rs485_0_1_tdm_0_1_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_CLCD1_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_CLCD1_MASK,
+               .val = PMX_CLCD1_MASK,
        },
 };
 
@@ -1376,6 +1544,10 @@ static struct spear_muxreg i2c_1_2_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_CLCD1_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_CLCD1_MASK,
+               .val = PMX_CLCD1_MASK,
        },
 };
 
@@ -1409,6 +1581,10 @@ static struct spear_muxreg i2c3_dis_smi_clcd_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_CLCD1_MASK | PMX_SMI_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_CLCD1_MASK | PMX_SMI_MASK,
+               .val = PMX_CLCD1_MASK | PMX_SMI_MASK,
        },
 };
 
@@ -1435,6 +1611,10 @@ static struct spear_muxreg i2c3_dis_sd_i2s0_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_I2S1_MASK | PMX_MCIDATA3_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_I2S1_MASK | PMX_MCIDATA3_MASK,
+               .val = PMX_I2S1_MASK | PMX_MCIDATA3_MASK,
        },
 };
 
@@ -1469,6 +1649,10 @@ static struct spear_muxreg i2c_4_5_dis_smi_muxreg[] = {
                .reg = PAD_FUNCTION_EN_0,
                .mask = PMX_SMI_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_SMI_MASK,
+               .val = PMX_SMI_MASK,
        },
 };
 
@@ -1499,6 +1683,14 @@ static struct spear_muxreg i2c4_dis_sd_muxreg[] = {
                .reg = PAD_FUNCTION_EN_2,
                .mask = PMX_MCIDATA5_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_MCIDATA4_MASK,
+               .val = PMX_MCIDATA4_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_MCIDATA5_MASK,
+               .val = PMX_MCIDATA5_MASK,
        },
 };
 
@@ -1526,6 +1718,12 @@ static struct spear_muxreg i2c5_dis_sd_muxreg[] = {
                .mask = PMX_MCIDATA6_MASK |
                        PMX_MCIDATA7_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_MCIDATA6_MASK |
+                       PMX_MCIDATA7_MASK,
+               .val = PMX_MCIDATA6_MASK |
+                       PMX_MCIDATA7_MASK,
        },
 };
 
@@ -1560,6 +1758,10 @@ static struct spear_muxreg i2c_6_7_dis_kbd_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_KBD_ROWCOL25_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_KBD_ROWCOL25_MASK,
+               .val = PMX_KBD_ROWCOL25_MASK,
        },
 };
 
@@ -1587,6 +1789,12 @@ static struct spear_muxreg i2c6_dis_sd_muxreg[] = {
                .mask = PMX_MCIIORDRE_MASK |
                        PMX_MCIIOWRWE_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_MCIIORDRE_MASK |
+                       PMX_MCIIOWRWE_MASK,
+               .val = PMX_MCIIORDRE_MASK |
+                       PMX_MCIIOWRWE_MASK,
        },
 };
 
@@ -1613,6 +1821,12 @@ static struct spear_muxreg i2c7_dis_sd_muxreg[] = {
                .mask = PMX_MCIRESETCF_MASK |
                        PMX_MCICS0CE_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_MCIRESETCF_MASK |
+                       PMX_MCICS0CE_MASK,
+               .val = PMX_MCIRESETCF_MASK |
+                       PMX_MCICS0CE_MASK,
        },
 };
 
@@ -1651,6 +1865,14 @@ static struct spear_muxreg can0_dis_nor_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_NFRSTPWDWN3_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_NFRSTPWDWN2_MASK,
+               .val = PMX_NFRSTPWDWN2_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_NFRSTPWDWN3_MASK,
+               .val = PMX_NFRSTPWDWN3_MASK,
        },
 };
 
@@ -1677,6 +1899,10 @@ static struct spear_muxreg can0_dis_sd_muxreg[] = {
                .reg = PAD_FUNCTION_EN_2,
                .mask = PMX_MCICFINTR_MASK | PMX_MCIIORDY_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_MCICFINTR_MASK | PMX_MCIIORDY_MASK,
+               .val = PMX_MCICFINTR_MASK | PMX_MCIIORDY_MASK,
        },
 };
 
@@ -1711,6 +1937,10 @@ static struct spear_muxreg can1_dis_sd_muxreg[] = {
                .reg = PAD_FUNCTION_EN_2,
                .mask = PMX_MCICS1_MASK | PMX_MCIDMAACK_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_MCICS1_MASK | PMX_MCIDMAACK_MASK,
+               .val = PMX_MCICS1_MASK | PMX_MCIDMAACK_MASK,
        },
 };
 
@@ -1737,6 +1967,10 @@ static struct spear_muxreg can1_dis_kbd_muxreg[] = {
                .reg = PAD_FUNCTION_EN_1,
                .mask = PMX_KBD_ROWCOL25_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_KBD_ROWCOL25_MASK,
+               .val = PMX_KBD_ROWCOL25_MASK,
        },
 };
 
@@ -1763,29 +1997,64 @@ static struct spear_function can1_function = {
        .ngroups = ARRAY_SIZE(can1_grps),
 };
 
-/* Pad multiplexing for pci device */
-static const unsigned pci_sata_pins[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 18,
+/* Pad multiplexing for (ras-ip) pci device */
+static const unsigned pci_pins[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 18,
        19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
        37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
        55, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 };
-#define PCI_SATA_MUXREG                                \
-       {                                       \
-               .reg = PAD_FUNCTION_EN_0,       \
-               .mask = PMX_MCI_DATA8_15_MASK,  \
-               .val = 0,                       \
-       }, {                                    \
-               .reg = PAD_FUNCTION_EN_1,       \
-               .mask = PMX_PCI_REG1_MASK,      \
-               .val = 0,                       \
-       }, {                                    \
-               .reg = PAD_FUNCTION_EN_2,       \
-               .mask = PMX_PCI_REG2_MASK,      \
-               .val = 0,                       \
-       }
 
-/* pad multiplexing for pcie0 device */
+static struct spear_muxreg pci_muxreg[] = {
+       {
+               .reg = PAD_FUNCTION_EN_0,
+               .mask = PMX_MCI_DATA8_15_MASK,
+               .val = 0,
+       }, {
+               .reg = PAD_FUNCTION_EN_1,
+               .mask = PMX_PCI_REG1_MASK,
+               .val = 0,
+       }, {
+               .reg = PAD_FUNCTION_EN_2,
+               .mask = PMX_PCI_REG2_MASK,
+               .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_0,
+               .mask = PMX_MCI_DATA8_15_MASK,
+               .val = PMX_MCI_DATA8_15_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_PCI_REG1_MASK,
+               .val = PMX_PCI_REG1_MASK,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_PCI_REG2_MASK,
+               .val = PMX_PCI_REG2_MASK,
+       },
+};
+
+static struct spear_modemux pci_modemux[] = {
+       {
+               .muxregs = pci_muxreg,
+               .nmuxregs = ARRAY_SIZE(pci_muxreg),
+       },
+};
+
+static struct spear_pingroup pci_pingroup = {
+       .name = "pci_grp",
+       .pins = pci_pins,
+       .npins = ARRAY_SIZE(pci_pins),
+       .modemuxs = pci_modemux,
+       .nmodemuxs = ARRAY_SIZE(pci_modemux),
+};
+
+static const char *const pci_grps[] = { "pci_grp" };
+static struct spear_function pci_function = {
+       .name = "pci",
+       .groups = pci_grps,
+       .ngroups = ARRAY_SIZE(pci_grps),
+};
+
+/* pad multiplexing for (fix-part) pcie0 device */
 static struct spear_muxreg pcie0_muxreg[] = {
-       PCI_SATA_MUXREG,
        {
                .reg = PCIE_SATA_CFG,
                .mask = PCIE_CFG_VAL(0),
@@ -1802,15 +2071,12 @@ static struct spear_modemux pcie0_modemux[] = {
 
 static struct spear_pingroup pcie0_pingroup = {
        .name = "pcie0_grp",
-       .pins = pci_sata_pins,
-       .npins = ARRAY_SIZE(pci_sata_pins),
        .modemuxs = pcie0_modemux,
        .nmodemuxs = ARRAY_SIZE(pcie0_modemux),
 };
 
-/* pad multiplexing for pcie1 device */
+/* pad multiplexing for (fix-part) pcie1 device */
 static struct spear_muxreg pcie1_muxreg[] = {
-       PCI_SATA_MUXREG,
        {
                .reg = PCIE_SATA_CFG,
                .mask = PCIE_CFG_VAL(1),
@@ -1827,15 +2093,12 @@ static struct spear_modemux pcie1_modemux[] = {
 
 static struct spear_pingroup pcie1_pingroup = {
        .name = "pcie1_grp",
-       .pins = pci_sata_pins,
-       .npins = ARRAY_SIZE(pci_sata_pins),
        .modemuxs = pcie1_modemux,
        .nmodemuxs = ARRAY_SIZE(pcie1_modemux),
 };
 
-/* pad multiplexing for pcie2 device */
+/* pad multiplexing for (fix-part) pcie2 device */
 static struct spear_muxreg pcie2_muxreg[] = {
-       PCI_SATA_MUXREG,
        {
                .reg = PCIE_SATA_CFG,
                .mask = PCIE_CFG_VAL(2),
@@ -1852,22 +2115,20 @@ static struct spear_modemux pcie2_modemux[] = {
 
 static struct spear_pingroup pcie2_pingroup = {
        .name = "pcie2_grp",
-       .pins = pci_sata_pins,
-       .npins = ARRAY_SIZE(pci_sata_pins),
        .modemuxs = pcie2_modemux,
        .nmodemuxs = ARRAY_SIZE(pcie2_modemux),
 };
 
-static const char *const pci_grps[] = { "pcie0_grp", "pcie1_grp", "pcie2_grp" };
-static struct spear_function pci_function = {
-       .name = "pci",
-       .groups = pci_grps,
-       .ngroups = ARRAY_SIZE(pci_grps),
+static const char *const pcie_grps[] = { "pcie0_grp", "pcie1_grp", "pcie2_grp"
+};
+static struct spear_function pcie_function = {
+       .name = "pci_express",
+       .groups = pcie_grps,
+       .ngroups = ARRAY_SIZE(pcie_grps),
 };
 
 /* pad multiplexing for sata0 device */
 static struct spear_muxreg sata0_muxreg[] = {
-       PCI_SATA_MUXREG,
        {
                .reg = PCIE_SATA_CFG,
                .mask = SATA_CFG_VAL(0),
@@ -1884,15 +2145,12 @@ static struct spear_modemux sata0_modemux[] = {
 
 static struct spear_pingroup sata0_pingroup = {
        .name = "sata0_grp",
-       .pins = pci_sata_pins,
-       .npins = ARRAY_SIZE(pci_sata_pins),
        .modemuxs = sata0_modemux,
        .nmodemuxs = ARRAY_SIZE(sata0_modemux),
 };
 
 /* pad multiplexing for sata1 device */
 static struct spear_muxreg sata1_muxreg[] = {
-       PCI_SATA_MUXREG,
        {
                .reg = PCIE_SATA_CFG,
                .mask = SATA_CFG_VAL(1),
@@ -1909,15 +2167,12 @@ static struct spear_modemux sata1_modemux[] = {
 
 static struct spear_pingroup sata1_pingroup = {
        .name = "sata1_grp",
-       .pins = pci_sata_pins,
-       .npins = ARRAY_SIZE(pci_sata_pins),
        .modemuxs = sata1_modemux,
        .nmodemuxs = ARRAY_SIZE(sata1_modemux),
 };
 
 /* pad multiplexing for sata2 device */
 static struct spear_muxreg sata2_muxreg[] = {
-       PCI_SATA_MUXREG,
        {
                .reg = PCIE_SATA_CFG,
                .mask = SATA_CFG_VAL(2),
@@ -1934,8 +2189,6 @@ static struct spear_modemux sata2_modemux[] = {
 
 static struct spear_pingroup sata2_pingroup = {
        .name = "sata2_grp",
-       .pins = pci_sata_pins,
-       .npins = ARRAY_SIZE(pci_sata_pins),
        .modemuxs = sata2_modemux,
        .nmodemuxs = ARRAY_SIZE(sata2_modemux),
 };
@@ -1957,6 +2210,14 @@ static struct spear_muxreg ssp1_dis_kbd_muxreg[] = {
                        PMX_KBD_COL0_MASK | PMX_NFIO8_15_MASK | PMX_NFCE1_MASK |
                        PMX_NFCE2_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_1,
+               .mask = PMX_KBD_ROWCOL25_MASK | PMX_KBD_COL1_MASK |
+                       PMX_KBD_COL0_MASK | PMX_NFIO8_15_MASK | PMX_NFCE1_MASK |
+                       PMX_NFCE2_MASK,
+               .val = PMX_KBD_ROWCOL25_MASK | PMX_KBD_COL1_MASK |
+                       PMX_KBD_COL0_MASK | PMX_NFIO8_15_MASK | PMX_NFCE1_MASK |
+                       PMX_NFCE2_MASK,
        },
 };
 
@@ -1983,6 +2244,12 @@ static struct spear_muxreg ssp1_dis_sd_muxreg[] = {
                .mask = PMX_MCIADDR0ALE_MASK | PMX_MCIADDR2_MASK |
                        PMX_MCICECF_MASK | PMX_MCICEXD_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_MCIADDR0ALE_MASK | PMX_MCIADDR2_MASK |
+                       PMX_MCICECF_MASK | PMX_MCICEXD_MASK,
+               .val = PMX_MCIADDR0ALE_MASK | PMX_MCIADDR2_MASK |
+                       PMX_MCICECF_MASK | PMX_MCICEXD_MASK,
        },
 };
 
@@ -2017,6 +2284,12 @@ static struct spear_muxreg gpt64_muxreg[] = {
                .mask = PMX_MCICDCF1_MASK | PMX_MCICDCF2_MASK | PMX_MCICDXD_MASK
                        | PMX_MCILEDS_MASK,
                .val = 0,
+       }, {
+               .reg = PAD_DIRECTION_SEL_2,
+               .mask = PMX_MCICDCF1_MASK | PMX_MCICDCF2_MASK | PMX_MCICDXD_MASK
+                       | PMX_MCILEDS_MASK,
+               .val = PMX_MCICDCF1_MASK | PMX_MCICDCF2_MASK | PMX_MCICDXD_MASK
+                       | PMX_MCILEDS_MASK,
        },
 };
 
@@ -2093,6 +2366,7 @@ static struct spear_pingroup *spear1310_pingroups[] = {
        &can0_dis_sd_pingroup,
        &can1_dis_sd_pingroup,
        &can1_dis_kbd_pingroup,
+       &pci_pingroup,
        &pcie0_pingroup,
        &pcie1_pingroup,
        &pcie2_pingroup,
@@ -2138,11 +2412,274 @@ static struct spear_function *spear1310_functions[] = {
        &can0_function,
        &can1_function,
        &pci_function,
+       &pcie_function,
        &sata_function,
        &ssp1_function,
        &gpt64_function,
 };
 
+static const unsigned pin18[] = { 18, };
+static const unsigned pin19[] = { 19, };
+static const unsigned pin20[] = { 20, };
+static const unsigned pin21[] = { 21, };
+static const unsigned pin22[] = { 22, };
+static const unsigned pin23[] = { 23, };
+static const unsigned pin54[] = { 54, };
+static const unsigned pin55[] = { 55, };
+static const unsigned pin56[] = { 56, };
+static const unsigned pin57[] = { 57, };
+static const unsigned pin58[] = { 58, };
+static const unsigned pin59[] = { 59, };
+static const unsigned pin60[] = { 60, };
+static const unsigned pin61[] = { 61, };
+static const unsigned pin62[] = { 62, };
+static const unsigned pin63[] = { 63, };
+static const unsigned pin143[] = { 143, };
+static const unsigned pin144[] = { 144, };
+static const unsigned pin145[] = { 145, };
+static const unsigned pin146[] = { 146, };
+static const unsigned pin147[] = { 147, };
+static const unsigned pin148[] = { 148, };
+static const unsigned pin149[] = { 149, };
+static const unsigned pin150[] = { 150, };
+static const unsigned pin151[] = { 151, };
+static const unsigned pin152[] = { 152, };
+static const unsigned pin205[] = { 205, };
+static const unsigned pin206[] = { 206, };
+static const unsigned pin211[] = { 211, };
+static const unsigned pin212[] = { 212, };
+static const unsigned pin213[] = { 213, };
+static const unsigned pin214[] = { 214, };
+static const unsigned pin215[] = { 215, };
+static const unsigned pin216[] = { 216, };
+static const unsigned pin217[] = { 217, };
+static const unsigned pin218[] = { 218, };
+static const unsigned pin219[] = { 219, };
+static const unsigned pin220[] = { 220, };
+static const unsigned pin221[] = { 221, };
+static const unsigned pin222[] = { 222, };
+static const unsigned pin223[] = { 223, };
+static const unsigned pin224[] = { 224, };
+static const unsigned pin225[] = { 225, };
+static const unsigned pin226[] = { 226, };
+static const unsigned pin227[] = { 227, };
+static const unsigned pin228[] = { 228, };
+static const unsigned pin229[] = { 229, };
+static const unsigned pin230[] = { 230, };
+static const unsigned pin231[] = { 231, };
+static const unsigned pin232[] = { 232, };
+static const unsigned pin233[] = { 233, };
+static const unsigned pin234[] = { 234, };
+static const unsigned pin235[] = { 235, };
+static const unsigned pin236[] = { 236, };
+static const unsigned pin237[] = { 237, };
+static const unsigned pin238[] = { 238, };
+static const unsigned pin239[] = { 239, };
+static const unsigned pin240[] = { 240, };
+static const unsigned pin241[] = { 241, };
+static const unsigned pin242[] = { 242, };
+static const unsigned pin243[] = { 243, };
+static const unsigned pin244[] = { 244, };
+static const unsigned pin245[] = { 245, };
+
+static const unsigned pin_grp0[] = { 173, 174, };
+static const unsigned pin_grp1[] = { 175, 185, 188, 197, 198, };
+static const unsigned pin_grp2[] = { 176, 177, 178, 179, 184, 186, 187, 189,
+       190, 191, 192, };
+static const unsigned pin_grp3[] = { 180, 181, 182, 183, 193, 194, 195, 196, };
+static const unsigned pin_grp4[] = { 199, 200, };
+static const unsigned pin_grp5[] = { 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+       75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, };
+static const unsigned pin_grp6[] = { 86, 87, 88, 89, 90, 91, 92, 93, };
+static const unsigned pin_grp7[] = { 98, 99, };
+static const unsigned pin_grp8[] = { 158, 159, 160, 161, 162, 163, 164, 165,
+       166, 167, 168, 169, 170, 171, 172, };
+
+/* Define muxreg arrays */
+DEFINE_2_MUXREG(i2c0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2C0_MASK, 0, 1);
+DEFINE_2_MUXREG(ssp0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SSP0_MASK, 0, 1);
+DEFINE_2_MUXREG(ssp0_cs0_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS0_MASK, 0, 1);
+DEFINE_2_MUXREG(ssp0_cs1_2_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS1_2_MASK, 0, 1);
+DEFINE_2_MUXREG(i2s0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2S0_MASK, 0, 1);
+DEFINE_2_MUXREG(i2s1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_I2S1_MASK, 0, 1);
+DEFINE_2_MUXREG(clcd_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_CLCD1_MASK, 0, 1);
+DEFINE_2_MUXREG(clcd_high_res_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_CLCD2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin18, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO15_MASK, 0, 1);
+DEFINE_2_MUXREG(pin19, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO14_MASK, 0, 1);
+DEFINE_2_MUXREG(pin20, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO13_MASK, 0, 1);
+DEFINE_2_MUXREG(pin21, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO12_MASK, 0, 1);
+DEFINE_2_MUXREG(pin22, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO11_MASK, 0, 1);
+DEFINE_2_MUXREG(pin23, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO10_MASK, 0, 1);
+DEFINE_2_MUXREG(pin143, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO00_MASK, 0, 1);
+DEFINE_2_MUXREG(pin144, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO01_MASK, 0, 1);
+DEFINE_2_MUXREG(pin145, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO02_MASK, 0, 1);
+DEFINE_2_MUXREG(pin146, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO03_MASK, 0, 1);
+DEFINE_2_MUXREG(pin147, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO04_MASK, 0, 1);
+DEFINE_2_MUXREG(pin148, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO05_MASK, 0, 1);
+DEFINE_2_MUXREG(pin149, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO06_MASK, 0, 1);
+DEFINE_2_MUXREG(pin150, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO07_MASK, 0, 1);
+DEFINE_2_MUXREG(pin151, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO08_MASK, 0, 1);
+DEFINE_2_MUXREG(pin152, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO09_MASK, 0, 1);
+DEFINE_2_MUXREG(smi_2_chips_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SMI_MASK, 0, 1);
+DEFINE_2_MUXREG(pin54, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin55, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin56, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFRSTPWDWN3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin57, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin58, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin59, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN0_MASK, 0, 1);
+DEFINE_2_MUXREG(pin60, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFWPRT3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin61, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFCE3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin62, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD25_MASK, 0, 1);
+DEFINE_2_MUXREG(pin63, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD24_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp0, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICLK_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp1, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICOL_CRS_XFERER_MIITXCLK_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp2, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_RXCLK_RDV_TXEN_D03_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp3, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIID47_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp4, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MDC_MDIO_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp5, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD23_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp6, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MCI_DATA8_15_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp7, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFCE2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp8, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND8_MASK, 0, 1);
+DEFINE_2_MUXREG(nand_16bit_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND16BIT_1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin205, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL1_MASK | PMX_NFCE1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin206, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL0_MASK | PMX_NFCE2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin211, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW1_MASK | PMX_NFWPRT1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin212, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW0_MASK | PMX_NFWPRT2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin213, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA0_MASK, 0, 1);
+DEFINE_2_MUXREG(pin214, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin215, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin216, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin217, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA4_MASK, 0, 1);
+DEFINE_2_MUXREG(pin218, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA5_MASK, 0, 1);
+DEFINE_2_MUXREG(pin219, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA6_MASK, 0, 1);
+DEFINE_2_MUXREG(pin220, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA7_MASK, 0, 1);
+DEFINE_2_MUXREG(pin221, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA1SD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin222, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA2SD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin223, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA3SD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin224, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR0ALE_MASK, 0, 1);
+DEFINE_2_MUXREG(pin225, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR1CLECLK_MASK, 0, 1);
+DEFINE_2_MUXREG(pin226, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin227, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICECF_MASK, 0, 1);
+DEFINE_2_MUXREG(pin228, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICEXD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin229, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICESDMMC_MASK, 0, 1);
+DEFINE_2_MUXREG(pin230, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin231, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin232, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDXD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin233, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDSDMMC_MASK, 0, 1);
+DEFINE_2_MUXREG(pin234, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATADIR_MASK, 0, 1);
+DEFINE_2_MUXREG(pin235, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMARQWP_MASK, 0, 1);
+DEFINE_2_MUXREG(pin236, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDRE_MASK, 0, 1);
+DEFINE_2_MUXREG(pin237, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIOWRWE_MASK, 0, 1);
+DEFINE_2_MUXREG(pin238, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIRESETCF_MASK, 0, 1);
+DEFINE_2_MUXREG(pin239, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS0CE_MASK, 0, 1);
+DEFINE_2_MUXREG(pin240, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICFINTR_MASK, 0, 1);
+DEFINE_2_MUXREG(pin241, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDY_MASK, 0, 1);
+DEFINE_2_MUXREG(pin242, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin243, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMAACK_MASK, 0, 1);
+DEFINE_2_MUXREG(pin244, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCISDCMD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin245, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCILEDS_MASK, 0, 1);
+DEFINE_2_MUXREG(keyboard_rowcol6_8_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROWCOL68_MASK, 0, 1);
+DEFINE_2_MUXREG(uart0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_UART0_MASK, 0, 1);
+DEFINE_2_MUXREG(uart0_modem_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_UART0_MODEM_MASK, 0, 1);
+DEFINE_2_MUXREG(gpt0_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR0_MASK, 0, 1);
+DEFINE_2_MUXREG(gpt0_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR1_MASK, 0, 1);
+DEFINE_2_MUXREG(gpt1_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR0_MASK, 0, 1);
+DEFINE_2_MUXREG(gpt1_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR1_MASK, 0, 1);
+DEFINE_2_MUXREG(touch_xy_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_TOUCH_XY_MASK, 0, 1);
+
+static struct spear_gpio_pingroup spear1310_gpio_pingroup[] = {
+       GPIO_PINGROUP(i2c0_pins),
+       GPIO_PINGROUP(ssp0_pins),
+       GPIO_PINGROUP(ssp0_cs0_pins),
+       GPIO_PINGROUP(ssp0_cs1_2_pins),
+       GPIO_PINGROUP(i2s0_pins),
+       GPIO_PINGROUP(i2s1_pins),
+       GPIO_PINGROUP(clcd_pins),
+       GPIO_PINGROUP(clcd_high_res_pins),
+       GPIO_PINGROUP(pin18),
+       GPIO_PINGROUP(pin19),
+       GPIO_PINGROUP(pin20),
+       GPIO_PINGROUP(pin21),
+       GPIO_PINGROUP(pin22),
+       GPIO_PINGROUP(pin23),
+       GPIO_PINGROUP(pin143),
+       GPIO_PINGROUP(pin144),
+       GPIO_PINGROUP(pin145),
+       GPIO_PINGROUP(pin146),
+       GPIO_PINGROUP(pin147),
+       GPIO_PINGROUP(pin148),
+       GPIO_PINGROUP(pin149),
+       GPIO_PINGROUP(pin150),
+       GPIO_PINGROUP(pin151),
+       GPIO_PINGROUP(pin152),
+       GPIO_PINGROUP(smi_2_chips_pins),
+       GPIO_PINGROUP(pin54),
+       GPIO_PINGROUP(pin55),
+       GPIO_PINGROUP(pin56),
+       GPIO_PINGROUP(pin57),
+       GPIO_PINGROUP(pin58),
+       GPIO_PINGROUP(pin59),
+       GPIO_PINGROUP(pin60),
+       GPIO_PINGROUP(pin61),
+       GPIO_PINGROUP(pin62),
+       GPIO_PINGROUP(pin63),
+       GPIO_PINGROUP(pin_grp0),
+       GPIO_PINGROUP(pin_grp1),
+       GPIO_PINGROUP(pin_grp2),
+       GPIO_PINGROUP(pin_grp3),
+       GPIO_PINGROUP(pin_grp4),
+       GPIO_PINGROUP(pin_grp5),
+       GPIO_PINGROUP(pin_grp6),
+       GPIO_PINGROUP(pin_grp7),
+       GPIO_PINGROUP(pin_grp8),
+       GPIO_PINGROUP(nand_16bit_pins),
+       GPIO_PINGROUP(pin205),
+       GPIO_PINGROUP(pin206),
+       GPIO_PINGROUP(pin211),
+       GPIO_PINGROUP(pin212),
+       GPIO_PINGROUP(pin213),
+       GPIO_PINGROUP(pin214),
+       GPIO_PINGROUP(pin215),
+       GPIO_PINGROUP(pin216),
+       GPIO_PINGROUP(pin217),
+       GPIO_PINGROUP(pin218),
+       GPIO_PINGROUP(pin219),
+       GPIO_PINGROUP(pin220),
+       GPIO_PINGROUP(pin221),
+       GPIO_PINGROUP(pin222),
+       GPIO_PINGROUP(pin223),
+       GPIO_PINGROUP(pin224),
+       GPIO_PINGROUP(pin225),
+       GPIO_PINGROUP(pin226),
+       GPIO_PINGROUP(pin227),
+       GPIO_PINGROUP(pin228),
+       GPIO_PINGROUP(pin229),
+       GPIO_PINGROUP(pin230),
+       GPIO_PINGROUP(pin231),
+       GPIO_PINGROUP(pin232),
+       GPIO_PINGROUP(pin233),
+       GPIO_PINGROUP(pin234),
+       GPIO_PINGROUP(pin235),
+       GPIO_PINGROUP(pin236),
+       GPIO_PINGROUP(pin237),
+       GPIO_PINGROUP(pin238),
+       GPIO_PINGROUP(pin239),
+       GPIO_PINGROUP(pin240),
+       GPIO_PINGROUP(pin241),
+       GPIO_PINGROUP(pin242),
+       GPIO_PINGROUP(pin243),
+       GPIO_PINGROUP(pin244),
+       GPIO_PINGROUP(pin245),
+       GPIO_PINGROUP(keyboard_rowcol6_8_pins),
+       GPIO_PINGROUP(uart0_pins),
+       GPIO_PINGROUP(uart0_modem_pins),
+       GPIO_PINGROUP(gpt0_tmr0_pins),
+       GPIO_PINGROUP(gpt0_tmr1_pins),
+       GPIO_PINGROUP(gpt1_tmr0_pins),
+       GPIO_PINGROUP(gpt1_tmr1_pins),
+       GPIO_PINGROUP(touch_xy_pins),
+};
+
 static struct spear_pinctrl_machdata spear1310_machdata = {
        .pins = spear1310_pins,
        .npins = ARRAY_SIZE(spear1310_pins),
@@ -2150,6 +2687,8 @@ static struct spear_pinctrl_machdata spear1310_machdata = {
        .ngroups = ARRAY_SIZE(spear1310_pingroups),
        .functions = spear1310_functions,
        .nfunctions = ARRAY_SIZE(spear1310_functions),
+       .gpio_pingroups = spear1310_gpio_pingroup,
+       .ngpio_pingroups = ARRAY_SIZE(spear1310_gpio_pingroup),
        .modes_supported = false,
 };
 
index a0eb057..0606b8c 100644 (file)
@@ -213,7 +213,7 @@ static const struct pinctrl_pin_desc spear1340_pins[] = {
  * Pad multiplexing for making all pads as gpio's. This is done to override the
  * values passed from bootloader and start from scratch.
  */
-static const unsigned pads_as_gpio_pins[] = { 251 };
+static const unsigned pads_as_gpio_pins[] = { 12, 88, 89, 251 };
 static struct spear_muxreg pads_as_gpio_muxreg[] = {
        {
                .reg = PAD_FUNCTION_EN_1,
@@ -1692,7 +1692,43 @@ static struct spear_pingroup clcd_pingroup = {
        .nmodemuxs = ARRAY_SIZE(clcd_modemux),
 };
 
-static const char *const clcd_grps[] = { "clcd_grp" };
+/* Disable cld runtime to save panel damage */
+static struct spear_muxreg clcd_sleep_muxreg[] = {
+       {
+               .reg = PAD_SHARED_IP_EN_1,
+               .mask = ARM_TRACE_MASK | MIPHY_DBG_MASK,
+               .val = 0,
+       }, {
+               .reg = PAD_FUNCTION_EN_5,
+               .mask = CLCD_REG4_MASK | CLCD_AND_ARM_TRACE_REG4_MASK,
+               .val = 0x0,
+       }, {
+               .reg = PAD_FUNCTION_EN_6,
+               .mask = CLCD_AND_ARM_TRACE_REG5_MASK,
+               .val = 0x0,
+       }, {
+               .reg = PAD_FUNCTION_EN_7,
+               .mask = CLCD_AND_ARM_TRACE_REG6_MASK,
+               .val = 0x0,
+       },
+};
+
+static struct spear_modemux clcd_sleep_modemux[] = {
+       {
+               .muxregs = clcd_sleep_muxreg,
+               .nmuxregs = ARRAY_SIZE(clcd_sleep_muxreg),
+       },
+};
+
+static struct spear_pingroup clcd_sleep_pingroup = {
+       .name = "clcd_sleep_grp",
+       .pins = clcd_pins,
+       .npins = ARRAY_SIZE(clcd_pins),
+       .modemuxs = clcd_sleep_modemux,
+       .nmodemuxs = ARRAY_SIZE(clcd_sleep_modemux),
+};
+
+static const char *const clcd_grps[] = { "clcd_grp", "clcd_sleep_grp" };
 static struct spear_function clcd_function = {
        .name = "clcd",
        .groups = clcd_grps,
@@ -1893,6 +1929,7 @@ static struct spear_pingroup *spear1340_pingroups[] = {
        &sdhci_pingroup,
        &cf_pingroup,
        &xd_pingroup,
+       &clcd_sleep_pingroup,
        &clcd_pingroup,
        &arm_trace_pingroup,
        &miphy_dbg_pingroup,
index 4dfc284..9a49100 100644 (file)
@@ -661,6 +661,8 @@ static int __devinit spear300_pinctrl_probe(struct platform_device *pdev)
        spear3xx_machdata.ngroups = ARRAY_SIZE(spear300_pingroups);
        spear3xx_machdata.functions = spear300_functions;
        spear3xx_machdata.nfunctions = ARRAY_SIZE(spear300_functions);
+       spear3xx_machdata.gpio_pingroups = NULL;
+       spear3xx_machdata.ngpio_pingroups = 0;
 
        spear3xx_machdata.modes_supported = true;
        spear3xx_machdata.pmx_modes = spear300_pmx_modes;
index 9688369..4d5dfe9 100644 (file)
@@ -388,6 +388,8 @@ static int __devinit spear310_pinctrl_probe(struct platform_device *pdev)
        spear3xx_machdata.nfunctions = ARRAY_SIZE(spear310_functions);
 
        pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+       pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups,
+                       spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG);
 
        spear3xx_machdata.modes_supported = false;
 
index 020b1e0..c996e26 100644 (file)
@@ -2240,6 +2240,10 @@ static struct spear_muxreg pwm2_pin_34_muxreg[] = {
                .mask = PMX_SSP_CS_MASK,
                .val = 0,
        }, {
+               .reg = MODE_CONFIG_REG,
+               .mask = PMX_PWM_MASK,
+               .val = PMX_PWM_MASK,
+       }, {
                .reg = IP_SEL_PAD_30_39_REG,
                .mask = PMX_PL_34_MASK,
                .val = PMX_PWM2_PL_34_VAL,
@@ -2956,9 +2960,9 @@ static struct spear_function mii2_function = {
 };
 
 /* Pad multiplexing for cadence mii 1_2 as smii or rmii device */
-static const unsigned smii0_1_pins[] = { 10, 11, 13, 14, 15, 16, 17, 18, 19, 20,
+static const unsigned rmii0_1_pins[] = { 10, 11, 13, 14, 15, 16, 17, 18, 19, 20,
        21, 22, 23, 24, 25, 26, 27 };
-static const unsigned rmii0_1_pins[] = { 10, 11, 21, 22, 23, 24, 25, 26, 27 };
+static const unsigned smii0_1_pins[] = { 10, 11, 21, 22, 23, 24, 25, 26, 27 };
 static struct spear_muxreg mii0_1_muxreg[] = {
        {
                .reg = PMX_CONFIG_REG,
@@ -3427,6 +3431,8 @@ static int __devinit spear320_pinctrl_probe(struct platform_device *pdev)
        spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear320_pmx_modes);
 
        pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+       pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups,
+                       spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG);
 
        ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
        if (ret)
index 0242378..12ee21a 100644 (file)
@@ -481,7 +481,44 @@ struct spear_function spear3xx_timer_2_3_function = {
        .ngroups = ARRAY_SIZE(timer_2_3_grps),
 };
 
+/* Define muxreg arrays */
+DEFINE_MUXREG(firda_pins, 0, PMX_FIRDA_MASK, 0);
+DEFINE_MUXREG(i2c_pins, 0, PMX_I2C_MASK, 0);
+DEFINE_MUXREG(ssp_cs_pins, 0, PMX_SSP_CS_MASK, 0);
+DEFINE_MUXREG(ssp_pins, 0, PMX_SSP_MASK, 0);
+DEFINE_MUXREG(mii_pins, 0, PMX_MII_MASK, 0);
+DEFINE_MUXREG(gpio0_pin0_pins, 0, PMX_GPIO_PIN0_MASK, 0);
+DEFINE_MUXREG(gpio0_pin1_pins, 0, PMX_GPIO_PIN1_MASK, 0);
+DEFINE_MUXREG(gpio0_pin2_pins, 0, PMX_GPIO_PIN2_MASK, 0);
+DEFINE_MUXREG(gpio0_pin3_pins, 0, PMX_GPIO_PIN3_MASK, 0);
+DEFINE_MUXREG(gpio0_pin4_pins, 0, PMX_GPIO_PIN4_MASK, 0);
+DEFINE_MUXREG(gpio0_pin5_pins, 0, PMX_GPIO_PIN5_MASK, 0);
+DEFINE_MUXREG(uart0_ext_pins, 0, PMX_UART0_MODEM_MASK, 0);
+DEFINE_MUXREG(uart0_pins, 0, PMX_UART0_MASK, 0);
+DEFINE_MUXREG(timer_0_1_pins, 0, PMX_TIMER_0_1_MASK, 0);
+DEFINE_MUXREG(timer_2_3_pins, 0, PMX_TIMER_2_3_MASK, 0);
+
+static struct spear_gpio_pingroup spear3xx_gpio_pingroup[] = {
+       GPIO_PINGROUP(firda_pins),
+       GPIO_PINGROUP(i2c_pins),
+       GPIO_PINGROUP(ssp_cs_pins),
+       GPIO_PINGROUP(ssp_pins),
+       GPIO_PINGROUP(mii_pins),
+       GPIO_PINGROUP(gpio0_pin0_pins),
+       GPIO_PINGROUP(gpio0_pin1_pins),
+       GPIO_PINGROUP(gpio0_pin2_pins),
+       GPIO_PINGROUP(gpio0_pin3_pins),
+       GPIO_PINGROUP(gpio0_pin4_pins),
+       GPIO_PINGROUP(gpio0_pin5_pins),
+       GPIO_PINGROUP(uart0_ext_pins),
+       GPIO_PINGROUP(uart0_pins),
+       GPIO_PINGROUP(timer_0_1_pins),
+       GPIO_PINGROUP(timer_2_3_pins),
+};
+
 struct spear_pinctrl_machdata spear3xx_machdata = {
        .pins = spear3xx_pins,
        .npins = ARRAY_SIZE(spear3xx_pins),
+       .gpio_pingroups = spear3xx_gpio_pingroup,
+       .ngpio_pingroups = ARRAY_SIZE(spear3xx_gpio_pingroup),
 };
index 31f4434..7860b36 100644 (file)
@@ -15,6 +15,7 @@
 #include "pinctrl-spear.h"
 
 /* pad mux declarations */
+#define PMX_PWM_MASK           (1 << 16)
 #define PMX_FIRDA_MASK         (1 << 14)
 #define PMX_I2C_MASK           (1 << 13)
 #define PMX_SSP_CS_MASK                (1 << 12)
index 33bb4d8..4af3dfe 100644 (file)
@@ -112,9 +112,6 @@ 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);
 
-#define __MAX_SUBCHANNEL 65535
-#define __MAX_SSID 3
-
 struct channel_subsystem {
        u8 cssid;
        int valid;
index fc916f5..fd3143c 100644 (file)
@@ -1424,7 +1424,7 @@ static enum io_sch_action sch_get_action(struct subchannel *sch)
        }
        if (device_is_disconnected(cdev))
                return IO_SCH_REPROBE;
-       if (cdev->online)
+       if (cdev->online && !cdev->private->flags.resuming)
                return IO_SCH_VERIFY;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return IO_SCH_UNREG_ATTACH;
@@ -1469,12 +1469,6 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
                rc = 0;
                goto out_unlock;
        case IO_SCH_VERIFY:
-               if (cdev->private->flags.resuming == 1) {
-                       if (cio_enable_subchannel(sch, (u32)(addr_t)sch)) {
-                               ccw_device_set_notoper(cdev);
-                               break;
-                       }
-               }
                /* Trigger path verification. */
                io_subchannel_verify(sch);
                rc = 0;
index 199bc67..65d13e3 100644 (file)
@@ -125,8 +125,7 @@ int idset_is_empty(struct idset *set)
 
 void idset_add_set(struct idset *to, struct idset *from)
 {
-       int len = min(__BITOPS_WORDS(to->num_ssid * to->num_id),
-                     __BITOPS_WORDS(from->num_ssid * from->num_id));
+       int len = min(to->num_ssid * to->num_id, from->num_ssid * from->num_id);
 
        bitmap_or(to->bitmap, to->bitmap, from->bitmap, len);
 }
index bd4708a..20fd974 100644 (file)
@@ -149,6 +149,7 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
 int
 qla24xx_disable_vp(scsi_qla_host_t *vha)
 {
+       unsigned long flags;
        int ret;
 
        ret = qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL);
@@ -156,7 +157,9 @@ qla24xx_disable_vp(scsi_qla_host_t *vha)
        atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
 
        /* Remove port id from vp target map */
+       spin_lock_irqsave(&vha->hw->vport_slock, flags);
        qlt_update_vp_map(vha, RESET_AL_PA);
+       spin_unlock_irqrestore(&vha->hw->vport_slock, flags);
 
        qla2x00_mark_vp_devices_dead(vha);
        atomic_set(&vha->vp_state, VP_FAILED);
index 0e09d8f..62aa558 100644 (file)
@@ -557,6 +557,7 @@ static bool qlt_check_fcport_exist(struct scsi_qla_host *vha,
        int pmap_len;
        fc_port_t *fcport;
        int global_resets;
+       unsigned long flags;
 
 retry:
        global_resets = atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count);
@@ -625,10 +626,10 @@ retry:
            sess->s_id.b.area, sess->loop_id, fcport->d_id.b.domain,
            fcport->d_id.b.al_pa, fcport->d_id.b.area, fcport->loop_id);
 
-       sess->s_id = fcport->d_id;
-       sess->loop_id = fcport->loop_id;
-       sess->conf_compl_supported = !!(fcport->flags &
-           FCF_CONF_COMP_SUPPORTED);
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id,
+                               (fcport->flags & FCF_CONF_COMP_SUPPORTED));
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        res = true;
 
@@ -740,10 +741,9 @@ static struct qla_tgt_sess *qlt_create_sess(
                                qlt_undelete_sess(sess);
 
                        kref_get(&sess->se_sess->sess_kref);
-                       sess->s_id = fcport->d_id;
-                       sess->loop_id = fcport->loop_id;
-                       sess->conf_compl_supported = !!(fcport->flags &
-                           FCF_CONF_COMP_SUPPORTED);
+                       ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id,
+                                               (fcport->flags & FCF_CONF_COMP_SUPPORTED));
+
                        if (sess->local && !local)
                                sess->local = 0;
                        spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -796,8 +796,7 @@ static struct qla_tgt_sess *qlt_create_sess(
         */
        kref_get(&sess->se_sess->sess_kref);
 
-       sess->conf_compl_supported = !!(fcport->flags &
-           FCF_CONF_COMP_SUPPORTED);
+       sess->conf_compl_supported = (fcport->flags & FCF_CONF_COMP_SUPPORTED);
        BUILD_BUG_ON(sizeof(sess->port_name) != sizeof(fcport->port_name));
        memcpy(sess->port_name, fcport->port_name, sizeof(sess->port_name));
 
@@ -869,10 +868,8 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
                        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf007,
                            "Reappeared sess %p\n", sess);
                }
-               sess->s_id = fcport->d_id;
-               sess->loop_id = fcport->loop_id;
-               sess->conf_compl_supported = !!(fcport->flags &
-                   FCF_CONF_COMP_SUPPORTED);
+               ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id,
+                                       (fcport->flags & FCF_CONF_COMP_SUPPORTED));
        }
 
        if (sess && sess->local) {
index 170af15..bad7495 100644 (file)
@@ -648,6 +648,7 @@ struct qla_tgt_func_tmpl {
 
        int (*check_initiator_node_acl)(struct scsi_qla_host *, unsigned char *,
                                        void *, uint8_t *, uint16_t);
+       void (*update_sess)(struct qla_tgt_sess *, port_id_t, uint16_t, bool);
        struct qla_tgt_sess *(*find_sess_by_loop_id)(struct scsi_qla_host *,
                                                const uint16_t);
        struct qla_tgt_sess *(*find_sess_by_s_id)(struct scsi_qla_host *,
index 2358c16..3d74f2f 100644 (file)
@@ -237,7 +237,7 @@ static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg)
                                struct tcm_qla2xxx_tpg, se_tpg);
        struct tcm_qla2xxx_lport *lport = tpg->lport;
 
-       return &lport->lport_name[0];
+       return lport->lport_naa_name;
 }
 
 static char *tcm_qla2xxx_npiv_get_fabric_wwn(struct se_portal_group *se_tpg)
@@ -1457,6 +1457,78 @@ static int tcm_qla2xxx_check_initiator_node_acl(
        return 0;
 }
 
+static void tcm_qla2xxx_update_sess(struct qla_tgt_sess *sess, port_id_t s_id,
+                                   uint16_t loop_id, bool conf_compl_supported)
+{
+       struct qla_tgt *tgt = sess->tgt;
+       struct qla_hw_data *ha = tgt->ha;
+       struct tcm_qla2xxx_lport *lport = ha->tgt.target_lport_ptr;
+       struct se_node_acl *se_nacl = sess->se_sess->se_node_acl;
+       struct tcm_qla2xxx_nacl *nacl = container_of(se_nacl,
+                       struct tcm_qla2xxx_nacl, se_node_acl);
+       u32 key;
+
+
+       if (sess->loop_id != loop_id || sess->s_id.b24 != s_id.b24)
+               pr_info("Updating session %p from port %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x loop_id %d -> %d s_id %x:%x:%x -> %x:%x:%x\n",
+                       sess,
+                       sess->port_name[0], sess->port_name[1],
+                       sess->port_name[2], sess->port_name[3],
+                       sess->port_name[4], sess->port_name[5],
+                       sess->port_name[6], sess->port_name[7],
+                       sess->loop_id, loop_id,
+                       sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
+                       s_id.b.domain, s_id.b.area, s_id.b.al_pa);
+
+       if (sess->loop_id != loop_id) {
+               /*
+                * Because we can shuffle loop IDs around and we
+                * update different sessions non-atomically, we might
+                * have overwritten this session's old loop ID
+                * already, and we might end up overwriting some other
+                * session that will be updated later.  So we have to
+                * be extra careful and we can't warn about those things...
+                */
+               if (lport->lport_loopid_map[sess->loop_id].se_nacl == se_nacl)
+                       lport->lport_loopid_map[sess->loop_id].se_nacl = NULL;
+
+               lport->lport_loopid_map[loop_id].se_nacl = se_nacl;
+
+               sess->loop_id = loop_id;
+       }
+
+       if (sess->s_id.b24 != s_id.b24) {
+               key = (((u32) sess->s_id.b.domain << 16) |
+                      ((u32) sess->s_id.b.area   <<  8) |
+                      ((u32) sess->s_id.b.al_pa));
+
+               if (btree_lookup32(&lport->lport_fcport_map, key))
+                       WARN(btree_remove32(&lport->lport_fcport_map, key) != se_nacl,
+                            "Found wrong se_nacl when updating s_id %x:%x:%x\n",
+                            sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa);
+               else
+                       WARN(1, "No lport_fcport_map entry for s_id %x:%x:%x\n",
+                            sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa);
+
+               key = (((u32) s_id.b.domain << 16) |
+                      ((u32) s_id.b.area   <<  8) |
+                      ((u32) s_id.b.al_pa));
+
+               if (btree_lookup32(&lport->lport_fcport_map, key)) {
+                       WARN(1, "Already have lport_fcport_map entry for s_id %x:%x:%x\n",
+                            s_id.b.domain, s_id.b.area, s_id.b.al_pa);
+                       btree_update32(&lport->lport_fcport_map, key, se_nacl);
+               } else {
+                       btree_insert32(&lport->lport_fcport_map, key, se_nacl, GFP_ATOMIC);
+               }
+
+               sess->s_id = s_id;
+               nacl->nport_id = key;
+       }
+
+       sess->conf_compl_supported = conf_compl_supported;
+}
+
 /*
  * Calls into tcm_qla2xxx used by qla2xxx LLD I/O path.
  */
@@ -1467,6 +1539,7 @@ static struct qla_tgt_func_tmpl tcm_qla2xxx_template = {
        .free_cmd               = tcm_qla2xxx_free_cmd,
        .free_mcmd              = tcm_qla2xxx_free_mcmd,
        .free_session           = tcm_qla2xxx_free_session,
+       .update_sess            = tcm_qla2xxx_update_sess,
        .check_initiator_node_acl = tcm_qla2xxx_check_initiator_node_acl,
        .find_sess_by_s_id      = tcm_qla2xxx_find_sess_by_s_id,
        .find_sess_by_loop_id   = tcm_qla2xxx_find_sess_by_loop_id,
@@ -1534,6 +1607,7 @@ static struct se_wwn *tcm_qla2xxx_make_lport(
        lport->lport_wwpn = wwpn;
        tcm_qla2xxx_format_wwn(&lport->lport_name[0], TCM_QLA2XXX_NAMELEN,
                                wwpn);
+       sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) wwpn);
 
        ret = tcm_qla2xxx_init_lport(lport);
        if (ret != 0)
@@ -1601,6 +1675,7 @@ static struct se_wwn *tcm_qla2xxx_npiv_make_lport(
        lport->lport_npiv_wwnn = npiv_wwnn;
        tcm_qla2xxx_npiv_format_wwn(&lport->lport_npiv_name[0],
                        TCM_QLA2XXX_NAMELEN, npiv_wwpn, npiv_wwnn);
+       sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) npiv_wwpn);
 
 /* FIXME: tcm_qla2xxx_npiv_make_lport */
        ret = -ENOSYS;
index 8254981..9ba075f 100644 (file)
@@ -61,6 +61,8 @@ struct tcm_qla2xxx_lport {
        u64 lport_npiv_wwnn;
        /* ASCII formatted WWPN for FC Target Lport */
        char lport_name[TCM_QLA2XXX_NAMELEN];
+       /* ASCII formatted naa WWPN for VPD page 83 etc */
+       char lport_naa_name[TCM_QLA2XXX_NAMELEN];
        /* ASCII formatted WWPN+WWNN for NPIV FC Target Lport */
        char lport_npiv_name[TCM_QLA2XXX_NPIV_NAMELEN];
        /* map for fc_port pointers in 24-bit FC Port ID space */
index b191dd5..71fddbc 100644 (file)
@@ -1294,26 +1294,19 @@ static struct scsi_host_template qpti_template = {
 static const struct of_device_id qpti_match[];
 static int __devinit qpti_sbus_probe(struct platform_device *op)
 {
-       const struct of_device_id *match;
-       struct scsi_host_template *tpnt;
        struct device_node *dp = op->dev.of_node;
        struct Scsi_Host *host;
        struct qlogicpti *qpti;
        static int nqptis;
        const char *fcode;
 
-       match = of_match_device(qpti_match, &op->dev);
-       if (!match)
-               return -EINVAL;
-       tpnt = match->data;
-
        /* Sometimes Antares cards come up not completely
         * setup, and we get a report of a zero IRQ.
         */
        if (op->archdata.irqs[0] == 0)
                return -ENODEV;
 
-       host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
+       host = scsi_host_alloc(&qpti_template, sizeof(struct qlogicpti));
        if (!host)
                return -ENOMEM;
 
@@ -1445,19 +1438,15 @@ static int __devexit qpti_sbus_remove(struct platform_device *op)
 static const struct of_device_id qpti_match[] = {
        {
                .name = "ptisp",
-               .data = &qpti_template,
        },
        {
                .name = "PTI,ptisp",
-               .data = &qpti_template,
        },
        {
                .name = "QLGC,isp",
-               .data = &qpti_template,
        },
        {
                .name = "SUNW,isp",
-               .data = &qpti_template,
        },
        {},
 };
index d6ce218..035c2c7 100644 (file)
@@ -3719,7 +3719,9 @@ restart:
                 */
                iscsit_thread_check_cpumask(conn, current, 1);
 
-               schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
+               wait_event_interruptible(conn->queues_wq,
+                                        !iscsit_conn_all_queues_empty(conn) ||
+                                        ts->status == ISCSI_THREAD_SET_RESET);
 
                if ((ts->status == ISCSI_THREAD_SET_RESET) ||
                     signal_pending(current))
index 2ba9f9b..21048db 100644 (file)
@@ -486,6 +486,7 @@ struct iscsi_tmr_req {
 };
 
 struct iscsi_conn {
+       wait_queue_head_t       queues_wq;
        /* Authentication Successful for this connection */
        u8                      auth_complete;
        /* State connection is currently in */
index cdc8a10..f8dbec0 100644 (file)
@@ -41,6 +41,7 @@
 
 static int iscsi_login_init_conn(struct iscsi_conn *conn)
 {
+       init_waitqueue_head(&conn->queues_wq);
        INIT_LIST_HEAD(&conn->conn_list);
        INIT_LIST_HEAD(&conn->conn_cmd_list);
        INIT_LIST_HEAD(&conn->immed_queue_list);
index afd98cc..1a91195 100644 (file)
@@ -488,7 +488,7 @@ void iscsit_add_cmd_to_immediate_queue(
        atomic_set(&conn->check_immediate_queue, 1);
        spin_unlock_bh(&conn->immed_queue_lock);
 
-       wake_up_process(conn->thread_set->tx_thread);
+       wake_up(&conn->queues_wq);
 }
 
 struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn)
@@ -562,7 +562,7 @@ void iscsit_add_cmd_to_response_queue(
        atomic_inc(&cmd->response_queue_count);
        spin_unlock_bh(&conn->response_queue_lock);
 
-       wake_up_process(conn->thread_set->tx_thread);
+       wake_up(&conn->queues_wq);
 }
 
 struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn)
@@ -616,6 +616,24 @@ static void iscsit_remove_cmd_from_response_queue(
        }
 }
 
+bool iscsit_conn_all_queues_empty(struct iscsi_conn *conn)
+{
+       bool empty;
+
+       spin_lock_bh(&conn->immed_queue_lock);
+       empty = list_empty(&conn->immed_queue_list);
+       spin_unlock_bh(&conn->immed_queue_lock);
+
+       if (!empty)
+               return empty;
+
+       spin_lock_bh(&conn->response_queue_lock);
+       empty = list_empty(&conn->response_queue_list);
+       spin_unlock_bh(&conn->response_queue_lock);
+
+       return empty;
+}
+
 void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
 {
        struct iscsi_queue_req *qr, *qr_tmp;
index 44054bd..894d0f8 100644 (file)
@@ -25,6 +25,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_
 extern void iscsit_add_cmd_to_response_queue(struct iscsi_cmd *, struct iscsi_conn *, u8);
 extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *);
 extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *);
+extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *);
 extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
 extern void iscsit_release_cmd(struct iscsi_cmd *);
 extern void iscsit_free_cmd(struct iscsi_cmd *);
index 015f5be..c123327 100644 (file)
@@ -3206,7 +3206,8 @@ static int __init target_core_init_configfs(void)
        if (ret < 0)
                goto out;
 
-       if (core_dev_setup_virtual_lun0() < 0)
+       ret = core_dev_setup_virtual_lun0();
+       if (ret < 0)
                goto out;
 
        return 0;
index 8d774da..9abef9f 100644 (file)
@@ -850,20 +850,20 @@ int se_dev_check_shutdown(struct se_device *dev)
 
 static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
 {
-       u32 tmp, aligned_max_sectors;
+       u32 aligned_max_sectors;
+       u32 alignment;
        /*
         * Limit max_sectors to a PAGE_SIZE aligned value for modern
         * transport_allocate_data_tasks() operation.
         */
-       tmp = rounddown((max_sectors * block_size), PAGE_SIZE);
-       aligned_max_sectors = (tmp / block_size);
-       if (max_sectors != aligned_max_sectors) {
-               printk(KERN_INFO "Rounding down aligned max_sectors from %u"
-                               " to %u\n", max_sectors, aligned_max_sectors);
-               return aligned_max_sectors;
-       }
+       alignment = max(1ul, PAGE_SIZE / block_size);
+       aligned_max_sectors = rounddown(max_sectors, alignment);
+
+       if (max_sectors != aligned_max_sectors)
+               pr_info("Rounding down aligned max_sectors from %u to %u\n",
+                       max_sectors, aligned_max_sectors);
 
-       return max_sectors;
+       return aligned_max_sectors;
 }
 
 void se_dev_set_default_attribs(
index 868f8aa..a6e27d9 100644 (file)
@@ -135,6 +135,12 @@ static int sbc_emulate_verify(struct se_cmd *cmd)
        return 0;
 }
 
+static int sbc_emulate_noop(struct se_cmd *cmd)
+{
+       target_complete_cmd(cmd, GOOD);
+       return 0;
+}
+
 static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors)
 {
        return cmd->se_dev->se_sub_dev->se_dev_attrib.block_size * sectors;
@@ -531,6 +537,18 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops)
                size = 0;
                cmd->execute_cmd = sbc_emulate_verify;
                break;
+       case REZERO_UNIT:
+       case SEEK_6:
+       case SEEK_10:
+               /*
+                * There are still clients out there which use these old SCSI-2
+                * commands. This mainly happens when running VMs with legacy
+                * guest systems, connected via SCSI command pass-through to
+                * iSCSI targets. Make them happy and return status GOOD.
+                */
+               size = 0;
+               cmd->execute_cmd = sbc_emulate_noop;
+               break;
        default:
                ret = spc_parse_cdb(cmd, &size);
                if (ret)
index 9229bd9..6fd434d 100644 (file)
@@ -605,6 +605,8 @@ static int spc_emulate_inquiry(struct se_cmd *cmd)
        unsigned char buf[SE_INQUIRY_BUF];
        int p, ret;
 
+       memset(buf, 0, SE_INQUIRY_BUF);
+
        if (dev == tpg->tpg_virt_lun0.lun_se_dev)
                buf[0] = 0x3f; /* Not connected */
        else
index 1c59a3c..be75c43 100644 (file)
@@ -140,15 +140,15 @@ void core_tmr_abort_task(
                printk("ABORT_TASK: Found referenced %s task_tag: %u\n",
                        se_cmd->se_tfo->get_fabric_name(), ref_tag);
 
-               spin_lock_irq(&se_cmd->t_state_lock);
+               spin_lock(&se_cmd->t_state_lock);
                if (se_cmd->transport_state & CMD_T_COMPLETE) {
                        printk("ABORT_TASK: ref_tag: %u already complete, skipping\n", ref_tag);
-                       spin_unlock_irq(&se_cmd->t_state_lock);
+                       spin_unlock(&se_cmd->t_state_lock);
                        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
                        goto out;
                }
                se_cmd->transport_state |= CMD_T_ABORTED;
-               spin_unlock_irq(&se_cmd->t_state_lock);
+               spin_unlock(&se_cmd->t_state_lock);
 
                list_del_init(&se_cmd->se_cmd_list);
                kref_get(&se_cmd->cmd_kref);
index c33baff..9097155 100644 (file)
@@ -1616,7 +1616,6 @@ static void target_complete_tmr_failure(struct work_struct *work)
 
        se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST;
        se_cmd->se_tfo->queue_tm_rsp(se_cmd);
-       transport_generic_free_cmd(se_cmd, 0);
 }
 
 /**
index fd03e85..6dd29e4 100644 (file)
@@ -815,7 +815,7 @@ static struct platform_device_id exynos_tmu_driver_ids[] = {
        },
        { },
 };
-MODULE_DEVICE_TABLE(platform, exynos4_tmu_driver_ids);
+MODULE_DEVICE_TABLE(platform, exynos_tmu_driver_ids);
 
 static inline struct  exynos_tmu_platform_data *exynos_get_driver_data(
                        struct platform_device *pdev)
index d445271..f7a1b57 100644 (file)
@@ -210,7 +210,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
                goto error_free_priv;
        }
 
-       zone = thermal_zone_device_register("rcar_thermal", 0, priv,
+       zone = thermal_zone_device_register("rcar_thermal", 0, 0, priv,
                                            &rcar_thermal_zone_ops, 0, 0);
        if (IS_ERR(zone)) {
                dev_err(&pdev->dev, "thermal zone device is NULL\n");
index 3d7e1ee..65f891b 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/atmel_pdc.h>
 #include <linux/atmel_serial.h>
 #include <linux/uaccess.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <asm/io.h>
 #include <asm/ioctls.h>
@@ -1773,6 +1774,7 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
        struct atmel_uart_data *pdata = pdev->dev.platform_data;
        void *data;
        int ret = -ENODEV;
+       struct pinctrl *pinctrl;
 
        BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
 
@@ -1805,6 +1807,12 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
 
        atmel_init_port(port, pdev);
 
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl)) {
+               ret = PTR_ERR(pinctrl);
+               goto err;
+       }
+
        if (!atmel_use_dma_rx(&port->uart)) {
                ret = -ENOMEM;
                data = kmalloc(sizeof(struct atmel_uart_char)
index 6458764..4ec3c0d 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/ctype.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
+#include <linux/if_vlan.h>
 
 #include "u_ether.h"
 
@@ -295,7 +296,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
                while (skb2) {
                        if (status < 0
                                        || ETH_HLEN > skb2->len
-                                       || skb2->len > ETH_FRAME_LEN) {
+                                       || skb2->len > VLAN_ETH_FRAME_LEN) {
                                dev->net->stats.rx_errors++;
                                dev->net->stats.rx_length_errors++;
                                DBG(dev, "rx length %d\n", skb2->len);
index b7f5173..917bb56 100644 (file)
@@ -641,7 +641,6 @@ static void xenfb_backend_changed(struct xenbus_device *dev,
        case XenbusStateReconfiguring:
        case XenbusStateReconfigured:
        case XenbusStateUnknown:
-       case XenbusStateClosed:
                break;
 
        case XenbusStateInitWait:
@@ -670,6 +669,10 @@ InitWait:
                info->feature_resize = val;
                break;
 
+       case XenbusStateClosed:
+               if (dev->state == XenbusStateClosed)
+                       break;
+               /* Missed the backend's CLOSING state -- fallthrough */
        case XenbusStateClosing:
                xenbus_frontend_closed(dev);
                break;
index 1e8659c..809b0de 100644 (file)
@@ -225,8 +225,10 @@ EXPORT_SYMBOL_GPL(register_virtio_device);
 
 void unregister_virtio_device(struct virtio_device *dev)
 {
+       int index = dev->index; /* save for after device release */
+
        device_unregister(&dev->dev);
-       ida_simple_remove(&virtio_index_ida, dev->index);
+       ida_simple_remove(&virtio_index_ida, index);
 }
 EXPORT_SYMBOL_GPL(unregister_virtio_device);
 
index 0e86370..7435470 100644 (file)
@@ -2,6 +2,7 @@ ifneq ($(CONFIG_ARM),y)
 obj-y  += manage.o balloon.o
 obj-$(CONFIG_HOTPLUG_CPU)              += cpu_hotplug.o
 endif
+obj-$(CONFIG_X86)                      += fallback.o
 obj-y  += grant-table.o features.o events.o
 obj-y  += xenbus/
 
index 912ac81..0be4df3 100644 (file)
@@ -1395,10 +1395,10 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
 
+       irq_enter();
 #ifdef CONFIG_X86
        exit_idle();
 #endif
-       irq_enter();
 
        __xen_evtchn_do_upcall();
 
diff --git a/drivers/xen/fallback.c b/drivers/xen/fallback.c
new file mode 100644 (file)
index 0000000..0ef7c4d
--- /dev/null
@@ -0,0 +1,80 @@
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/bug.h>
+#include <linux/export.h>
+#include <asm/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+int xen_event_channel_op_compat(int cmd, void *arg)
+{
+       struct evtchn_op op;
+       int rc;
+
+       op.cmd = cmd;
+       memcpy(&op.u, arg, sizeof(op.u));
+       rc = _hypercall1(int, event_channel_op_compat, &op);
+
+       switch (cmd) {
+       case EVTCHNOP_close:
+       case EVTCHNOP_send:
+       case EVTCHNOP_bind_vcpu:
+       case EVTCHNOP_unmask:
+               /* no output */
+               break;
+
+#define COPY_BACK(eop) \
+       case EVTCHNOP_##eop: \
+               memcpy(arg, &op.u.eop, sizeof(op.u.eop)); \
+               break
+
+       COPY_BACK(bind_interdomain);
+       COPY_BACK(bind_virq);
+       COPY_BACK(bind_pirq);
+       COPY_BACK(status);
+       COPY_BACK(alloc_unbound);
+       COPY_BACK(bind_ipi);
+#undef COPY_BACK
+
+       default:
+               WARN_ON(rc != -ENOSYS);
+               break;
+       }
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(xen_event_channel_op_compat);
+
+int HYPERVISOR_physdev_op_compat(int cmd, void *arg)
+{
+       struct physdev_op op;
+       int rc;
+
+       op.cmd = cmd;
+       memcpy(&op.u, arg, sizeof(op.u));
+       rc = _hypercall1(int, physdev_op_compat, &op);
+
+       switch (cmd) {
+       case PHYSDEVOP_IRQ_UNMASK_NOTIFY:
+       case PHYSDEVOP_set_iopl:
+       case PHYSDEVOP_set_iobitmap:
+       case PHYSDEVOP_apic_write:
+               /* no output */
+               break;
+
+#define COPY_BACK(pop, fld) \
+       case PHYSDEVOP_##pop: \
+               memcpy(arg, &op.u.fld, sizeof(op.u.fld)); \
+               break
+
+       COPY_BACK(irq_status_query, irq_status_query);
+       COPY_BACK(apic_read, apic_op);
+       COPY_BACK(ASSIGN_VECTOR, irq_op);
+#undef COPY_BACK
+
+       default:
+               WARN_ON(rc != -ENOSYS);
+               break;
+       }
+
+       return rc;
+}
index 610bfc6..2e22df2 100644 (file)
@@ -105,6 +105,21 @@ static void gntdev_print_maps(struct gntdev_priv *priv,
 #endif
 }
 
+static void gntdev_free_map(struct grant_map *map)
+{
+       if (map == NULL)
+               return;
+
+       if (map->pages)
+               free_xenballooned_pages(map->count, map->pages);
+       kfree(map->pages);
+       kfree(map->grants);
+       kfree(map->map_ops);
+       kfree(map->unmap_ops);
+       kfree(map->kmap_ops);
+       kfree(map);
+}
+
 static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count)
 {
        struct grant_map *add;
@@ -142,12 +157,7 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count)
        return add;
 
 err:
-       kfree(add->pages);
-       kfree(add->grants);
-       kfree(add->map_ops);
-       kfree(add->unmap_ops);
-       kfree(add->kmap_ops);
-       kfree(add);
+       gntdev_free_map(add);
        return NULL;
 }
 
@@ -198,17 +208,9 @@ static void gntdev_put_map(struct grant_map *map)
                evtchn_put(map->notify.event);
        }
 
-       if (map->pages) {
-               if (!use_ptemod)
-                       unmap_grant_pages(map, 0, map->count);
-
-               free_xenballooned_pages(map->count, map->pages);
-       }
-       kfree(map->pages);
-       kfree(map->grants);
-       kfree(map->map_ops);
-       kfree(map->unmap_ops);
-       kfree(map);
+       if (map->pages && !use_ptemod)
+               unmap_grant_pages(map, 0, map->count);
+       gntdev_free_map(map);
 }
 
 /* ------------------------------------------------------------------ */
index 89f7625..ac72702 100644 (file)
@@ -458,7 +458,7 @@ static ssize_t xenbus_file_write(struct file *filp,
                goto out;
 
        /* Can't write a xenbus message larger we can buffer */
-       if ((len + u->len) > sizeof(u->u.buffer)) {
+       if (len > sizeof(u->u.buffer) - u->len) {
                /* On error, dump existing buffer */
                u->len = 0;
                rc = -EINVAL;
index 9298c65..b96fc6c 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -75,6 +75,7 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size)
        unsigned int sz = sizeof(struct bio) + extra_size;
        struct kmem_cache *slab = NULL;
        struct bio_slab *bslab, *new_bio_slabs;
+       unsigned int new_bio_slab_max;
        unsigned int i, entry = -1;
 
        mutex_lock(&bio_slab_lock);
@@ -97,12 +98,13 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size)
                goto out_unlock;
 
        if (bio_slab_nr == bio_slab_max && entry == -1) {
-               bio_slab_max <<= 1;
+               new_bio_slab_max = bio_slab_max << 1;
                new_bio_slabs = krealloc(bio_slabs,
-                                        bio_slab_max * sizeof(struct bio_slab),
+                                        new_bio_slab_max * sizeof(struct bio_slab),
                                         GFP_KERNEL);
                if (!new_bio_slabs)
                        goto out_unlock;
+               bio_slab_max = new_bio_slab_max;
                bio_slabs = new_bio_slabs;
        }
        if (entry == -1)
index 02ce909..9349bb3 100644 (file)
@@ -90,6 +90,8 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
                *max_len = handle_length;
                type = 255;
        }
+       if (dentry)
+               dput(dentry);
        return type;
 }
 
index fc783e2..0fb15bb 100644 (file)
@@ -225,6 +225,13 @@ sid_to_str(struct cifs_sid *sidptr, char *sidstr)
 }
 
 static void
+cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
+{
+       memcpy(dst, src, sizeof(*dst));
+       dst->num_subauth = min_t(u8, src->num_subauth, NUM_SUBAUTHS);
+}
+
+static void
 id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
                struct cifs_sid_id **psidid, char *typestr)
 {
@@ -248,7 +255,7 @@ id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
                }
        }
 
-       memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid));
+       cifs_copy_sid(&(*psidid)->sid, sidptr);
        (*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
        (*psidid)->refcount = 0;
 
@@ -354,7 +361,7 @@ id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
         * any fields of the node after a reference is put .
         */
        if (test_bit(SID_ID_MAPPED, &psidid->state)) {
-               memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid));
+               cifs_copy_sid(ssid, &psidid->sid);
                psidid->time = jiffies; /* update ts for accessing */
                goto id_sid_out;
        }
@@ -370,14 +377,14 @@ id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
                if (IS_ERR(sidkey)) {
                        rc = -EINVAL;
                        cFYI(1, "%s: Can't map and id to a SID", __func__);
+               } else if (sidkey->datalen < sizeof(struct cifs_sid)) {
+                       rc = -EIO;
+                       cFYI(1, "%s: Downcall contained malformed key "
+                               "(datalen=%hu)", __func__, sidkey->datalen);
                } else {
                        lsid = (struct cifs_sid *)sidkey->payload.data;
-                       memcpy(&psidid->sid, lsid,
-                               sidkey->datalen < sizeof(struct cifs_sid) ?
-                               sidkey->datalen : sizeof(struct cifs_sid));
-                       memcpy(ssid, &psidid->sid,
-                               sidkey->datalen < sizeof(struct cifs_sid) ?
-                               sidkey->datalen : sizeof(struct cifs_sid));
+                       cifs_copy_sid(&psidid->sid, lsid);
+                       cifs_copy_sid(ssid, &psidid->sid);
                        set_bit(SID_ID_MAPPED, &psidid->state);
                        key_put(sidkey);
                        kfree(psidid->sidstr);
@@ -396,7 +403,7 @@ id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
                        return rc;
                }
                if (test_bit(SID_ID_MAPPED, &psidid->state))
-                       memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid));
+                       cifs_copy_sid(ssid, &psidid->sid);
                else
                        rc = -EINVAL;
        }
@@ -675,8 +682,6 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
 static void copy_sec_desc(const struct cifs_ntsd *pntsd,
                                struct cifs_ntsd *pnntsd, __u32 sidsoffset)
 {
-       int i;
-
        struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
        struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
 
@@ -692,26 +697,14 @@ static void copy_sec_desc(const struct cifs_ntsd *pntsd,
        owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
                                le32_to_cpu(pntsd->osidoffset));
        nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
-
-       nowner_sid_ptr->revision = owner_sid_ptr->revision;
-       nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
-       for (i = 0; i < 6; i++)
-               nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
-       for (i = 0; i < 5; i++)
-               nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
+       cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
 
        /* copy group sid */
        group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
                                le32_to_cpu(pntsd->gsidoffset));
        ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
                                        sizeof(struct cifs_sid));
-
-       ngroup_sid_ptr->revision = group_sid_ptr->revision;
-       ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
-       for (i = 0; i < 6; i++)
-               ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
-       for (i = 0; i < 5; i++)
-               ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
+       cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
 
        return;
 }
@@ -1120,8 +1113,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
                                kfree(nowner_sid_ptr);
                                return rc;
                        }
-                       memcpy(owner_sid_ptr, nowner_sid_ptr,
-                                       sizeof(struct cifs_sid));
+                       cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
                        kfree(nowner_sid_ptr);
                        *aclflag = CIFS_ACL_OWNER;
                }
@@ -1139,8 +1131,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
                                kfree(ngroup_sid_ptr);
                                return rc;
                        }
-                       memcpy(group_sid_ptr, ngroup_sid_ptr,
-                                       sizeof(struct cifs_sid));
+                       cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
                        kfree(ngroup_sid_ptr);
                        *aclflag = CIFS_ACL_GROUP;
                }
index 7c0a812..d3671f2 100644 (file)
@@ -398,7 +398,16 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
         * in network traffic in the other paths.
         */
        if (!(oflags & O_CREAT)) {
-               struct dentry *res = cifs_lookup(inode, direntry, 0);
+               struct dentry *res;
+
+               /*
+                * Check for hashed negative dentry. We have already revalidated
+                * the dentry and it is fine. No need to perform another lookup.
+                */
+               if (!d_unhashed(direntry))
+                       return -ENOENT;
+
+               res = cifs_lookup(inode, direntry, 0);
                if (IS_ERR(res))
                        return PTR_ERR(res);
 
index da72250..cd96649 100644 (file)
@@ -346,7 +346,7 @@ static inline struct epitem *ep_item_from_epqueue(poll_table *p)
 /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */
 static inline int ep_op_has_event(int op)
 {
-       return op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD;
+       return op != EPOLL_CTL_DEL;
 }
 
 /* Initialize the poll safe wake up structure */
@@ -676,34 +676,6 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
        return 0;
 }
 
-/*
- * Disables a "struct epitem" in the eventpoll set. Returns -EBUSY if the item
- * had no event flags set, indicating that another thread may be currently
- * handling that item's events (in the case that EPOLLONESHOT was being
- * used). Otherwise a zero result indicates that the item has been disabled
- * from receiving events. A disabled item may be re-enabled via
- * EPOLL_CTL_MOD. Must be called with "mtx" held.
- */
-static int ep_disable(struct eventpoll *ep, struct epitem *epi)
-{
-       int result = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ep->lock, flags);
-       if (epi->event.events & ~EP_PRIVATE_BITS) {
-               if (ep_is_linked(&epi->rdllink))
-                       list_del_init(&epi->rdllink);
-               /* Ensure ep_poll_callback will not add epi back onto ready
-                  list: */
-               epi->event.events &= EP_PRIVATE_BITS;
-               }
-       else
-               result = -EBUSY;
-       spin_unlock_irqrestore(&ep->lock, flags);
-
-       return result;
-}
-
 static void ep_free(struct eventpoll *ep)
 {
        struct rb_node *rbp;
@@ -1048,6 +1020,8 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi)
        rb_insert_color(&epi->rbn, &ep->rbr);
 }
 
+
+
 #define PATH_ARR_SIZE 5
 /*
  * These are the number paths of length 1 to 5, that we are allowing to emanate
@@ -1813,12 +1787,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
                } else
                        error = -ENOENT;
                break;
-       case EPOLL_CTL_DISABLE:
-               if (epi)
-                       error = ep_disable(ep, epi);
-               else
-                       error = -ENOENT;
-               break;
        }
        mutex_unlock(&ep->mtx);
 
index 4facdd2..3a100e7 100644 (file)
@@ -725,6 +725,10 @@ repeat_in_this_group:
                                   "inode=%lu", ino + 1);
                        continue;
                }
+               BUFFER_TRACE(inode_bitmap_bh, "get_write_access");
+               err = ext4_journal_get_write_access(handle, inode_bitmap_bh);
+               if (err)
+                       goto fail;
                ext4_lock_group(sb, group);
                ret2 = ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data);
                ext4_unlock_group(sb, group);
@@ -738,6 +742,11 @@ repeat_in_this_group:
        goto out;
 
 got:
+       BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata");
+       err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh);
+       if (err)
+               goto fail;
+
        /* We may have to initialize the block bitmap if it isn't already */
        if (ext4_has_group_desc_csum(sb) &&
            gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
@@ -771,11 +780,6 @@ got:
                        goto fail;
        }
 
-       BUFFER_TRACE(inode_bitmap_bh, "get_write_access");
-       err = ext4_journal_get_write_access(handle, inode_bitmap_bh);
-       if (err)
-               goto fail;
-
        BUFFER_TRACE(group_desc_bh, "get_write_access");
        err = ext4_journal_get_write_access(handle, group_desc_bh);
        if (err)
@@ -823,11 +827,6 @@ got:
        }
        ext4_unlock_group(sb, group);
 
-       BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata");
-       err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh);
-       if (err)
-               goto fail;
-
        BUFFER_TRACE(group_desc_bh, "call ext4_handle_dirty_metadata");
        err = ext4_handle_dirty_metadata(handle, NULL, group_desc_bh);
        if (err)
index d3b5fa8..708d997 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -900,7 +900,7 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
                return __close_fd(files, fd);
 
        if (fd >= rlimit(RLIMIT_NOFILE))
-               return -EMFILE;
+               return -EBADF;
 
        spin_lock(&files->file_lock);
        err = expand_files(files, fd);
@@ -926,7 +926,7 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
                return -EINVAL;
 
        if (newfd >= rlimit(RLIMIT_NOFILE))
-               return -EMFILE;
+               return -EBADF;
 
        spin_lock(&files->file_lock);
        err = expand_files(files, newfd);
index 0def050..e056b4c 100644 (file)
@@ -516,15 +516,13 @@ static int gfs2_mmap(struct file *file, struct vm_area_struct *vma)
                struct gfs2_holder i_gh;
                int error;
 
-               gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
-               error = gfs2_glock_nq(&i_gh);
-               if (error == 0) {
-                       file_accessed(file);
-                       gfs2_glock_dq(&i_gh);
-               }
-               gfs2_holder_uninit(&i_gh);
+               error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
+                                          &i_gh);
                if (error)
                        return error;
+               /* grab lock to update inode */
+               gfs2_glock_dq_uninit(&i_gh);
+               file_accessed(file);
        }
        vma->vm_ops = &gfs2_vm_ops;
 
@@ -677,10 +675,8 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        size_t writesize = iov_length(iov, nr_segs);
        struct dentry *dentry = file->f_dentry;
        struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
-       struct gfs2_sbd *sdp;
        int ret;
 
-       sdp = GFS2_SB(file->f_mapping->host);
        ret = gfs2_rs_alloc(ip);
        if (ret)
                return ret;
index 8ff95a2..9ceccb1 100644 (file)
@@ -393,12 +393,10 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
        struct gfs2_meta_header *mh;
        struct gfs2_trans *tr;
 
-       lock_buffer(bd->bd_bh);
-       gfs2_log_lock(sdp);
        tr = current->journal_info;
        tr->tr_touched = 1;
        if (!list_empty(&bd->bd_list))
-               goto out;
+               return;
        set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
        set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
        mh = (struct gfs2_meta_header *)bd->bd_bh->b_data;
@@ -414,9 +412,6 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
        sdp->sd_log_num_buf++;
        list_add(&bd->bd_list, &sdp->sd_log_le_buf);
        tr->tr_num_buf_new++;
-out:
-       gfs2_log_unlock(sdp);
-       unlock_buffer(bd->bd_bh);
 }
 
 static void gfs2_check_magic(struct buffer_head *bh)
@@ -621,7 +616,6 @@ static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
 
 static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
 {
-       struct gfs2_log_descriptor *ld;
        struct gfs2_meta_header *mh;
        unsigned int offset;
        struct list_head *head = &sdp->sd_log_le_revoke;
@@ -634,7 +628,6 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
 
        length = gfs2_struct2blk(sdp, sdp->sd_log_num_revoke, sizeof(u64));
        page = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_REVOKE, length, sdp->sd_log_num_revoke);
-       ld = page_address(page);
        offset = sizeof(struct gfs2_log_descriptor);
 
        list_for_each_entry(bd, head, bd_list) {
@@ -777,12 +770,10 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
        struct address_space *mapping = bd->bd_bh->b_page->mapping;
        struct gfs2_inode *ip = GFS2_I(mapping->host);
 
-       lock_buffer(bd->bd_bh);
-       gfs2_log_lock(sdp);
        if (tr)
                tr->tr_touched = 1;
        if (!list_empty(&bd->bd_list))
-               goto out;
+               return;
        set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
        set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
        if (gfs2_is_jdata(ip)) {
@@ -793,9 +784,6 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
        } else {
                list_add_tail(&bd->bd_list, &sdp->sd_log_le_ordered);
        }
-out:
-       gfs2_log_unlock(sdp);
-       unlock_buffer(bd->bd_bh);
 }
 
 /**
index 40c4b0d..c5af8e1 100644 (file)
@@ -497,8 +497,11 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
        struct gfs2_quota_data **qd;
        int error;
 
-       if (ip->i_res == NULL)
-               gfs2_rs_alloc(ip);
+       if (ip->i_res == NULL) {
+               error = gfs2_rs_alloc(ip);
+               if (error)
+                       return error;
+       }
 
        qd = ip->i_res->rs_qa_qd;
 
index 3cc402c..38fe18f 100644 (file)
@@ -553,7 +553,6 @@ void gfs2_free_clones(struct gfs2_rgrpd *rgd)
  */
 int gfs2_rs_alloc(struct gfs2_inode *ip)
 {
-       int error = 0;
        struct gfs2_blkreserv *res;
 
        if (ip->i_res)
@@ -561,7 +560,7 @@ int gfs2_rs_alloc(struct gfs2_inode *ip)
 
        res = kmem_cache_zalloc(gfs2_rsrv_cachep, GFP_NOFS);
        if (!res)
-               error = -ENOMEM;
+               return -ENOMEM;
 
        RB_CLEAR_NODE(&res->rs_node);
 
@@ -571,7 +570,7 @@ int gfs2_rs_alloc(struct gfs2_inode *ip)
        else
                ip->i_res = res;
        up_write(&ip->i_rw_mutex);
-       return error;
+       return 0;
 }
 
 static void dump_rs(struct seq_file *seq, const struct gfs2_blkreserv *rs)
@@ -1263,7 +1262,9 @@ int gfs2_fitrim(struct file *filp, void __user *argp)
        int ret = 0;
        u64 amt;
        u64 trimmed = 0;
+       u64 start, end, minlen;
        unsigned int x;
+       unsigned bs_shift = sdp->sd_sb.sb_bsize_shift;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -1271,19 +1272,25 @@ int gfs2_fitrim(struct file *filp, void __user *argp)
        if (!blk_queue_discard(q))
                return -EOPNOTSUPP;
 
-       if (argp == NULL) {
-               r.start = 0;
-               r.len = ULLONG_MAX;
-               r.minlen = 0;
-       } else if (copy_from_user(&r, argp, sizeof(r)))
+       if (copy_from_user(&r, argp, sizeof(r)))
                return -EFAULT;
 
        ret = gfs2_rindex_update(sdp);
        if (ret)
                return ret;
 
-       rgd = gfs2_blk2rgrpd(sdp, r.start, 0);
-       rgd_end = gfs2_blk2rgrpd(sdp, r.start + r.len, 0);
+       start = r.start >> bs_shift;
+       end = start + (r.len >> bs_shift);
+       minlen = max_t(u64, r.minlen,
+                      q->limits.discard_granularity) >> bs_shift;
+
+       rgd = gfs2_blk2rgrpd(sdp, start, 0);
+       rgd_end = gfs2_blk2rgrpd(sdp, end - 1, 0);
+
+       if (end <= start ||
+           minlen > sdp->sd_max_rg_data ||
+           start > rgd_end->rd_data0 + rgd_end->rd_data)
+               return -EINVAL;
 
        while (1) {
 
@@ -1295,7 +1302,9 @@ int gfs2_fitrim(struct file *filp, void __user *argp)
                        /* Trim each bitmap in the rgrp */
                        for (x = 0; x < rgd->rd_length; x++) {
                                struct gfs2_bitmap *bi = rgd->rd_bits + x;
-                               ret = gfs2_rgrp_send_discards(sdp, rgd->rd_data0, NULL, bi, r.minlen, &amt);
+                               ret = gfs2_rgrp_send_discards(sdp,
+                                               rgd->rd_data0, NULL, bi, minlen,
+                                               &amt);
                                if (ret) {
                                        gfs2_glock_dq_uninit(&gh);
                                        goto out;
@@ -1324,7 +1333,7 @@ int gfs2_fitrim(struct file *filp, void __user *argp)
 
 out:
        r.len = trimmed << 9;
-       if (argp && copy_to_user(argp, &r, sizeof(r)))
+       if (copy_to_user(argp, &r, sizeof(r)))
                return -EFAULT;
 
        return ret;
index bc73726..d648867 100644 (file)
@@ -810,7 +810,8 @@ static void gfs2_dirty_inode(struct inode *inode, int flags)
                        return;
                }
                need_unlock = 1;
-       }
+       } else if (WARN_ON_ONCE(ip->i_gl->gl_state != LM_ST_EXCLUSIVE))
+               return;
 
        if (current->journal_info == NULL) {
                ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
index adbd278..4136270 100644 (file)
@@ -155,14 +155,22 @@ void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta)
        struct gfs2_sbd *sdp = gl->gl_sbd;
        struct gfs2_bufdata *bd;
 
+       lock_buffer(bh);
+       gfs2_log_lock(sdp);
        bd = bh->b_private;
        if (bd)
                gfs2_assert(sdp, bd->bd_gl == gl);
        else {
+               gfs2_log_unlock(sdp);
+               unlock_buffer(bh);
                gfs2_attach_bufdata(gl, bh, meta);
                bd = bh->b_private;
+               lock_buffer(bh);
+               gfs2_log_lock(sdp);
        }
        lops_add(sdp, bd);
+       gfs2_log_unlock(sdp);
+       unlock_buffer(bh);
 }
 
 void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
index 31c26c4..ca4b11e 100644 (file)
@@ -217,7 +217,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
 {
        char buf1[NFS_DNS_HOSTNAME_MAXLEN+1];
        struct nfs_dns_ent key, *item;
-       unsigned long ttl;
+       unsigned int ttl;
        ssize_t len;
        int ret = -EINVAL;
 
@@ -240,7 +240,8 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
        key.namelen = len;
        memset(&key.h, 0, sizeof(key.h));
 
-       ttl = get_expiry(&buf);
+       if (get_uint(&buf, &ttl) < 0)
+               goto out;
        if (ttl == 0)
                goto out;
        key.h.expiry_time = ttl + seconds_since_boot();
index 5c7325c..6fa01ae 100644 (file)
@@ -685,7 +685,10 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
        if (ctx->cred != NULL)
                put_rpccred(ctx->cred);
        dput(ctx->dentry);
-       nfs_sb_deactive(sb);
+       if (is_sync)
+               nfs_sb_deactive(sb);
+       else
+               nfs_sb_deactive_async(sb);
        kfree(ctx->mdsthreshold);
        kfree(ctx);
 }
index 59b133c..05521ca 100644 (file)
@@ -351,10 +351,12 @@ extern int __init register_nfs_fs(void);
 extern void __exit unregister_nfs_fs(void);
 extern void nfs_sb_active(struct super_block *sb);
 extern void nfs_sb_deactive(struct super_block *sb);
+extern void nfs_sb_deactive_async(struct super_block *sb);
 
 /* namespace.c */
+#define NFS_PATH_CANONICAL 1
 extern char *nfs_path(char **p, struct dentry *dentry,
-                     char *buffer, ssize_t buflen);
+                     char *buffer, ssize_t buflen, unsigned flags);
 extern struct vfsmount *nfs_d_automount(struct path *path);
 struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *,
                              struct nfs_fh *, struct nfs_fattr *);
@@ -498,7 +500,7 @@ static inline char *nfs_devname(struct dentry *dentry,
                                char *buffer, ssize_t buflen)
 {
        char *dummy;
-       return nfs_path(&dummy, dentry, buffer, buflen);
+       return nfs_path(&dummy, dentry, buffer, buflen, NFS_PATH_CANONICAL);
 }
 
 /*
index 8e65c7f..015f71f 100644 (file)
@@ -181,7 +181,7 @@ int nfs_mount(struct nfs_mount_request *info)
        else
                msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT];
 
-       status = rpc_call_sync(mnt_clnt, &msg, 0);
+       status = rpc_call_sync(mnt_clnt, &msg, RPC_TASK_SOFT|RPC_TASK_TIMEOUT);
        rpc_shutdown_client(mnt_clnt);
 
        if (status < 0)
index 6559253..dd057bc 100644 (file)
@@ -33,6 +33,7 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
  * @dentry - pointer to dentry
  * @buffer - result buffer
  * @buflen - length of buffer
+ * @flags - options (see below)
  *
  * Helper function for constructing the server pathname
  * by arbitrary hashed dentry.
@@ -40,8 +41,14 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
  * This is mainly for use in figuring out the path on the
  * server side when automounting on top of an existing partition
  * and in generating /proc/mounts and friends.
+ *
+ * Supported flags:
+ * NFS_PATH_CANONICAL: ensure there is exactly one slash after
+ *                    the original device (export) name
+ *                    (if unset, the original name is returned verbatim)
  */
-char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen)
+char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen,
+              unsigned flags)
 {
        char *end;
        int namelen;
@@ -74,7 +81,7 @@ rename_retry:
                rcu_read_unlock();
                goto rename_retry;
        }
-       if (*end != '/') {
+       if ((flags & NFS_PATH_CANONICAL) && *end != '/') {
                if (--buflen < 0) {
                        spin_unlock(&dentry->d_lock);
                        rcu_read_unlock();
@@ -91,9 +98,11 @@ rename_retry:
                return end;
        }
        namelen = strlen(base);
-       /* Strip off excess slashes in base string */
-       while (namelen > 0 && base[namelen - 1] == '/')
-               namelen--;
+       if (flags & NFS_PATH_CANONICAL) {
+               /* Strip off excess slashes in base string */
+               while (namelen > 0 && base[namelen - 1] == '/')
+                       namelen--;
+       }
        buflen -= namelen;
        if (buflen < 0) {
                spin_unlock(&dentry->d_lock);
index 79fbb61..1e09eb7 100644 (file)
@@ -81,7 +81,8 @@ static char *nfs_path_component(const char *nfspath, const char *end)
 static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
 {
        char *limit;
-       char *path = nfs_path(&limit, dentry, buffer, buflen);
+       char *path = nfs_path(&limit, dentry, buffer, buflen,
+                             NFS_PATH_CANONICAL);
        if (!IS_ERR(path)) {
                char *path_component = nfs_path_component(path, limit);
                if (path_component)
index 68b21d8..5eec442 100644 (file)
@@ -339,8 +339,7 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
                        dprintk("%s ERROR: %d Reset session\n", __func__,
                                errorcode);
                        nfs4_schedule_session_recovery(clp->cl_session, errorcode);
-                       exception->retry = 1;
-                       break;
+                       goto wait_on_recovery;
 #endif /* defined(CONFIG_NFS_V4_1) */
                case -NFS4ERR_FILE_OPEN:
                        if (exception->timeout > HZ) {
@@ -1572,9 +1571,11 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
        data->timestamp = jiffies;
        if (nfs4_setup_sequence(data->o_arg.server,
                                &data->o_arg.seq_args,
-                               &data->o_res.seq_res, task))
-               return;
-       rpc_call_start(task);
+                               &data->o_res.seq_res,
+                               task) != 0)
+               nfs_release_seqid(data->o_arg.seqid);
+       else
+               rpc_call_start(task);
        return;
 unlock_no_action:
        rcu_read_unlock();
@@ -1748,7 +1749,7 @@ static int nfs4_opendata_access(struct rpc_cred *cred,
 
        /* even though OPEN succeeded, access is denied. Close the file */
        nfs4_close_state(state, fmode);
-       return -NFS4ERR_ACCESS;
+       return -EACCES;
 }
 
 /*
@@ -2196,7 +2197,7 @@ static void nfs4_free_closedata(void *data)
        nfs4_put_open_state(calldata->state);
        nfs_free_seqid(calldata->arg.seqid);
        nfs4_put_state_owner(sp);
-       nfs_sb_deactive(sb);
+       nfs_sb_deactive_async(sb);
        kfree(calldata);
 }
 
@@ -2296,9 +2297,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        if (nfs4_setup_sequence(NFS_SERVER(inode),
                                &calldata->arg.seq_args,
                                &calldata->res.seq_res,
-                               task))
-               goto out;
-       rpc_call_start(task);
+                               task) != 0)
+               nfs_release_seqid(calldata->arg.seqid);
+       else
+               rpc_call_start(task);
 out:
        dprintk("%s: done!\n", __func__);
 }
@@ -4529,6 +4531,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
                        if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN)
                                rpc_restart_call_prepare(task);
        }
+       nfs_release_seqid(calldata->arg.seqid);
 }
 
 static void nfs4_locku_prepare(struct rpc_task *task, void *data)
@@ -4545,9 +4548,11 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
        calldata->timestamp = jiffies;
        if (nfs4_setup_sequence(calldata->server,
                                &calldata->arg.seq_args,
-                               &calldata->res.seq_res, task))
-               return;
-       rpc_call_start(task);
+                               &calldata->res.seq_res,
+                               task) != 0)
+               nfs_release_seqid(calldata->arg.seqid);
+       else
+               rpc_call_start(task);
 }
 
 static const struct rpc_call_ops nfs4_locku_ops = {
@@ -4692,7 +4697,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
        /* Do we need to do an open_to_lock_owner? */
        if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
                if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0)
-                       return;
+                       goto out_release_lock_seqid;
                data->arg.open_stateid = &state->stateid;
                data->arg.new_lock_owner = 1;
                data->res.open_seqid = data->arg.open_seqid;
@@ -4701,10 +4706,15 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
        data->timestamp = jiffies;
        if (nfs4_setup_sequence(data->server,
                                &data->arg.seq_args,
-                               &data->res.seq_res, task))
+                               &data->res.seq_res,
+                               task) == 0) {
+               rpc_call_start(task);
                return;
-       rpc_call_start(task);
-       dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
+       }
+       nfs_release_seqid(data->arg.open_seqid);
+out_release_lock_seqid:
+       nfs_release_seqid(data->arg.lock_seqid);
+       dprintk("%s: done!, ret = %d\n", __func__, task->tk_status);
 }
 
 static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata)
@@ -5667,7 +5677,7 @@ static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl,
                tbl->slots = new;
                tbl->max_slots = max_slots;
        }
-       tbl->highest_used_slotid = -1;  /* no slot is currently used */
+       tbl->highest_used_slotid = NFS4_NO_SLOT;
        for (i = 0; i < tbl->max_slots; i++)
                tbl->slots[i].seq_nr = ivalue;
        spin_unlock(&tbl->slot_tbl_lock);
index fe624c9..2878f97 100644 (file)
@@ -925,8 +925,8 @@ pnfs_find_alloc_layout(struct inode *ino,
        if (likely(nfsi->layout == NULL)) {     /* Won the race? */
                nfsi->layout = new;
                return new;
-       }
-       pnfs_free_layout_hdr(new);
+       } else if (new != NULL)
+               pnfs_free_layout_hdr(new);
 out_existing:
        pnfs_get_layout_hdr(nfsi->layout);
        return nfsi->layout;
index e831bce..652d3f7 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/parser.h>
 #include <linux/nsproxy.h>
 #include <linux/rcupdate.h>
+#include <linux/kthread.h>
 
 #include <asm/uaccess.h>
 
@@ -415,6 +416,54 @@ void nfs_sb_deactive(struct super_block *sb)
 }
 EXPORT_SYMBOL_GPL(nfs_sb_deactive);
 
+static int nfs_deactivate_super_async_work(void *ptr)
+{
+       struct super_block *sb = ptr;
+
+       deactivate_super(sb);
+       module_put_and_exit(0);
+       return 0;
+}
+
+/*
+ * same effect as deactivate_super, but will do final unmount in kthread
+ * context
+ */
+static void nfs_deactivate_super_async(struct super_block *sb)
+{
+       struct task_struct *task;
+       char buf[INET6_ADDRSTRLEN + 1];
+       struct nfs_server *server = NFS_SB(sb);
+       struct nfs_client *clp = server->nfs_client;
+
+       if (!atomic_add_unless(&sb->s_active, -1, 1)) {
+               rcu_read_lock();
+               snprintf(buf, sizeof(buf),
+                       rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
+               rcu_read_unlock();
+
+               __module_get(THIS_MODULE);
+               task = kthread_run(nfs_deactivate_super_async_work, sb,
+                               "%s-deactivate-super", buf);
+               if (IS_ERR(task)) {
+                       pr_err("%s: kthread_run: %ld\n",
+                               __func__, PTR_ERR(task));
+                       /* make synchronous call and hope for the best */
+                       deactivate_super(sb);
+                       module_put(THIS_MODULE);
+               }
+       }
+}
+
+void nfs_sb_deactive_async(struct super_block *sb)
+{
+       struct nfs_server *server = NFS_SB(sb);
+
+       if (atomic_dec_and_test(&server->active))
+               nfs_deactivate_super_async(sb);
+}
+EXPORT_SYMBOL_GPL(nfs_sb_deactive_async);
+
 /*
  * Deliver file system statistics to userspace
  */
@@ -771,7 +820,7 @@ int nfs_show_devname(struct seq_file *m, struct dentry *root)
        int err = 0;
        if (!page)
                return -ENOMEM;
-       devname = nfs_path(&dummy, root, page, PAGE_SIZE);
+       devname = nfs_path(&dummy, root, page, PAGE_SIZE, 0);
        if (IS_ERR(devname))
                err = PTR_ERR(devname);
        else
index 13cea63..3f79c77 100644 (file)
@@ -95,7 +95,7 @@ static void nfs_async_unlink_release(void *calldata)
 
        nfs_dec_sillycount(data->dir);
        nfs_free_unlinkdata(data);
-       nfs_sb_deactive(sb);
+       nfs_sb_deactive_async(sb);
 }
 
 static void nfs_unlink_prepare(struct rpc_task *task, void *calldata)
index f35794b..a506360 100644 (file)
@@ -21,6 +21,7 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new)
                        if ((old->path.mnt == new->path.mnt) &&
                            (old->path.dentry == new->path.dentry))
                                return true;
+                       break;
                case (FSNOTIFY_EVENT_NONE):
                        return true;
                default:
index 4f33c32..335206a 100644 (file)
@@ -1866,6 +1866,7 @@ xfs_alloc_fix_freelist(
        /*
         * Initialize the args structure.
         */
+       memset(&targs, 0, sizeof(targs));
        targs.tp = tp;
        targs.mp = mp;
        targs.agbp = agbp;
@@ -2207,7 +2208,7 @@ xfs_alloc_read_agf(
  * group or loop over the allocation groups to find the result.
  */
 int                            /* error */
-__xfs_alloc_vextent(
+xfs_alloc_vextent(
        xfs_alloc_arg_t *args)  /* allocation argument structure */
 {
        xfs_agblock_t   agsize; /* allocation group size */
@@ -2417,46 +2418,6 @@ error0:
        return error;
 }
 
-static void
-xfs_alloc_vextent_worker(
-       struct work_struct      *work)
-{
-       struct xfs_alloc_arg    *args = container_of(work,
-                                               struct xfs_alloc_arg, work);
-       unsigned long           pflags;
-
-       /* we are in a transaction context here */
-       current_set_flags_nested(&pflags, PF_FSTRANS);
-
-       args->result = __xfs_alloc_vextent(args);
-       complete(args->done);
-
-       current_restore_flags_nested(&pflags, PF_FSTRANS);
-}
-
-/*
- * Data allocation requests often come in with little stack to work on. Push
- * them off to a worker thread so there is lots of stack to use. Metadata
- * requests, OTOH, are generally from low stack usage paths, so avoid the
- * context switch overhead here.
- */
-int
-xfs_alloc_vextent(
-       struct xfs_alloc_arg    *args)
-{
-       DECLARE_COMPLETION_ONSTACK(done);
-
-       if (!args->userdata)
-               return __xfs_alloc_vextent(args);
-
-
-       args->done = &done;
-       INIT_WORK_ONSTACK(&args->work, xfs_alloc_vextent_worker);
-       queue_work(xfs_alloc_wq, &args->work);
-       wait_for_completion(&done);
-       return args->result;
-}
-
 /*
  * Free an extent.
  * Just break up the extent address and hand off to xfs_free_ag_extent
index 93be4a6..feacb06 100644 (file)
@@ -120,9 +120,6 @@ typedef struct xfs_alloc_arg {
        char            isfl;           /* set if is freelist blocks - !acctg */
        char            userdata;       /* set if this is user data */
        xfs_fsblock_t   firstblock;     /* io first block allocated */
-       struct completion *done;
-       struct work_struct work;
-       int             result;
 } xfs_alloc_arg_t;
 
 /*
index f1647ca..f7876c6 100644 (file)
@@ -121,6 +121,8 @@ xfs_allocbt_free_block(
        xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
                              XFS_EXTENT_BUSY_SKIP_DISCARD);
        xfs_trans_agbtree_delta(cur->bc_tp, -1);
+
+       xfs_trans_binval(cur->bc_tp, bp);
        return 0;
 }
 
index 848ffa7..83d0cf3 100644 (file)
@@ -2437,6 +2437,7 @@ xfs_bmap_btalloc(
         * Normal allocation, done through xfs_alloc_vextent.
         */
        tryagain = isaligned = 0;
+       memset(&args, 0, sizeof(args));
        args.tp = ap->tp;
        args.mp = mp;
        args.fsbno = ap->blkno;
@@ -3082,6 +3083,7 @@ xfs_bmap_extents_to_btree(
         * Convert to a btree with two levels, one record in root.
         */
        XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE);
+       memset(&args, 0, sizeof(args));
        args.tp = tp;
        args.mp = mp;
        args.firstblock = *firstblock;
@@ -3237,6 +3239,7 @@ xfs_bmap_local_to_extents(
                xfs_buf_t       *bp;    /* buffer for extent block */
                xfs_bmbt_rec_host_t *ep;/* extent record pointer */
 
+               memset(&args, 0, sizeof(args));
                args.tp = tp;
                args.mp = ip->i_mount;
                args.firstblock = *firstblock;
@@ -4616,12 +4619,11 @@ xfs_bmapi_delay(
 
 
 STATIC int
-xfs_bmapi_allocate(
-       struct xfs_bmalloca     *bma,
-       int                     flags)
+__xfs_bmapi_allocate(
+       struct xfs_bmalloca     *bma)
 {
        struct xfs_mount        *mp = bma->ip->i_mount;
-       int                     whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
+       int                     whichfork = (bma->flags & XFS_BMAPI_ATTRFORK) ?
                                                XFS_ATTR_FORK : XFS_DATA_FORK;
        struct xfs_ifork        *ifp = XFS_IFORK_PTR(bma->ip, whichfork);
        int                     tmp_logflags = 0;
@@ -4654,24 +4656,27 @@ xfs_bmapi_allocate(
         * Indicate if this is the first user data in the file, or just any
         * user data.
         */
-       if (!(flags & XFS_BMAPI_METADATA)) {
+       if (!(bma->flags & XFS_BMAPI_METADATA)) {
                bma->userdata = (bma->offset == 0) ?
                        XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA;
        }
 
-       bma->minlen = (flags & XFS_BMAPI_CONTIG) ? bma->length : 1;
+       bma->minlen = (bma->flags & XFS_BMAPI_CONTIG) ? bma->length : 1;
 
        /*
         * Only want to do the alignment at the eof if it is userdata and
         * allocation length is larger than a stripe unit.
         */
        if (mp->m_dalign && bma->length >= mp->m_dalign &&
-           !(flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) {
+           !(bma->flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) {
                error = xfs_bmap_isaeof(bma, whichfork);
                if (error)
                        return error;
        }
 
+       if (bma->flags & XFS_BMAPI_STACK_SWITCH)
+               bma->stack_switch = 1;
+
        error = xfs_bmap_alloc(bma);
        if (error)
                return error;
@@ -4706,7 +4711,7 @@ xfs_bmapi_allocate(
         * A wasdelay extent has been initialized, so shouldn't be flagged
         * as unwritten.
         */
-       if (!bma->wasdel && (flags & XFS_BMAPI_PREALLOC) &&
+       if (!bma->wasdel && (bma->flags & XFS_BMAPI_PREALLOC) &&
            xfs_sb_version_hasextflgbit(&mp->m_sb))
                bma->got.br_state = XFS_EXT_UNWRITTEN;
 
@@ -4734,6 +4739,45 @@ xfs_bmapi_allocate(
        return 0;
 }
 
+static void
+xfs_bmapi_allocate_worker(
+       struct work_struct      *work)
+{
+       struct xfs_bmalloca     *args = container_of(work,
+                                               struct xfs_bmalloca, work);
+       unsigned long           pflags;
+
+       /* we are in a transaction context here */
+       current_set_flags_nested(&pflags, PF_FSTRANS);
+
+       args->result = __xfs_bmapi_allocate(args);
+       complete(args->done);
+
+       current_restore_flags_nested(&pflags, PF_FSTRANS);
+}
+
+/*
+ * Some allocation requests often come in with little stack to work on. Push
+ * them off to a worker thread so there is lots of stack to use. Otherwise just
+ * call directly to avoid the context switch overhead here.
+ */
+int
+xfs_bmapi_allocate(
+       struct xfs_bmalloca     *args)
+{
+       DECLARE_COMPLETION_ONSTACK(done);
+
+       if (!args->stack_switch)
+               return __xfs_bmapi_allocate(args);
+
+
+       args->done = &done;
+       INIT_WORK_ONSTACK(&args->work, xfs_bmapi_allocate_worker);
+       queue_work(xfs_alloc_wq, &args->work);
+       wait_for_completion(&done);
+       return args->result;
+}
+
 STATIC int
 xfs_bmapi_convert_unwritten(
        struct xfs_bmalloca     *bma,
@@ -4919,6 +4963,7 @@ xfs_bmapi_write(
                        bma.conv = !!(flags & XFS_BMAPI_CONVERT);
                        bma.wasdel = wasdelay;
                        bma.offset = bno;
+                       bma.flags = flags;
 
                        /*
                         * There's a 32/64 bit type mismatch between the
@@ -4934,7 +4979,7 @@ xfs_bmapi_write(
 
                        ASSERT(len > 0);
                        ASSERT(bma.length > 0);
-                       error = xfs_bmapi_allocate(&bma, flags);
+                       error = xfs_bmapi_allocate(&bma);
                        if (error)
                                goto error0;
                        if (bma.blkno == NULLFSBLOCK)
index 803b56d..5f469c3 100644 (file)
@@ -77,6 +77,7 @@ typedef       struct xfs_bmap_free
  * from written to unwritten, otherwise convert from unwritten to written.
  */
 #define XFS_BMAPI_CONVERT      0x040
+#define XFS_BMAPI_STACK_SWITCH 0x080
 
 #define XFS_BMAPI_FLAGS \
        { XFS_BMAPI_ENTIRE,     "ENTIRE" }, \
@@ -85,7 +86,8 @@ typedef       struct xfs_bmap_free
        { XFS_BMAPI_PREALLOC,   "PREALLOC" }, \
        { XFS_BMAPI_IGSTATE,    "IGSTATE" }, \
        { XFS_BMAPI_CONTIG,     "CONTIG" }, \
-       { XFS_BMAPI_CONVERT,    "CONVERT" }
+       { XFS_BMAPI_CONVERT,    "CONVERT" }, \
+       { XFS_BMAPI_STACK_SWITCH, "STACK_SWITCH" }
 
 
 static inline int xfs_bmapi_aflag(int w)
@@ -133,6 +135,11 @@ typedef struct xfs_bmalloca {
        char                    userdata;/* set if is user data */
        char                    aeof;   /* allocated space at eof */
        char                    conv;   /* overwriting unwritten extents */
+       char                    stack_switch;
+       int                     flags;
+       struct completion       *done;
+       struct work_struct      work;
+       int                     result;
 } xfs_bmalloca_t;
 
 /*
index a8d0ed9..becf4a9 100644 (file)
@@ -526,7 +526,25 @@ xfs_buf_item_unpin(
                }
                xfs_buf_relse(bp);
        } else if (freed && remove) {
+               /*
+                * There are currently two references to the buffer - the active
+                * LRU reference and the buf log item. What we are about to do
+                * here - simulate a failed IO completion - requires 3
+                * references.
+                *
+                * The LRU reference is removed by the xfs_buf_stale() call. The
+                * buf item reference is removed by the xfs_buf_iodone()
+                * callback that is run by xfs_buf_do_callbacks() during ioend
+                * processing (via the bp->b_iodone callback), and then finally
+                * the ioend processing will drop the IO reference if the buffer
+                * is marked XBF_ASYNC.
+                *
+                * Hence we need to take an additional reference here so that IO
+                * completion processing doesn't free the buffer prematurely.
+                */
                xfs_buf_lock(bp);
+               xfs_buf_hold(bp);
+               bp->b_flags |= XBF_ASYNC;
                xfs_buf_ioerror(bp, EIO);
                XFS_BUF_UNDONE(bp);
                xfs_buf_stale(bp);
index c25b094..4beaede 100644 (file)
@@ -399,9 +399,26 @@ xfs_growfs_data_private(
 
        /* update secondary superblocks. */
        for (agno = 1; agno < nagcount; agno++) {
-               error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
+               error = 0;
+               /*
+                * new secondary superblocks need to be zeroed, not read from
+                * disk as the contents of the new area we are growing into is
+                * completely unknown.
+                */
+               if (agno < oagcount) {
+                       error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
                                  XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
                                  XFS_FSS_TO_BB(mp, 1), 0, &bp);
+               } else {
+                       bp = xfs_trans_get_buf(NULL, mp->m_ddev_targp,
+                                 XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
+                                 XFS_FSS_TO_BB(mp, 1), 0);
+                       if (bp)
+                               xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
+                       else
+                               error = ENOMEM;
+               }
+
                if (error) {
                        xfs_warn(mp,
                "error %d reading secondary superblock for ag %d",
@@ -423,7 +440,7 @@ xfs_growfs_data_private(
                        break; /* no point in continuing */
                }
        }
-       return 0;
+       return error;
 
  error0:
        xfs_trans_cancel(tp, XFS_TRANS_ABORT);
index 445bf1a..c5c4ef4 100644 (file)
@@ -250,6 +250,7 @@ xfs_ialloc_ag_alloc(
                                        /* boundary */
        struct xfs_perag *pag;
 
+       memset(&args, 0, sizeof(args));
        args.tp = tp;
        args.mp = tp->t_mountp;
 
index 2778258..1938b41 100644 (file)
@@ -1509,7 +1509,8 @@ xfs_ifree_cluster(
                 * to mark all the active inodes on the buffer stale.
                 */
                bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno,
-                                       mp->m_bsize * blks_per_cluster, 0);
+                                       mp->m_bsize * blks_per_cluster,
+                                       XBF_UNMAPPED);
 
                if (!bp)
                        return ENOMEM;
index 8305f2a..c1df3c6 100644 (file)
@@ -70,7 +70,7 @@ xfs_find_handle(
        int                     hsize;
        xfs_handle_t            handle;
        struct inode            *inode;
-       struct fd               f;
+       struct fd               f = {0};
        struct path             path;
        int                     error;
        struct xfs_inode        *ip;
index 973dff6..7f53766 100644 (file)
@@ -584,7 +584,9 @@ xfs_iomap_write_allocate(
                         * pointer that the caller gave to us.
                         */
                        error = xfs_bmapi_write(tp, ip, map_start_fsb,
-                                               count_fsb, 0, &first_block, 1,
+                                               count_fsb,
+                                               XFS_BMAPI_STACK_SWITCH,
+                                               &first_block, 1,
                                                imap, &nimaps, &free_list);
                        if (error)
                                goto trans_cancel;
index 7f4f937..4dad756 100644 (file)
@@ -2387,14 +2387,27 @@ xlog_state_do_callback(
 
 
                                /*
-                                * update the last_sync_lsn before we drop the
+                                * Completion of a iclog IO does not imply that
+                                * a transaction has completed, as transactions
+                                * can be large enough to span many iclogs. We
+                                * cannot change the tail of the log half way
+                                * through a transaction as this may be the only
+                                * transaction in the log and moving th etail to
+                                * point to the middle of it will prevent
+                                * recovery from finding the start of the
+                                * transaction. Hence we should only update the
+                                * last_sync_lsn if this iclog contains
+                                * transaction completion callbacks on it.
+                                *
+                                * We have to do this before we drop the
                                 * icloglock to ensure we are the only one that
                                 * can update it.
                                 */
                                ASSERT(XFS_LSN_CMP(atomic64_read(&log->l_last_sync_lsn),
                                        be64_to_cpu(iclog->ic_header.h_lsn)) <= 0);
-                               atomic64_set(&log->l_last_sync_lsn,
-                                       be64_to_cpu(iclog->ic_header.h_lsn));
+                               if (iclog->ic_callback)
+                                       atomic64_set(&log->l_last_sync_lsn,
+                                               be64_to_cpu(iclog->ic_header.h_lsn));
 
                        } else
                                ioerrors++;
index 5da3ace..d308749 100644 (file)
@@ -3541,7 +3541,7 @@ xlog_do_recovery_pass(
                                 *   - order is important.
                                 */
                                error = xlog_bread_offset(log, 0,
-                                               bblks - split_bblks, hbp,
+                                               bblks - split_bblks, dbp,
                                                offset + BBTOB(split_bblks));
                                if (error)
                                        goto bread_err2;
index a9432fc..2b84fc3 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/of.h>
+#include <linux/pinctrl/pinctrl.h>
 
 #ifdef CONFIG_GPIOLIB
 
@@ -134,6 +135,15 @@ struct gpio_chip {
        int (*of_xlate)(struct gpio_chip *gc,
                        const struct of_phandle_args *gpiospec, u32 *flags);
 #endif
+#ifdef CONFIG_PINCTRL
+       /*
+        * If CONFIG_PINCTRL is enabled, then gpio controllers can optionally
+        * describe the actual pin range which they serve in an SoC. This
+        * information would be used by pinctrl subsystem to configure
+        * corresponding pins for gpio usage.
+        */
+       struct list_head pin_ranges;
+#endif
 };
 
 extern const char *gpiochip_is_requested(struct gpio_chip *chip,
@@ -257,4 +267,39 @@ static inline void gpio_unexport(unsigned gpio)
 }
 #endif /* CONFIG_GPIO_SYSFS */
 
+#ifdef CONFIG_PINCTRL
+
+/**
+ * struct gpio_pin_range - pin range controlled by a gpio chip
+ * @head: list for maintaining set of pin ranges, used internally
+ * @pctldev: pinctrl device which handles corresponding pins
+ * @range: actual range of pins controlled by a gpio controller
+ */
+
+struct gpio_pin_range {
+       struct list_head node;
+       struct pinctrl_dev *pctldev;
+       struct pinctrl_gpio_range range;
+};
+
+int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+                          unsigned int pin_base, unsigned int npins);
+void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
+
+#else
+
+static inline int
+gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+                      unsigned int pin_base, unsigned int npins)
+{
+       return 0;
+}
+
+static inline void
+gpiochip_remove_pin_ranges(struct gpio_chip *chip)
+{
+}
+
+#endif /* CONFIG_PINCTRL */
+
 #endif /* _ASM_GENERIC_GPIO_H */
index 2e31e8b..7ba2762 100644 (file)
@@ -72,9 +72,9 @@ static inline int irq_to_gpio(unsigned int irq)
        return -EINVAL;
 }
 
-#endif
+#endif /* ! CONFIG_ARCH_HAVE_CUSTOM_GPIO_H */
 
-#else
+#else /* ! CONFIG_GENERIC_GPIO */
 
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -231,6 +231,20 @@ static inline int irq_to_gpio(unsigned irq)
        return -EINVAL;
 }
 
-#endif
+static inline int
+gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+                      unsigned int pin_base, unsigned int npins)
+{
+       WARN_ON(1);
+       return -EINVAL;
+}
+
+static inline void
+gpiochip_remove_pin_ranges(struct gpio_chip *chip)
+{
+       WARN_ON(1);
+}
+
+#endif /* ! CONFIG_GENERIC_GPIO */
 
 #endif /* __LINUX_GPIO_H */
diff --git a/include/linux/hashtable.h b/include/linux/hashtable.h
new file mode 100644 (file)
index 0000000..227c624
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Statically sized hash table implementation
+ * (C) 2012  Sasha Levin <levinsasha928@gmail.com>
+ */
+
+#ifndef _LINUX_HASHTABLE_H
+#define _LINUX_HASHTABLE_H
+
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/hash.h>
+#include <linux/rculist.h>
+
+#define DEFINE_HASHTABLE(name, bits)                                           \
+       struct hlist_head name[1 << (bits)] =                                   \
+                       { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
+
+#define DECLARE_HASHTABLE(name, bits)                                          \
+       struct hlist_head name[1 << (bits)]
+
+#define HASH_SIZE(name) (ARRAY_SIZE(name))
+#define HASH_BITS(name) ilog2(HASH_SIZE(name))
+
+/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */
+#define hash_min(val, bits)                                                    \
+       (sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits))
+
+static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
+{
+       unsigned int i;
+
+       for (i = 0; i < sz; i++)
+               INIT_HLIST_HEAD(&ht[i]);
+}
+
+/**
+ * hash_init - initialize a hash table
+ * @hashtable: hashtable to be initialized
+ *
+ * Calculates the size of the hashtable from the given parameter, otherwise
+ * same as hash_init_size.
+ *
+ * This has to be a macro since HASH_BITS() will not work on pointers since
+ * it calculates the size during preprocessing.
+ */
+#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable))
+
+/**
+ * hash_add - add an object to a hashtable
+ * @hashtable: hashtable to add to
+ * @node: the &struct hlist_node of the object to be added
+ * @key: the key of the object to be added
+ */
+#define hash_add(hashtable, node, key)                                         \
+       hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
+
+/**
+ * hash_add_rcu - add an object to a rcu enabled hashtable
+ * @hashtable: hashtable to add to
+ * @node: the &struct hlist_node of the object to be added
+ * @key: the key of the object to be added
+ */
+#define hash_add_rcu(hashtable, node, key)                                     \
+       hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
+
+/**
+ * hash_hashed - check whether an object is in any hashtable
+ * @node: the &struct hlist_node of the object to be checked
+ */
+static inline bool hash_hashed(struct hlist_node *node)
+{
+       return !hlist_unhashed(node);
+}
+
+static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz)
+{
+       unsigned int i;
+
+       for (i = 0; i < sz; i++)
+               if (!hlist_empty(&ht[i]))
+                       return false;
+
+       return true;
+}
+
+/**
+ * hash_empty - check whether a hashtable is empty
+ * @hashtable: hashtable to check
+ *
+ * This has to be a macro since HASH_BITS() will not work on pointers since
+ * it calculates the size during preprocessing.
+ */
+#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable))
+
+/**
+ * hash_del - remove an object from a hashtable
+ * @node: &struct hlist_node of the object to remove
+ */
+static inline void hash_del(struct hlist_node *node)
+{
+       hlist_del_init(node);
+}
+
+/**
+ * hash_del_rcu - remove an object from a rcu enabled hashtable
+ * @node: &struct hlist_node of the object to remove
+ */
+static inline void hash_del_rcu(struct hlist_node *node)
+{
+       hlist_del_init_rcu(node);
+}
+
+/**
+ * hash_for_each - iterate over a hashtable
+ * @name: hashtable to iterate
+ * @bkt: integer to use as bucket loop cursor
+ * @node: the &struct list_head to use as a loop cursor for each entry
+ * @obj: the type * to use as a loop cursor for each entry
+ * @member: the name of the hlist_node within the struct
+ */
+#define hash_for_each(name, bkt, node, obj, member)                            \
+       for ((bkt) = 0, node = NULL; node == NULL && (bkt) < HASH_SIZE(name); (bkt)++)\
+               hlist_for_each_entry(obj, node, &name[bkt], member)
+
+/**
+ * hash_for_each_rcu - iterate over a rcu enabled hashtable
+ * @name: hashtable to iterate
+ * @bkt: integer to use as bucket loop cursor
+ * @node: the &struct list_head to use as a loop cursor for each entry
+ * @obj: the type * to use as a loop cursor for each entry
+ * @member: the name of the hlist_node within the struct
+ */
+#define hash_for_each_rcu(name, bkt, node, obj, member)                                \
+       for ((bkt) = 0, node = NULL; node == NULL && (bkt) < HASH_SIZE(name); (bkt)++)\
+               hlist_for_each_entry_rcu(obj, node, &name[bkt], member)
+
+/**
+ * hash_for_each_safe - iterate over a hashtable safe against removal of
+ * hash entry
+ * @name: hashtable to iterate
+ * @bkt: integer to use as bucket loop cursor
+ * @node: the &struct list_head to use as a loop cursor for each entry
+ * @tmp: a &struct used for temporary storage
+ * @obj: the type * to use as a loop cursor for each entry
+ * @member: the name of the hlist_node within the struct
+ */
+#define hash_for_each_safe(name, bkt, node, tmp, obj, member)                  \
+       for ((bkt) = 0, node = NULL; node == NULL && (bkt) < HASH_SIZE(name); (bkt)++)\
+               hlist_for_each_entry_safe(obj, node, tmp, &name[bkt], member)
+
+/**
+ * hash_for_each_possible - iterate over all possible objects hashing to the
+ * same bucket
+ * @name: hashtable to iterate
+ * @obj: the type * to use as a loop cursor for each entry
+ * @node: the &struct list_head to use as a loop cursor for each entry
+ * @member: the name of the hlist_node within the struct
+ * @key: the key of the objects to iterate over
+ */
+#define hash_for_each_possible(name, obj, node, member, key)                   \
+       hlist_for_each_entry(obj, node, &name[hash_min(key, HASH_BITS(name))], member)
+
+/**
+ * hash_for_each_possible_rcu - iterate over all possible objects hashing to the
+ * same bucket in an rcu enabled hashtable
+ * in a rcu enabled hashtable
+ * @name: hashtable to iterate
+ * @obj: the type * to use as a loop cursor for each entry
+ * @node: the &struct list_head to use as a loop cursor for each entry
+ * @member: the name of the hlist_node within the struct
+ * @key: the key of the objects to iterate over
+ */
+#define hash_for_each_possible_rcu(name, obj, node, member, key)               \
+       hlist_for_each_entry_rcu(obj, node, &name[hash_min(key, HASH_BITS(name))], member)
+
+/**
+ * hash_for_each_possible_safe - iterate over all possible objects hashing to the
+ * same bucket safe against removals
+ * @name: hashtable to iterate
+ * @obj: the type * to use as a loop cursor for each entry
+ * @node: the &struct list_head to use as a loop cursor for each entry
+ * @tmp: a &struct used for temporary storage
+ * @member: the name of the hlist_node within the struct
+ * @key: the key of the objects to iterate over
+ */
+#define hash_for_each_possible_safe(name, obj, node, tmp, member, key)         \
+       hlist_for_each_entry_safe(obj, node, tmp,                               \
+               &name[hash_min(key, HASH_BITS(name))], member)
+
+
+#endif
index 93bfc9f..ecc5543 100644 (file)
  */
 #define KVM_MEMSLOT_INVALID    (1UL << 16)
 
-/*
- * If we support unaligned MMIO, at most one fragment will be split into two:
- */
-#ifdef KVM_UNALIGNED_MMIO
-#  define KVM_EXTRA_MMIO_FRAGMENTS 1
-#else
-#  define KVM_EXTRA_MMIO_FRAGMENTS 0
-#endif
-
-#define KVM_USER_MMIO_SIZE 8
-
-#define KVM_MAX_MMIO_FRAGMENTS \
-       (KVM_MMIO_SIZE / KVM_USER_MMIO_SIZE + KVM_EXTRA_MMIO_FRAGMENTS)
+/* Two fragments for cross MMIO pages. */
+#define KVM_MAX_MMIO_FRAGMENTS 2
 
 /*
  * For the normal pfn, the highest 12 bits should be zero,
index 7c6a113..9653166 100644 (file)
@@ -137,7 +137,7 @@ struct dw_mci {
 
        dma_addr_t              sg_dma;
        void                    *sg_cpu;
-       struct dw_mci_dma_ops   *dma_ops;
+       const struct dw_mci_dma_ops     *dma_ops;
 #ifdef CONFIG_MMC_DW_IDMAC
        unsigned int            ring_size;
 #else
@@ -162,7 +162,7 @@ struct dw_mci {
        u16                     data_offset;
        struct device           *dev;
        struct dw_mci_board     *pdata;
-       struct dw_mci_drv_data  *drv_data;
+       const struct dw_mci_drv_data    *drv_data;
        void                    *priv;
        struct clk              *biu_clk;
        struct clk              *ciu_clk;
@@ -186,7 +186,7 @@ struct dw_mci {
 
        struct regulator        *vmmc;  /* Power regulator */
        unsigned long           irq_flags; /* IRQ flags */
-       unsigned int            irq;
+       int                     irq;
 };
 
 /* DMA ops for Internal/External DMAC interface */
index fa8529a..1edcb4d 100644 (file)
@@ -91,6 +91,7 @@ struct sdhci_host {
        unsigned int quirks2;   /* More deviations from spec. */
 
 #define SDHCI_QUIRK2_HOST_OFF_CARD_ON                  (1<<0)
+#define SDHCI_QUIRK2_HOST_NO_CMD23                     (1<<1)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
index a1984dd..e20e3af 100644 (file)
@@ -28,11 +28,13 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
 #endif
 
 #else /* CONFIG_OF_ADDRESS */
+#ifndef of_address_to_resource
 static inline int of_address_to_resource(struct device_node *dev, int index,
                                         struct resource *r)
 {
        return -EINVAL;
 }
+#endif
 static inline struct device_node *of_find_matching_node_by_address(
                                        struct device_node *from,
                                        const struct of_device_id *matches,
index 7d087f0..4a58428 100644 (file)
@@ -134,6 +134,22 @@ extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
 extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
                                struct pinctrl_gpio_range *ranges,
                                unsigned nranges);
+extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
+                               struct pinctrl_gpio_range *range);
+
+extern struct pinctrl_dev *find_pinctrl_and_add_gpio_range(const char *devname,
+               struct pinctrl_gpio_range *range);
+
+#ifdef CONFIG_OF
+extern struct pinctrl_dev *of_pinctrl_get(struct device_node *np);
+#else
+static inline
+struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
+{
+       return NULL;
+}
+#endif /* CONFIG_OF */
+
 extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
 extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
 #else
index 30dea25..27a23b3 100644 (file)
  * struct u300_gpio_platform - U300 GPIO platform data
  * @ports: number of GPIO block ports
  * @gpio_base: first GPIO number for this block (use a free range)
- * @gpio_irq_base: first GPIO IRQ number for this block (use a free range)
  * @pinctrl_device: pin control device to spawn as child
  */
 struct u300_gpio_platform {
        u8 ports;
        int gpio_base;
-       int gpio_irq_base;
        struct platform_device *pinctrl_device;
 };
 
index f2dc6d8..38a9935 100644 (file)
@@ -54,7 +54,8 @@ struct ptp_clock_request {
  * clock operations
  *
  * @adjfreq:  Adjusts the frequency of the hardware clock.
- *            parameter delta: Desired period change in parts per billion.
+ *            parameter delta: Desired frequency offset from nominal frequency
+ *            in parts per billion
  *
  * @adjtime:  Shifts the time of the hardware clock.
  *            parameter delta: Desired change in nanoseconds.
index 2415a64..e69de29 100644 (file)
@@ -1,2 +0,0 @@
-header-y += md_p.h
-header-y += md_u.h
index fb1abb3..358c04b 100644 (file)
    (for example /usr/src/linux/COPYING); if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
 */
-
 #ifndef _MD_U_H
 #define _MD_U_H
 
-/*
- * Different major versions are not compatible.
- * Different minor versions are only downward compatible.
- * Different patchlevel versions are downward and upward compatible.
- */
-#define MD_MAJOR_VERSION                0
-#define MD_MINOR_VERSION                90
-/*
- * MD_PATCHLEVEL_VERSION indicates kernel functionality.
- * >=1 means different superblock formats are selectable using SET_ARRAY_INFO
- *     and major_version/minor_version accordingly
- * >=2 means that Internal bitmaps are supported by setting MD_SB_BITMAP_PRESENT
- *     in the super status byte
- * >=3 means that bitmap superblock version 4 is supported, which uses
- *     little-ending representation rather than host-endian
- */
-#define MD_PATCHLEVEL_VERSION           3
-
-/* ioctls */
-
-/* status */
-#define RAID_VERSION           _IOR (MD_MAJOR, 0x10, mdu_version_t)
-#define GET_ARRAY_INFO         _IOR (MD_MAJOR, 0x11, mdu_array_info_t)
-#define GET_DISK_INFO          _IOR (MD_MAJOR, 0x12, mdu_disk_info_t)
-#define PRINT_RAID_DEBUG       _IO (MD_MAJOR, 0x13)
-#define RAID_AUTORUN           _IO (MD_MAJOR, 0x14)
-#define GET_BITMAP_FILE                _IOR (MD_MAJOR, 0x15, mdu_bitmap_file_t)
-
-/* configuration */
-#define CLEAR_ARRAY            _IO (MD_MAJOR, 0x20)
-#define ADD_NEW_DISK           _IOW (MD_MAJOR, 0x21, mdu_disk_info_t)
-#define HOT_REMOVE_DISK                _IO (MD_MAJOR, 0x22)
-#define SET_ARRAY_INFO         _IOW (MD_MAJOR, 0x23, mdu_array_info_t)
-#define SET_DISK_INFO          _IO (MD_MAJOR, 0x24)
-#define WRITE_RAID_INFO                _IO (MD_MAJOR, 0x25)
-#define UNPROTECT_ARRAY                _IO (MD_MAJOR, 0x26)
-#define PROTECT_ARRAY          _IO (MD_MAJOR, 0x27)
-#define HOT_ADD_DISK           _IO (MD_MAJOR, 0x28)
-#define SET_DISK_FAULTY                _IO (MD_MAJOR, 0x29)
-#define HOT_GENERATE_ERROR     _IO (MD_MAJOR, 0x2a)
-#define SET_BITMAP_FILE                _IOW (MD_MAJOR, 0x2b, int)
+#include <uapi/linux/raid/md_u.h>
 
-/* usage */
-#define RUN_ARRAY              _IOW (MD_MAJOR, 0x30, mdu_param_t)
-/*  0x31 was START_ARRAY  */
-#define STOP_ARRAY             _IO (MD_MAJOR, 0x32)
-#define STOP_ARRAY_RO          _IO (MD_MAJOR, 0x33)
-#define RESTART_ARRAY_RW       _IO (MD_MAJOR, 0x34)
-
-/* 63 partitions with the alternate major number (mdp) */
-#define MdpMinorShift 6
-#ifdef __KERNEL__
 extern int mdp_major;
-#endif
-
-typedef struct mdu_version_s {
-       int major;
-       int minor;
-       int patchlevel;
-} mdu_version_t;
-
-typedef struct mdu_array_info_s {
-       /*
-        * Generic constant information
-        */
-       int major_version;
-       int minor_version;
-       int patch_version;
-       int ctime;
-       int level;
-       int size;
-       int nr_disks;
-       int raid_disks;
-       int md_minor;
-       int not_persistent;
-
-       /*
-        * Generic state information
-        */
-       int utime;              /*  0 Superblock update time                  */
-       int state;              /*  1 State bits (clean, ...)                 */
-       int active_disks;       /*  2 Number of currently active disks        */
-       int working_disks;      /*  3 Number of working disks                 */
-       int failed_disks;       /*  4 Number of failed disks                  */
-       int spare_disks;        /*  5 Number of spare disks                   */
-
-       /*
-        * Personality information
-        */
-       int layout;             /*  0 the array's physical layout             */
-       int chunk_size; /*  1 chunk size in bytes                     */
-
-} mdu_array_info_t;
-
-/* non-obvious values for 'level' */
-#define        LEVEL_MULTIPATH         (-4)
-#define        LEVEL_LINEAR            (-1)
-#define        LEVEL_FAULTY            (-5)
-
-/* we need a value for 'no level specified' and 0
- * means 'raid0', so we need something else.  This is
- * for internal use only
- */
-#define        LEVEL_NONE              (-1000000)
-
-typedef struct mdu_disk_info_s {
-       /*
-        * configuration/status of one particular disk
-        */
-       int number;
-       int major;
-       int minor;
-       int raid_disk;
-       int state;
-
-} mdu_disk_info_t;
-
-typedef struct mdu_start_info_s {
-       /*
-        * configuration/status of one particular disk
-        */
-       int major;
-       int minor;
-       int raid_disk;
-       int state;
-
-} mdu_start_info_t;
-
-typedef struct mdu_bitmap_file_s
-{
-       char pathname[4096];
-} mdu_bitmap_file_t;
-
-typedef struct mdu_param_s
-{
-       int                     personality;    /* 1,2,3,4 */
-       int                     chunk_size;     /* in bytes */
-       int                     max_fault;      /* unused for now */
-} mdu_param_t;
-
 #endif 
-
index f8cd4cf..7d5b600 100644 (file)
@@ -2652,6 +2652,15 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);
 unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc);
 
 /**
+ * ieee80211_get_mesh_hdrlen - get mesh extension header length
+ * @meshhdr: the mesh extension header, only the flags field
+ *     (first byte) will be accessed
+ * Returns the length of the extension header, which is always at
+ * least 6 bytes and at most 18 if address 5 and 6 are present.
+ */
+unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
+
+/**
  * DOC: Data path helpers
  *
  * In addition to generic utilities, cfg80211 also offers
index bc05668..93896ad 100644 (file)
@@ -132,6 +132,7 @@ struct snd_card {
        int shutdown;                   /* this card is going down */
        int free_on_last_close;         /* free in context of file_release */
        wait_queue_head_t shutdown_sleep;
+       atomic_t refcount;              /* refcount for disconnection */
        struct device *dev;             /* device assigned to this card */
        struct device *card_dev;        /* cardX object for sysfs */
 
@@ -189,6 +190,7 @@ struct snd_minor {
        const struct file_operations *f_ops;    /* file operations */
        void *private_data;             /* private data for f_ops->open */
        struct device *dev;             /* device for sysfs */
+       struct snd_card *card_ptr;      /* assigned card instance */
 };
 
 /* return a device pointer linked to each sound device as a parent */
@@ -295,6 +297,7 @@ int snd_card_info_done(void);
 int snd_component_add(struct snd_card *card, const char *component);
 int snd_card_file_add(struct snd_card *card, struct file *file);
 int snd_card_file_remove(struct snd_card *card, struct file *file);
+void snd_card_unref(struct snd_card *card);
 
 #define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
 
index 15ba03b..d06b6da 100644 (file)
@@ -377,6 +377,14 @@ DECLARE_EVENT_CLASS(xen_mmu_pgd,
 DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_pin);
 DEFINE_XEN_MMU_PGD_EVENT(xen_mmu_pgd_unpin);
 
+TRACE_EVENT(xen_mmu_flush_tlb_all,
+           TP_PROTO(int x),
+           TP_ARGS(x),
+           TP_STRUCT__entry(__array(char, x, 0)),
+           TP_fast_assign((void)x),
+           TP_printk("%s", "")
+       );
+
 TRACE_EVENT(xen_mmu_flush_tlb,
            TP_PROTO(int x),
            TP_ARGS(x),
index 8c99ce7..2c267bc 100644 (file)
@@ -25,7 +25,6 @@
 #define EPOLL_CTL_ADD 1
 #define EPOLL_CTL_DEL 2
 #define EPOLL_CTL_MOD 3
-#define EPOLL_CTL_DISABLE 4
 
 /*
  * Request the handling of system wakeup events so as to prevent system suspends
index aafaa5a..e2c3d25 100644 (file)
@@ -1 +1,3 @@
 # UAPI Header export list
+header-y += md_p.h
+header-y += md_u.h
diff --git a/include/uapi/linux/raid/md_u.h b/include/uapi/linux/raid/md_u.h
new file mode 100644 (file)
index 0000000..4133e74
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+   md_u.h : user <=> kernel API between Linux raidtools and RAID drivers
+          Copyright (C) 1998 Ingo Molnar
+         
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+*/
+
+#ifndef _UAPI_MD_U_H
+#define _UAPI_MD_U_H
+
+/*
+ * Different major versions are not compatible.
+ * Different minor versions are only downward compatible.
+ * Different patchlevel versions are downward and upward compatible.
+ */
+#define MD_MAJOR_VERSION                0
+#define MD_MINOR_VERSION                90
+/*
+ * MD_PATCHLEVEL_VERSION indicates kernel functionality.
+ * >=1 means different superblock formats are selectable using SET_ARRAY_INFO
+ *     and major_version/minor_version accordingly
+ * >=2 means that Internal bitmaps are supported by setting MD_SB_BITMAP_PRESENT
+ *     in the super status byte
+ * >=3 means that bitmap superblock version 4 is supported, which uses
+ *     little-ending representation rather than host-endian
+ */
+#define MD_PATCHLEVEL_VERSION           3
+
+/* ioctls */
+
+/* status */
+#define RAID_VERSION           _IOR (MD_MAJOR, 0x10, mdu_version_t)
+#define GET_ARRAY_INFO         _IOR (MD_MAJOR, 0x11, mdu_array_info_t)
+#define GET_DISK_INFO          _IOR (MD_MAJOR, 0x12, mdu_disk_info_t)
+#define PRINT_RAID_DEBUG       _IO (MD_MAJOR, 0x13)
+#define RAID_AUTORUN           _IO (MD_MAJOR, 0x14)
+#define GET_BITMAP_FILE                _IOR (MD_MAJOR, 0x15, mdu_bitmap_file_t)
+
+/* configuration */
+#define CLEAR_ARRAY            _IO (MD_MAJOR, 0x20)
+#define ADD_NEW_DISK           _IOW (MD_MAJOR, 0x21, mdu_disk_info_t)
+#define HOT_REMOVE_DISK                _IO (MD_MAJOR, 0x22)
+#define SET_ARRAY_INFO         _IOW (MD_MAJOR, 0x23, mdu_array_info_t)
+#define SET_DISK_INFO          _IO (MD_MAJOR, 0x24)
+#define WRITE_RAID_INFO                _IO (MD_MAJOR, 0x25)
+#define UNPROTECT_ARRAY                _IO (MD_MAJOR, 0x26)
+#define PROTECT_ARRAY          _IO (MD_MAJOR, 0x27)
+#define HOT_ADD_DISK           _IO (MD_MAJOR, 0x28)
+#define SET_DISK_FAULTY                _IO (MD_MAJOR, 0x29)
+#define HOT_GENERATE_ERROR     _IO (MD_MAJOR, 0x2a)
+#define SET_BITMAP_FILE                _IOW (MD_MAJOR, 0x2b, int)
+
+/* usage */
+#define RUN_ARRAY              _IOW (MD_MAJOR, 0x30, mdu_param_t)
+/*  0x31 was START_ARRAY  */
+#define STOP_ARRAY             _IO (MD_MAJOR, 0x32)
+#define STOP_ARRAY_RO          _IO (MD_MAJOR, 0x33)
+#define RESTART_ARRAY_RW       _IO (MD_MAJOR, 0x34)
+
+/* 63 partitions with the alternate major number (mdp) */
+#define MdpMinorShift 6
+
+typedef struct mdu_version_s {
+       int major;
+       int minor;
+       int patchlevel;
+} mdu_version_t;
+
+typedef struct mdu_array_info_s {
+       /*
+        * Generic constant information
+        */
+       int major_version;
+       int minor_version;
+       int patch_version;
+       int ctime;
+       int level;
+       int size;
+       int nr_disks;
+       int raid_disks;
+       int md_minor;
+       int not_persistent;
+
+       /*
+        * Generic state information
+        */
+       int utime;              /*  0 Superblock update time                  */
+       int state;              /*  1 State bits (clean, ...)                 */
+       int active_disks;       /*  2 Number of currently active disks        */
+       int working_disks;      /*  3 Number of working disks                 */
+       int failed_disks;       /*  4 Number of failed disks                  */
+       int spare_disks;        /*  5 Number of spare disks                   */
+
+       /*
+        * Personality information
+        */
+       int layout;             /*  0 the array's physical layout             */
+       int chunk_size; /*  1 chunk size in bytes                     */
+
+} mdu_array_info_t;
+
+/* non-obvious values for 'level' */
+#define        LEVEL_MULTIPATH         (-4)
+#define        LEVEL_LINEAR            (-1)
+#define        LEVEL_FAULTY            (-5)
+
+/* we need a value for 'no level specified' and 0
+ * means 'raid0', so we need something else.  This is
+ * for internal use only
+ */
+#define        LEVEL_NONE              (-1000000)
+
+typedef struct mdu_disk_info_s {
+       /*
+        * configuration/status of one particular disk
+        */
+       int number;
+       int major;
+       int minor;
+       int raid_disk;
+       int state;
+
+} mdu_disk_info_t;
+
+typedef struct mdu_start_info_s {
+       /*
+        * configuration/status of one particular disk
+        */
+       int major;
+       int minor;
+       int raid_disk;
+       int state;
+
+} mdu_start_info_t;
+
+typedef struct mdu_bitmap_file_s
+{
+       char pathname[4096];
+} mdu_bitmap_file_t;
+
+typedef struct mdu_param_s
+{
+       int                     personality;    /* 1,2,3,4 */
+       int                     chunk_size;     /* in bytes */
+       int                     max_fault;      /* unused for now */
+} mdu_param_t;
+
+#endif /* _UAPI_MD_U_H */
index b193fa2..13e43e4 100644 (file)
@@ -5,6 +5,36 @@
 #include <xen/interface/hvm/params.h>
 #include <asm/xen/hypercall.h>
 
+static const char *param_name(int op)
+{
+#define PARAM(x) [HVM_PARAM_##x] = #x
+       static const char *const names[] = {
+               PARAM(CALLBACK_IRQ),
+               PARAM(STORE_PFN),
+               PARAM(STORE_EVTCHN),
+               PARAM(PAE_ENABLED),
+               PARAM(IOREQ_PFN),
+               PARAM(BUFIOREQ_PFN),
+               PARAM(TIMER_MODE),
+               PARAM(HPET_ENABLED),
+               PARAM(IDENT_PT),
+               PARAM(DM_DOMAIN),
+               PARAM(ACPI_S_STATE),
+               PARAM(VM86_TSS),
+               PARAM(VPT_ALIGN),
+               PARAM(CONSOLE_PFN),
+               PARAM(CONSOLE_EVTCHN),
+       };
+#undef PARAM
+
+       if (op >= ARRAY_SIZE(names))
+               return "unknown";
+
+       if (!names[op])
+               return "reserved";
+
+       return names[op];
+}
 static inline int hvm_get_parameter(int idx, uint64_t *value)
 {
        struct xen_hvm_param xhv;
@@ -14,8 +44,8 @@ static inline int hvm_get_parameter(int idx, uint64_t *value)
        xhv.index = idx;
        r = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv);
        if (r < 0) {
-               printk(KERN_ERR "Cannot get hvm parameter %d: %d!\n",
-                       idx, r);
+               printk(KERN_ERR "Cannot get hvm parameter %s (%d): %d!\n",
+                       param_name(idx), idx, r);
                return r;
        }
        *value = xhv.value;
index 9cf77ab..e33e09d 100644 (file)
@@ -442,9 +442,11 @@ void __init __weak smp_setup_processor_id(void)
 {
 }
 
+# if THREAD_SIZE >= PAGE_SIZE
 void __init __weak thread_info_cache_init(void)
 {
 }
+#endif
 
 /*
  * Set up kernel memory allocators
index 6085f5e..6e48c3a 100644 (file)
@@ -2293,12 +2293,17 @@ static void layout_symtab(struct module *mod, struct load_info *info)
        src = (void *)info->hdr + symsect->sh_offset;
        nsrc = symsect->sh_size / sizeof(*src);
 
+       /* strtab always starts with a nul, so offset 0 is the empty string. */
+       strtab_size = 1;
+
        /* Compute total space required for the core symbols' strtab. */
-       for (ndst = i = strtab_size = 1; i < nsrc; ++i, ++src)
-               if (is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) {
-                       strtab_size += strlen(&info->strtab[src->st_name]) + 1;
+       for (ndst = i = 0; i < nsrc; i++) {
+               if (i == 0 ||
+                   is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
+                       strtab_size += strlen(&info->strtab[src[i].st_name])+1;
                        ndst++;
                }
+       }
 
        /* Append room for core symbols at end of core part. */
        info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
@@ -2332,15 +2337,15 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
        mod->core_symtab = dst = mod->module_core + info->symoffs;
        mod->core_strtab = s = mod->module_core + info->stroffs;
        src = mod->symtab;
-       *dst = *src;
        *s++ = 0;
-       for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) {
-               if (!is_core_symbol(src, info->sechdrs, info->hdr->e_shnum))
-                       continue;
-
-               dst[ndst] = *src;
-               dst[ndst++].st_name = s - mod->core_strtab;
-               s += strlcpy(s, &mod->strtab[src->st_name], KSYM_NAME_LEN) + 1;
+       for (ndst = i = 0; i < mod->num_symtab; i++) {
+               if (i == 0 ||
+                   is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
+                       dst[ndst] = src[i];
+                       dst[ndst++].st_name = s - mod->core_strtab;
+                       s += strlcpy(s, &mod->strtab[src[i].st_name],
+                                    KSYM_NAME_LEN) + 1;
+               }
        }
        mod->core_num_syms = ndst;
 }
index 2624edc..8b055e9 100644 (file)
@@ -3017,6 +3017,8 @@ static int kswapd(void *p)
                                                &balanced_classzone_idx);
                }
        }
+
+       current->reclaim_state = NULL;
        return 0;
 }
 
index 159aa8b..3ef1759 100644 (file)
@@ -2300,10 +2300,11 @@ restart:
                        mutex_unlock(&con->mutex);
                        return;
                } else {
-                       con->ops->put(con);
                        dout("con_work %p FAILED to back off %lu\n", con,
                             con->delay);
+                       set_bit(CON_FLAG_BACKOFF, &con->flags);
                }
+               goto done;
        }
 
        if (con->state == CON_STATE_STANDBY) {
@@ -2749,7 +2750,8 @@ static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip)
                msg = con->ops->alloc_msg(con, hdr, skip);
                mutex_lock(&con->mutex);
                if (con->state != CON_STATE_OPEN) {
-                       ceph_msg_put(msg);
+                       if (msg)
+                               ceph_msg_put(msg);
                        return -EAGAIN;
                }
                con->in_msg = msg;
index 09cb3f6..bda6d00 100644 (file)
@@ -1666,7 +1666,7 @@ static inline int deliver_skb(struct sk_buff *skb,
 
 static inline bool skb_loop_sk(struct packet_type *ptype, struct sk_buff *skb)
 {
-       if (ptype->af_packet_priv == NULL)
+       if (!ptype->af_packet_priv || !skb->sk)
                return false;
 
        if (ptype->id_match)
index 76d4c2c..fad649a 100644 (file)
@@ -2192,7 +2192,8 @@ static int nlmsg_populate_fdb(struct sk_buff *skb,
                        goto skip;
 
                err = nlmsg_populate_fdb_fill(skb, dev, ha->addr,
-                                             portid, seq, 0, NTF_SELF);
+                                             portid, seq,
+                                             RTM_NEWNEIGH, NTF_SELF);
                if (err < 0)
                        return err;
 skip:
index 535584c..0c34bfa 100644 (file)
@@ -892,13 +892,16 @@ static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
                struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        const struct inet_diag_handler *handler;
+       int err = 0;
 
        handler = inet_diag_lock_handler(r->sdiag_protocol);
        if (!IS_ERR(handler))
                handler->dump(skb, cb, r, bc);
+       else
+               err = PTR_ERR(handler);
        inet_diag_unlock_handler(handler);
 
-       return skb->len;
+       return err ? : skb->len;
 }
 
 static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
index 9e0ffaf..a820472 100644 (file)
@@ -184,7 +184,8 @@ nf_nat_ipv4_out(unsigned int hooknum,
 
                if ((ct->tuplehash[dir].tuple.src.u3.ip !=
                     ct->tuplehash[!dir].tuple.dst.u3.ip) ||
-                   (ct->tuplehash[dir].tuple.src.u.all !=
+                   (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
+                    ct->tuplehash[dir].tuple.src.u.all !=
                     ct->tuplehash[!dir].tuple.dst.u.all))
                        if (nf_xfrm_me_harder(skb, AF_INET) < 0)
                                ret = NF_DROP;
@@ -221,6 +222,7 @@ nf_nat_ipv4_local_fn(unsigned int hooknum,
                }
 #ifdef CONFIG_XFRM
                else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
+                        ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
                         ct->tuplehash[dir].tuple.dst.u.all !=
                         ct->tuplehash[!dir].tuple.src.u.all)
                        if (nf_xfrm_me_harder(skb, AF_INET) < 0)
index 813b43a..834857f 100644 (file)
@@ -313,11 +313,13 @@ static void tcp_illinois_info(struct sock *sk, u32 ext,
                        .tcpv_rttcnt = ca->cnt_rtt,
                        .tcpv_minrtt = ca->base_rtt,
                };
-               u64 t = ca->sum_rtt;
 
-               do_div(t, ca->cnt_rtt);
-               info.tcpv_rtt = t;
+               if (info.tcpv_rttcnt > 0) {
+                       u64 t = ca->sum_rtt;
 
+                       do_div(t, info.tcpv_rttcnt);
+                       info.tcpv_rtt = t;
+               }
                nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info);
        }
 }
index 1db6639..2c2b13a 100644 (file)
@@ -4529,6 +4529,9 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
        struct tcphdr *th;
        bool fragstolen;
 
+       if (size == 0)
+               return 0;
+
        skb = alloc_skb(size + sizeof(*th), sk->sk_allocation);
        if (!skb)
                goto err;
index 4c752a6..53bc584 100644 (file)
@@ -864,7 +864,7 @@ static int parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr,
        }
        a = info->attrs[TCP_METRICS_ATTR_ADDR_IPV6];
        if (a) {
-               if (nla_len(a) != sizeof(sizeof(struct in6_addr)))
+               if (nla_len(a) != sizeof(struct in6_addr))
                        return -EINVAL;
                addr->family = AF_INET6;
                memcpy(addr->addr.a6, nla_data(a), sizeof(addr->addr.a6));
index 0185679..d5cb3c4 100644 (file)
@@ -1633,9 +1633,9 @@ static size_t ip6gre_get_size(const struct net_device *dev)
                /* IFLA_GRE_OKEY */
                nla_total_size(4) +
                /* IFLA_GRE_LOCAL */
-               nla_total_size(4) +
+               nla_total_size(sizeof(struct in6_addr)) +
                /* IFLA_GRE_REMOTE */
-               nla_total_size(4) +
+               nla_total_size(sizeof(struct in6_addr)) +
                /* IFLA_GRE_TTL */
                nla_total_size(1) +
                /* IFLA_GRE_TOS */
@@ -1659,8 +1659,8 @@ static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev)
            nla_put_be16(skb, IFLA_GRE_OFLAGS, p->o_flags) ||
            nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
            nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
-           nla_put(skb, IFLA_GRE_LOCAL, sizeof(struct in6_addr), &p->raddr) ||
-           nla_put(skb, IFLA_GRE_REMOTE, sizeof(struct in6_addr), &p->laddr) ||
+           nla_put(skb, IFLA_GRE_LOCAL, sizeof(struct in6_addr), &p->laddr) ||
+           nla_put(skb, IFLA_GRE_REMOTE, sizeof(struct in6_addr), &p->raddr) ||
            nla_put_u8(skb, IFLA_GRE_TTL, p->hop_limit) ||
            /*nla_put_u8(skb, IFLA_GRE_TOS, t->priority) ||*/
            nla_put_u8(skb, IFLA_GRE_ENCAP_LIMIT, p->encap_limit) ||
index ff36194..2edce30 100644 (file)
@@ -535,7 +535,7 @@ static void ndisc_send_unsol_na(struct net_device *dev)
 {
        struct inet6_dev *idev;
        struct inet6_ifaddr *ifa;
-       struct in6_addr mcaddr;
+       struct in6_addr mcaddr = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
 
        idev = in6_dev_get(dev);
        if (!idev)
@@ -543,7 +543,6 @@ static void ndisc_send_unsol_na(struct net_device *dev)
 
        read_lock_bh(&idev->lock);
        list_for_each_entry(ifa, &idev->addr_list, if_list) {
-               addrconf_addr_solict_mult(&ifa->addr, &mcaddr);
                ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr,
                              /*router=*/ !!idev->cnf.forwarding,
                              /*solicited=*/ false, /*override=*/ true,
index e418bd6..d57dab1 100644 (file)
@@ -186,7 +186,8 @@ nf_nat_ipv6_out(unsigned int hooknum,
 
                if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
                                      &ct->tuplehash[!dir].tuple.dst.u3) ||
-                   (ct->tuplehash[dir].tuple.src.u.all !=
+                   (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
+                    ct->tuplehash[dir].tuple.src.u.all !=
                     ct->tuplehash[!dir].tuple.dst.u.all))
                        if (nf_xfrm_me_harder(skb, AF_INET6) < 0)
                                ret = NF_DROP;
@@ -222,6 +223,7 @@ nf_nat_ipv6_local_fn(unsigned int hooknum,
                }
 #ifdef CONFIG_XFRM
                else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
+                        ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
                         ct->tuplehash[dir].tuple.dst.u.all !=
                         ct->tuplehash[!dir].tuple.src.u.all)
                        if (nf_xfrm_me_harder(skb, AF_INET6))
index 18bd9bb..22c8ea9 100644 (file)
@@ -85,7 +85,7 @@ static struct ctl_table nf_ct_frag6_sysctl_table[] = {
        { }
 };
 
-static int __net_init nf_ct_frag6_sysctl_register(struct net *net)
+static int nf_ct_frag6_sysctl_register(struct net *net)
 {
        struct ctl_table *table;
        struct ctl_table_header *hdr;
@@ -127,7 +127,7 @@ static void __net_exit nf_ct_frags6_sysctl_unregister(struct net *net)
 }
 
 #else
-static int __net_init nf_ct_frag6_sysctl_register(struct net *net)
+static int nf_ct_frag6_sysctl_register(struct net *net)
 {
        return 0;
 }
index 37b8b8b..76125c5 100644 (file)
@@ -291,6 +291,7 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p
 
 out_del_dev:
        free_netdev(dev);
+       spriv->dev = NULL;
 out_del_session:
        l2tp_session_delete(session);
 out:
index 5f3620f..bf87c70 100644 (file)
@@ -1108,7 +1108,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;
        sdata->u.ibss.ibss_join_req = jiffies;
 
-       memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN);
+       memcpy(sdata->u.ibss.ssid, params->ssid, params->ssid_len);
        sdata->u.ibss.ssid_len = params->ssid_len;
 
        mutex_unlock(&sdata->u.ibss.mtx);
index 61c621e..00ade7f 100644 (file)
@@ -531,6 +531,11 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 
                if (ieee80211_is_action(hdr->frame_control)) {
                        u8 category;
+
+                       /* make sure category field is present */
+                       if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
+                               return RX_DROP_MONITOR;
+
                        mgmt = (struct ieee80211_mgmt *)hdr;
                        category = mgmt->u.action.category;
                        if (category != WLAN_CATEGORY_MESH_ACTION &&
@@ -883,14 +888,16 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                 */
                if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
                    ieee80211_is_data_present(hdr->frame_control)) {
-                       u16 ethertype;
-                       u8 *payload;
-
-                       payload = rx->skb->data +
-                               ieee80211_hdrlen(hdr->frame_control);
-                       ethertype = (payload[6] << 8) | payload[7];
-                       if (cpu_to_be16(ethertype) ==
-                           rx->sdata->control_port_protocol)
+                       unsigned int hdrlen;
+                       __be16 ethertype;
+
+                       hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+                       if (rx->skb->len < hdrlen + 8)
+                               return RX_DROP_MONITOR;
+
+                       skb_copy_bits(rx->skb, hdrlen + 6, &ethertype, 2);
+                       if (ethertype == rx->sdata->control_port_protocol)
                                return RX_CONTINUE;
                }
 
@@ -1462,11 +1469,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
 
        hdr = (struct ieee80211_hdr *)rx->skb->data;
        fc = hdr->frame_control;
+
+       if (ieee80211_is_ctl(fc))
+               return RX_CONTINUE;
+
        sc = le16_to_cpu(hdr->seq_ctrl);
        frag = sc & IEEE80211_SCTL_FRAG;
 
        if (likely((!ieee80211_has_morefrags(fc) && frag == 0) ||
-                  (rx->skb)->len < 24 ||
                   is_multicast_ether_addr(hdr->addr1))) {
                /* not fragmented */
                goto out;
@@ -1889,6 +1899,20 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+       /* make sure fixed part of mesh header is there, also checks skb len */
+       if (!pskb_may_pull(rx->skb, hdrlen + 6))
+               return RX_DROP_MONITOR;
+
+       mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+
+       /* make sure full mesh header is there, also checks skb len */
+       if (!pskb_may_pull(rx->skb,
+                          hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr)))
+               return RX_DROP_MONITOR;
+
+       /* reload pointers */
+       hdr = (struct ieee80211_hdr *) skb->data;
        mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
 
        /* frame is in RMC, don't forward */
@@ -1897,7 +1921,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata))
                return RX_DROP_MONITOR;
 
-       if (!ieee80211_is_data(hdr->frame_control))
+       if (!ieee80211_is_data(hdr->frame_control) ||
+           !(status->rx_flags & IEEE80211_RX_RA_MATCH))
                return RX_CONTINUE;
 
        if (!mesh_hdr->ttl)
@@ -1911,9 +1936,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                if (is_multicast_ether_addr(hdr->addr1)) {
                        mpp_addr = hdr->addr3;
                        proxied_addr = mesh_hdr->eaddr1;
-               } else {
+               } else if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6) {
+                       /* has_a4 already checked in ieee80211_rx_mesh_check */
                        mpp_addr = hdr->addr4;
                        proxied_addr = mesh_hdr->eaddr2;
+               } else {
+                       return RX_DROP_MONITOR;
                }
 
                rcu_read_lock();
@@ -1941,12 +1969,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        }
        skb_set_queue_mapping(skb, q);
 
-       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
-               goto out;
-
        if (!--mesh_hdr->ttl) {
                IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
-               return RX_DROP_MONITOR;
+               goto out;
        }
 
        if (!ifmsh->mshcfg.dot11MeshForwarding)
@@ -2353,6 +2378,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                }
                break;
        case WLAN_CATEGORY_SELF_PROTECTED:
+               if (len < (IEEE80211_MIN_ACTION_SIZE +
+                          sizeof(mgmt->u.action.u.self_prot.action_code)))
+                       break;
+
                switch (mgmt->u.action.u.self_prot.action_code) {
                case WLAN_SP_MESH_PEERING_OPEN:
                case WLAN_SP_MESH_PEERING_CLOSE:
@@ -2371,6 +2400,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                }
                break;
        case WLAN_CATEGORY_MESH_ACTION:
+               if (len < (IEEE80211_MIN_ACTION_SIZE +
+                          sizeof(mgmt->u.action.u.mesh_action.action_code)))
+                       break;
+
                if (!ieee80211_vif_is_mesh(&sdata->vif))
                        break;
                if (mesh_action_is_path_sel(mgmt) &&
@@ -2913,10 +2946,15 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
                local->dot11ReceivedFragmentCount++;
 
-       if (ieee80211_is_mgmt(fc))
-               err = skb_linearize(skb);
-       else
+       if (ieee80211_is_mgmt(fc)) {
+               /* drop frame if too short for header */
+               if (skb->len < ieee80211_hdrlen(fc))
+                       err = -ENOBUFS;
+               else
+                       err = skb_linearize(skb);
+       } else {
                err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
+       }
 
        if (err) {
                dev_kfree_skb(skb);
index 94e5868..2393918 100644 (file)
@@ -643,13 +643,41 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
                        break;
                }
 
-               if (id != WLAN_EID_VENDOR_SPECIFIC &&
-                   id != WLAN_EID_QUIET &&
-                   test_bit(id, seen_elems)) {
-                       elems->parse_error = true;
-                       left -= elen;
-                       pos += elen;
-                       continue;
+               switch (id) {
+               case WLAN_EID_SSID:
+               case WLAN_EID_SUPP_RATES:
+               case WLAN_EID_FH_PARAMS:
+               case WLAN_EID_DS_PARAMS:
+               case WLAN_EID_CF_PARAMS:
+               case WLAN_EID_TIM:
+               case WLAN_EID_IBSS_PARAMS:
+               case WLAN_EID_CHALLENGE:
+               case WLAN_EID_RSN:
+               case WLAN_EID_ERP_INFO:
+               case WLAN_EID_EXT_SUPP_RATES:
+               case WLAN_EID_HT_CAPABILITY:
+               case WLAN_EID_HT_OPERATION:
+               case WLAN_EID_VHT_CAPABILITY:
+               case WLAN_EID_VHT_OPERATION:
+               case WLAN_EID_MESH_ID:
+               case WLAN_EID_MESH_CONFIG:
+               case WLAN_EID_PEER_MGMT:
+               case WLAN_EID_PREQ:
+               case WLAN_EID_PREP:
+               case WLAN_EID_PERR:
+               case WLAN_EID_RANN:
+               case WLAN_EID_CHANNEL_SWITCH:
+               case WLAN_EID_EXT_CHANSWITCH_ANN:
+               case WLAN_EID_COUNTRY:
+               case WLAN_EID_PWR_CONSTRAINT:
+               case WLAN_EID_TIMEOUT_INTERVAL:
+                       if (test_bit(id, seen_elems)) {
+                               elems->parse_error = true;
+                               left -= elen;
+                               pos += elen;
+                               continue;
+                       }
+                       break;
                }
 
                if (calc_crc && id < 64 && (filter & (1ULL << id)))
index 1b30b0d..962795e 100644 (file)
@@ -753,7 +753,8 @@ static int callforward_do_filter(const union nf_inet_addr *src,
                                   flowi4_to_flowi(&fl1), false)) {
                        if (!afinfo->route(&init_net, (struct dst_entry **)&rt2,
                                           flowi4_to_flowi(&fl2), false)) {
-                               if (rt1->rt_gateway == rt2->rt_gateway &&
+                               if (rt_nexthop(rt1, fl1.daddr) ==
+                                   rt_nexthop(rt2, fl2.daddr) &&
                                    rt1->dst.dev  == rt2->dst.dev)
                                        ret = 1;
                                dst_release(&rt2->dst);
index f0dd83c..9687fa1 100644 (file)
  * grp->index is the index of the group; and grp->slot_shift
  * is the shift for the corresponding (scaled) sigma_i.
  */
-#define QFQ_MAX_INDEX          19
-#define QFQ_MAX_WSHIFT         16
+#define QFQ_MAX_INDEX          24
+#define QFQ_MAX_WSHIFT         12
 
 #define        QFQ_MAX_WEIGHT          (1<<QFQ_MAX_WSHIFT)
-#define QFQ_MAX_WSUM           (2*QFQ_MAX_WEIGHT)
+#define QFQ_MAX_WSUM           (16*QFQ_MAX_WEIGHT)
 
 #define FRAC_BITS              30      /* fixed point arithmetic */
 #define ONE_FP                 (1UL << FRAC_BITS)
 #define IWSUM                  (ONE_FP/QFQ_MAX_WSUM)
 
-#define QFQ_MTU_SHIFT          11
+#define QFQ_MTU_SHIFT          16      /* to support TSO/GSO */
 #define QFQ_MIN_SLOT_SHIFT     (FRAC_BITS + QFQ_MTU_SHIFT - QFQ_MAX_INDEX)
+#define QFQ_MIN_LMAX           256     /* min possible lmax for a class */
 
 /*
  * Possible group states.  These values are used as indexes for the bitmaps
@@ -231,6 +232,32 @@ static void qfq_update_class_params(struct qfq_sched *q, struct qfq_class *cl,
        q->wsum += delta_w;
 }
 
+static void qfq_update_reactivate_class(struct qfq_sched *q,
+                                       struct qfq_class *cl,
+                                       u32 inv_w, u32 lmax, int delta_w)
+{
+       bool need_reactivation = false;
+       int i = qfq_calc_index(inv_w, lmax);
+
+       if (&q->groups[i] != cl->grp && cl->qdisc->q.qlen > 0) {
+               /*
+                * shift cl->F back, to not charge the
+                * class for the not-yet-served head
+                * packet
+                */
+               cl->F = cl->S;
+               /* remove class from its slot in the old group */
+               qfq_deactivate_class(q, cl);
+               need_reactivation = true;
+       }
+
+       qfq_update_class_params(q, cl, lmax, inv_w, delta_w);
+
+       if (need_reactivation) /* activate in new group */
+               qfq_activate_class(q, cl, qdisc_peek_len(cl->qdisc));
+}
+
+
 static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                            struct nlattr **tca, unsigned long *arg)
 {
@@ -238,7 +265,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
        struct qfq_class *cl = (struct qfq_class *)*arg;
        struct nlattr *tb[TCA_QFQ_MAX + 1];
        u32 weight, lmax, inv_w;
-       int i, err;
+       int err;
        int delta_w;
 
        if (tca[TCA_OPTIONS] == NULL) {
@@ -270,16 +297,14 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
 
        if (tb[TCA_QFQ_LMAX]) {
                lmax = nla_get_u32(tb[TCA_QFQ_LMAX]);
-               if (!lmax || lmax > (1UL << QFQ_MTU_SHIFT)) {
+               if (lmax < QFQ_MIN_LMAX || lmax > (1UL << QFQ_MTU_SHIFT)) {
                        pr_notice("qfq: invalid max length %u\n", lmax);
                        return -EINVAL;
                }
        } else
-               lmax = 1UL << QFQ_MTU_SHIFT;
+               lmax = psched_mtu(qdisc_dev(sch));
 
        if (cl != NULL) {
-               bool need_reactivation = false;
-
                if (tca[TCA_RATE]) {
                        err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
                                                    qdisc_root_sleeping_lock(sch),
@@ -291,24 +316,8 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                if (lmax == cl->lmax && inv_w == cl->inv_w)
                        return 0; /* nothing to update */
 
-               i = qfq_calc_index(inv_w, lmax);
                sch_tree_lock(sch);
-               if (&q->groups[i] != cl->grp && cl->qdisc->q.qlen > 0) {
-                       /*
-                        * shift cl->F back, to not charge the
-                        * class for the not-yet-served head
-                        * packet
-                        */
-                       cl->F = cl->S;
-                       /* remove class from its slot in the old group */
-                       qfq_deactivate_class(q, cl);
-                       need_reactivation = true;
-               }
-
-               qfq_update_class_params(q, cl, lmax, inv_w, delta_w);
-
-               if (need_reactivation) /* activate in new group */
-                       qfq_activate_class(q, cl, qdisc_peek_len(cl->qdisc));
+               qfq_update_reactivate_class(q, cl, inv_w, lmax, delta_w);
                sch_tree_unlock(sch);
 
                return 0;
@@ -663,15 +672,48 @@ static void qfq_make_eligible(struct qfq_sched *q, u64 old_V)
 
 
 /*
- * XXX we should make sure that slot becomes less than 32.
- * This is guaranteed by the input values.
- * roundedS is always cl->S rounded on grp->slot_shift bits.
+ * If the weight and lmax (max_pkt_size) of the classes do not change,
+ * then QFQ guarantees that the slot index is never higher than
+ * 2 + ((1<<QFQ_MTU_SHIFT)/QFQ_MIN_LMAX) * (QFQ_MAX_WEIGHT/QFQ_MAX_WSUM).
+ *
+ * With the current values of the above constants, the index is
+ * then guaranteed to never be higher than 2 + 256 * (1 / 16) = 18.
+ *
+ * When the weight of a class is increased or the lmax of the class is
+ * decreased, a new class with smaller slot size may happen to be
+ * activated. The activation of this class should be properly delayed
+ * to when the service of the class has finished in the ideal system
+ * tracked by QFQ. If the activation of the class is not delayed to
+ * this reference time instant, then this class may be unjustly served
+ * before other classes waiting for service. This may cause
+ * (unfrequently) the above bound to the slot index to be violated for
+ * some of these unlucky classes.
+ *
+ * Instead of delaying the activation of the new class, which is quite
+ * complex, the following inaccurate but simple solution is used: if
+ * the slot index is higher than QFQ_MAX_SLOTS-2, then the timestamps
+ * of the class are shifted backward so as to let the slot index
+ * become equal to QFQ_MAX_SLOTS-2. This threshold is used because, if
+ * the slot index is above it, then the data structure implementing
+ * the bucket list either gets immediately corrupted or may get
+ * corrupted on a possible next packet arrival that causes the start
+ * time of the group to be shifted backward.
  */
 static void qfq_slot_insert(struct qfq_group *grp, struct qfq_class *cl,
                            u64 roundedS)
 {
        u64 slot = (roundedS - grp->S) >> grp->slot_shift;
-       unsigned int i = (grp->front + slot) % QFQ_MAX_SLOTS;
+       unsigned int i; /* slot index in the bucket list */
+
+       if (unlikely(slot > QFQ_MAX_SLOTS - 2)) {
+               u64 deltaS = roundedS - grp->S -
+                       ((u64)(QFQ_MAX_SLOTS - 2)<<grp->slot_shift);
+               cl->S -= deltaS;
+               cl->F -= deltaS;
+               slot = QFQ_MAX_SLOTS - 2;
+       }
+
+       i = (grp->front + slot) % QFQ_MAX_SLOTS;
 
        hlist_add_head(&cl->next, &grp->slots[i]);
        __set_bit(slot, &grp->full_slots);
@@ -892,6 +934,13 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        }
        pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid);
 
+       if (unlikely(cl->lmax < qdisc_pkt_len(skb))) {
+               pr_debug("qfq: increasing maxpkt from %u to %u for class %u",
+                         cl->lmax, qdisc_pkt_len(skb), cl->common.classid);
+               qfq_update_reactivate_class(q, cl, cl->inv_w,
+                                           qdisc_pkt_len(skb), 0);
+       }
+
        err = qdisc_enqueue(skb, cl->qdisc);
        if (unlikely(err != NET_XMIT_SUCCESS)) {
                pr_debug("qfq_enqueue: enqueue failed %d\n", err);
index 59d16ea..a60d1f8 100644 (file)
@@ -974,7 +974,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk,
        void *addr_buf;
        struct sctp_af *af;
 
-       SCTP_DEBUG_PRINTK("sctp_setsocktopt_bindx: sk %p addrs %p"
+       SCTP_DEBUG_PRINTK("sctp_setsockopt_bindx: sk %p addrs %p"
                          " addrs_size %d opt %d\n", sk, addrs, addrs_size, op);
 
        if (unlikely(addrs_size <= 0))
index 5a3d675..a9c0bbc 100644 (file)
@@ -172,7 +172,7 @@ out_free:
                xprt_free_allocation(req);
 
        dprintk("RPC:       setup backchannel transport failed\n");
-       return -1;
+       return -ENOMEM;
 }
 EXPORT_SYMBOL_GPL(xprt_setup_backchannel);
 
index 111ff83..b36f0fc 100644 (file)
@@ -116,7 +116,6 @@ void tipc_handler_stop(void)
                return;
 
        handler_enabled = 0;
-       tasklet_disable(&tipc_tasklet);
        tasklet_kill(&tipc_tasklet);
 
        spin_lock_bh(&qitem_lock);
index 443d4d7..3f72530 100644 (file)
@@ -526,8 +526,7 @@ int wiphy_register(struct wiphy *wiphy)
                for (i = 0; i < sband->n_channels; i++) {
                        sband->channels[i].orig_flags =
                                sband->channels[i].flags;
-                       sband->channels[i].orig_mag =
-                               sband->channels[i].max_antenna_gain;
+                       sband->channels[i].orig_mag = INT_MAX;
                        sband->channels[i].orig_mpwr =
                                sband->channels[i].max_power;
                        sband->channels[i].band = band;
index 3b8cbbc..bcc7d7e 100644 (file)
@@ -908,7 +908,7 @@ static void handle_channel(struct wiphy *wiphy,
                        map_regdom_flags(reg_rule->flags) | bw_flags;
                chan->max_antenna_gain = chan->orig_mag =
                        (int) MBI_TO_DBI(power_rule->max_antenna_gain);
-               chan->max_power = chan->orig_mpwr =
+               chan->max_reg_power = chan->max_power = chan->orig_mpwr =
                        (int) MBM_TO_DBM(power_rule->max_eirp);
                return;
        }
@@ -1331,7 +1331,8 @@ static void handle_channel_custom(struct wiphy *wiphy,
 
        chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
        chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain);
-       chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
+       chan->max_reg_power = chan->max_power =
+               (int) MBM_TO_DBM(power_rule->max_eirp);
 }
 
 static void handle_band_custom(struct wiphy *wiphy, enum ieee80211_band band,
index ef35f4e..2762e83 100644 (file)
@@ -309,23 +309,21 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
 }
 EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
 
-static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
+unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
 {
        int ae = meshhdr->flags & MESH_FLAGS_AE;
-       /* 7.1.3.5a.2 */
+       /* 802.11-2012, 8.2.4.7.3 */
        switch (ae) {
+       default:
        case 0:
                return 6;
        case MESH_FLAGS_AE_A4:
                return 12;
        case MESH_FLAGS_AE_A5_A6:
                return 18;
-       case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6):
-               return 24;
-       default:
-               return 6;
        }
 }
+EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
 
 int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                           enum nl80211_iftype iftype)
@@ -373,6 +371,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                        /* make sure meshdr->flags is on the linear part */
                        if (!pskb_may_pull(skb, hdrlen + 1))
                                return -1;
+                       if (meshdr->flags & MESH_FLAGS_AE_A4)
+                               return -1;
                        if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
                                skb_copy_bits(skb, hdrlen +
                                        offsetof(struct ieee80211s_hdr, eaddr1),
@@ -397,6 +397,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                        /* make sure meshdr->flags is on the linear part */
                        if (!pskb_may_pull(skb, hdrlen + 1))
                                return -1;
+                       if (meshdr->flags & MESH_FLAGS_AE_A5_A6)
+                               return -1;
                        if (meshdr->flags & MESH_FLAGS_AE_A4)
                                skb_copy_bits(skb, hdrlen +
                                        offsetof(struct ieee80211s_hdr, eaddr1),
index dda4b2b..ecbb447 100644 (file)
@@ -16,8 +16,9 @@ PHONY += $(modules)
 __modinst: $(modules)
        @:
 
+# Don't stop modules_install if we can't sign external modules.
 quiet_cmd_modules_install = INSTALL $@
-      cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@) ; $(mod_sign_cmd) $(2)/$(notdir $@)
+      cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@) ; $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD))
 
 # Modules built outside the kernel source tree go into extra by default
 INSTALL_MOD_DIR ?= extra
index 21a9f5d..f18750e 100755 (executable)
@@ -1890,8 +1890,10 @@ sub process {
                }
 
                if ($realfile =~ m@^(drivers/net/|net/)@ &&
-                   $rawline !~ m@^\+[ \t]*(\/\*|\*\/)@ &&
-                   $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) {
+                   $rawline !~ m@^\+[ \t]*\*/[ \t]*$@ &&       #trailing */
+                   $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ &&      #inline /*...*/
+                   $rawline !~ m@^\+.*\*{2,}/[ \t]*$@ &&       #trailing **/
+                   $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) {    #non blank */
                        WARN("NETWORKING_BLOCK_COMMENT_STYLE",
                             "networking block comments put the trailing */ on a separate line\n" . $herecurr);
                }
index c40ae57..ad11dc9 100644 (file)
@@ -100,12 +100,15 @@ static int snd_compr_open(struct inode *inode, struct file *f)
 
        if (dirn != compr->direction) {
                pr_err("this device doesn't support this direction\n");
+               snd_card_unref(compr->card);
                return -EINVAL;
        }
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
+       if (!data) {
+               snd_card_unref(compr->card);
                return -ENOMEM;
+       }
        data->stream.ops = compr->ops;
        data->stream.direction = dirn;
        data->stream.private_data = compr->private_data;
@@ -113,6 +116,7 @@ static int snd_compr_open(struct inode *inode, struct file *f)
        runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
        if (!runtime) {
                kfree(data);
+               snd_card_unref(compr->card);
                return -ENOMEM;
        }
        runtime->state = SNDRV_PCM_STATE_OPEN;
@@ -126,7 +130,8 @@ static int snd_compr_open(struct inode *inode, struct file *f)
                kfree(runtime);
                kfree(data);
        }
-       return ret;
+       snd_card_unref(compr->card);
+       return 0;
 }
 
 static int snd_compr_free(struct inode *inode, struct file *f)
index 7e86a5b..8c7c2c9 100644 (file)
@@ -86,6 +86,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
        write_lock_irqsave(&card->ctl_files_rwlock, flags);
        list_add_tail(&ctl->list, &card->ctl_files);
        write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
+       snd_card_unref(card);
        return 0;
 
       __error:
@@ -93,6 +94,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
       __error2:
        snd_card_file_remove(card, file);
       __error1:
+       if (card)
+               snd_card_unref(card);
        return err;
 }
 
@@ -1434,6 +1437,8 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer,
                        spin_unlock_irq(&ctl->read_lock);
                        schedule();
                        remove_wait_queue(&ctl->change_sleep, &wait);
+                       if (ctl->card->shutdown)
+                               return -ENODEV;
                        if (signal_pending(current))
                                return -ERESTARTSYS;
                        spin_lock_irq(&ctl->read_lock);
index 75ea16f..3f7f662 100644 (file)
@@ -100,8 +100,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
        if (hw == NULL)
                return -ENODEV;
 
-       if (!try_module_get(hw->card->module))
+       if (!try_module_get(hw->card->module)) {
+               snd_card_unref(hw->card);
                return -EFAULT;
+       }
 
        init_waitqueue_entry(&wait, current);
        add_wait_queue(&hw->open_wait, &wait);
@@ -129,6 +131,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
                mutex_unlock(&hw->open_mutex);
                schedule();
                mutex_lock(&hw->open_mutex);
+               if (hw->card->shutdown) {
+                       err = -ENODEV;
+                       break;
+               }
                if (signal_pending(current)) {
                        err = -ERESTARTSYS;
                        break;
@@ -148,6 +154,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
        mutex_unlock(&hw->open_mutex);
        if (err < 0)
                module_put(hw->card->module);
+       snd_card_unref(hw->card);
        return err;
 }
 
@@ -459,12 +466,15 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
                mutex_unlock(&register_mutex);
                return -EINVAL;
        }
+       mutex_lock(&hwdep->open_mutex);
+       wake_up(&hwdep->open_wait);
 #ifdef CONFIG_SND_OSSEMUL
        if (hwdep->ossreg)
                snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
 #endif
        snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
        list_del_init(&hwdep->list);
+       mutex_unlock(&hwdep->open_mutex);
        mutex_unlock(&register_mutex);
        return 0;
 }
index d8ec849..7b012d1 100644 (file)
@@ -213,6 +213,7 @@ int snd_card_create(int idx, const char *xid,
        spin_lock_init(&card->files_lock);
        INIT_LIST_HEAD(&card->files_list);
        init_waitqueue_head(&card->shutdown_sleep);
+       atomic_set(&card->refcount, 0);
 #ifdef CONFIG_PM
        mutex_init(&card->power_lock);
        init_waitqueue_head(&card->power_sleep);
@@ -446,21 +447,36 @@ static int snd_card_do_free(struct snd_card *card)
        return 0;
 }
 
+/**
+ * snd_card_unref - release the reference counter
+ * @card: the card instance
+ *
+ * Decrements the reference counter.  When it reaches to zero, wake up
+ * the sleeper and call the destructor if needed.
+ */
+void snd_card_unref(struct snd_card *card)
+{
+       if (atomic_dec_and_test(&card->refcount)) {
+               wake_up(&card->shutdown_sleep);
+               if (card->free_on_last_close)
+                       snd_card_do_free(card);
+       }
+}
+EXPORT_SYMBOL(snd_card_unref);
+
 int snd_card_free_when_closed(struct snd_card *card)
 {
-       int free_now = 0;
-       int ret = snd_card_disconnect(card);
-       if (ret)
-               return ret;
+       int ret;
 
-       spin_lock(&card->files_lock);
-       if (list_empty(&card->files_list))
-               free_now = 1;
-       else
-               card->free_on_last_close = 1;
-       spin_unlock(&card->files_lock);
+       atomic_inc(&card->refcount);
+       ret = snd_card_disconnect(card);
+       if (ret) {
+               atomic_dec(&card->refcount);
+               return ret;
+       }
 
-       if (free_now)
+       card->free_on_last_close = 1;
+       if (atomic_dec_and_test(&card->refcount))
                snd_card_do_free(card);
        return 0;
 }
@@ -474,7 +490,7 @@ int snd_card_free(struct snd_card *card)
                return ret;
 
        /* wait, until all devices are ready for the free operation */
-       wait_event(card->shutdown_sleep, list_empty(&card->files_list));
+       wait_event(card->shutdown_sleep, !atomic_read(&card->refcount));
        snd_card_do_free(card);
        return 0;
 }
@@ -886,6 +902,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
                return -ENODEV;
        }
        list_add(&mfile->list, &card->files_list);
+       atomic_inc(&card->refcount);
        spin_unlock(&card->files_lock);
        return 0;
 }
@@ -908,7 +925,6 @@ EXPORT_SYMBOL(snd_card_file_add);
 int snd_card_file_remove(struct snd_card *card, struct file *file)
 {
        struct snd_monitor_file *mfile, *found = NULL;
-       int last_close = 0;
 
        spin_lock(&card->files_lock);
        list_for_each_entry(mfile, &card->files_list, list) {
@@ -923,19 +939,13 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
                        break;
                }
        }
-       if (list_empty(&card->files_list))
-               last_close = 1;
        spin_unlock(&card->files_lock);
-       if (last_close) {
-               wake_up(&card->shutdown_sleep);
-               if (card->free_on_last_close)
-                       snd_card_do_free(card);
-       }
        if (!found) {
                snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
                return -ENOENT;
        }
        kfree(found);
+       snd_card_unref(card);
        return 0;
 }
 
index 29f6ded..e8a1d18 100644 (file)
@@ -52,14 +52,19 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
                                         SNDRV_OSS_DEVICE_TYPE_MIXER);
        if (card == NULL)
                return -ENODEV;
-       if (card->mixer_oss == NULL)
+       if (card->mixer_oss == NULL) {
+               snd_card_unref(card);
                return -ENODEV;
+       }
        err = snd_card_file_add(card, file);
-       if (err < 0)
+       if (err < 0) {
+               snd_card_unref(card);
                return err;
+       }
        fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL);
        if (fmixer == NULL) {
                snd_card_file_remove(card, file);
+               snd_card_unref(card);
                return -ENOMEM;
        }
        fmixer->card = card;
@@ -68,8 +73,10 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
        if (!try_module_get(card->module)) {
                kfree(fmixer);
                snd_card_file_remove(card, file);
+               snd_card_unref(card);
                return -EFAULT;
        }
+       snd_card_unref(card);
        return 0;
 }
 
index 08fde00..4c1cc51 100644 (file)
@@ -2441,6 +2441,10 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
                mutex_unlock(&pcm->open_mutex);
                schedule();
                mutex_lock(&pcm->open_mutex);
+               if (pcm->card->shutdown) {
+                       err = -ENODEV;
+                       break;
+               }
                if (signal_pending(current)) {
                        err = -ERESTARTSYS;
                        break;
@@ -2450,6 +2454,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
        mutex_unlock(&pcm->open_mutex);
        if (err < 0)
                goto __error;
+       snd_card_unref(pcm->card);
        return err;
 
       __error:
@@ -2457,6 +2462,8 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
       __error2:
        snd_card_file_remove(pcm->card, file);
       __error1:
+       if (pcm)
+               snd_card_unref(pcm->card);
        return err;
 }
 
index f299194..030102c 100644 (file)
@@ -1086,11 +1086,19 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
        if (list_empty(&pcm->list))
                goto unlock;
 
+       mutex_lock(&pcm->open_mutex);
+       wake_up(&pcm->open_wait);
        list_del_init(&pcm->list);
        for (cidx = 0; cidx < 2; cidx++)
-               for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
-                       if (substream->runtime)
+               for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) {
+                       snd_pcm_stream_lock_irq(substream);
+                       if (substream->runtime) {
                                substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
+                               wake_up(&substream->runtime->sleep);
+                               wake_up(&substream->runtime->tsleep);
+                       }
+                       snd_pcm_stream_unlock_irq(substream);
+               }
        list_for_each_entry(notify, &snd_pcm_notify_list, list) {
                notify->n_disconnect(pcm);
        }
@@ -1110,6 +1118,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
                        pcm->streams[cidx].chmap_kctl = NULL;
                }
        }
+       mutex_unlock(&pcm->open_mutex);
  unlock:
        mutex_unlock(&register_mutex);
        return 0;
index 5e12e5b..f9ddecf 100644 (file)
@@ -369,6 +369,14 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
        return usecs;
 }
 
+static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
+{
+       snd_pcm_stream_lock_irq(substream);
+       if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED)
+               substream->runtime->status->state = state;
+       snd_pcm_stream_unlock_irq(substream);
+}
+
 static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
 {
@@ -452,7 +460,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
                runtime->boundary *= 2;
 
        snd_pcm_timer_resolution_change(substream);
-       runtime->status->state = SNDRV_PCM_STATE_SETUP;
+       snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
 
        if (pm_qos_request_active(&substream->latency_pm_qos_req))
                pm_qos_remove_request(&substream->latency_pm_qos_req);
@@ -464,7 +472,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        /* hardware might be unusable from this time,
           so we force application to retry to set
           the correct hardware parameter settings */
-       runtime->status->state = SNDRV_PCM_STATE_OPEN;
+       snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
        if (substream->ops->hw_free != NULL)
                substream->ops->hw_free(substream);
        return err;
@@ -512,7 +520,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
                return -EBADFD;
        if (substream->ops->hw_free)
                result = substream->ops->hw_free(substream);
-       runtime->status->state = SNDRV_PCM_STATE_OPEN;
+       snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
        pm_qos_remove_request(&substream->latency_pm_qos_req);
        return result;
 }
@@ -1320,7 +1328,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        runtime->control->appl_ptr = runtime->status->hw_ptr;
-       runtime->status->state = SNDRV_PCM_STATE_PREPARED;
+       snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED);
 }
 
 static struct action_ops snd_pcm_action_prepare = {
@@ -1510,6 +1518,10 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
                down_read(&snd_pcm_link_rwsem);
                snd_pcm_stream_lock_irq(substream);
                remove_wait_queue(&to_check->sleep, &wait);
+               if (card->shutdown) {
+                       result = -ENODEV;
+                       break;
+               }
                if (tout == 0) {
                        if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
                                result = -ESTRPIPE;
@@ -1634,6 +1646,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
        write_unlock_irq(&snd_pcm_link_rwlock);
        up_write(&snd_pcm_link_rwsem);
  _nolock:
+       snd_card_unref(substream1->pcm->card);
        fput_light(file, fput_needed);
        if (res < 0)
                kfree(group);
@@ -2108,7 +2121,10 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file)
                return err;
        pcm = snd_lookup_minor_data(iminor(inode),
                                    SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
-       return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
+       err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
+       if (pcm)
+               snd_card_unref(pcm->card);
+       return err;
 }
 
 static int snd_pcm_capture_open(struct inode *inode, struct file *file)
@@ -2119,7 +2135,10 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file)
                return err;
        pcm = snd_lookup_minor_data(iminor(inode),
                                    SNDRV_DEVICE_TYPE_PCM_CAPTURE);
-       return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
+       err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
+       if (pcm)
+               snd_card_unref(pcm->card);
+       return err;
 }
 
 static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
@@ -2156,6 +2175,10 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
                mutex_unlock(&pcm->open_mutex);
                schedule();
                mutex_lock(&pcm->open_mutex);
+               if (pcm->card->shutdown) {
+                       err = -ENODEV;
+                       break;
+               }
                if (signal_pending(current)) {
                        err = -ERESTARTSYS;
                        break;
index ebf6e49..1bb95ae 100644 (file)
@@ -379,8 +379,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
        if (rmidi == NULL)
                return -ENODEV;
 
-       if (!try_module_get(rmidi->card->module))
+       if (!try_module_get(rmidi->card->module)) {
+               snd_card_unref(rmidi->card);
                return -ENXIO;
+       }
 
        mutex_lock(&rmidi->open_mutex);
        card = rmidi->card;
@@ -422,6 +424,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
                mutex_unlock(&rmidi->open_mutex);
                schedule();
                mutex_lock(&rmidi->open_mutex);
+               if (rmidi->card->shutdown) {
+                       err = -ENODEV;
+                       break;
+               }
                if (signal_pending(current)) {
                        err = -ERESTARTSYS;
                        break;
@@ -440,6 +446,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
 #endif
        file->private_data = rawmidi_file;
        mutex_unlock(&rmidi->open_mutex);
+       snd_card_unref(rmidi->card);
        return 0;
 
  __error:
@@ -447,6 +454,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
  __error_card:
        mutex_unlock(&rmidi->open_mutex);
        module_put(rmidi->card->module);
+       snd_card_unref(rmidi->card);
        return err;
 }
 
@@ -991,6 +999,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
                        spin_unlock_irq(&runtime->lock);
                        schedule();
                        remove_wait_queue(&runtime->sleep, &wait);
+                       if (rfile->rmidi->card->shutdown)
+                               return -ENODEV;
                        if (signal_pending(current))
                                return result > 0 ? result : -ERESTARTSYS;
                        if (!runtime->avail)
@@ -1234,6 +1244,8 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
                        spin_unlock_irq(&runtime->lock);
                        timeout = schedule_timeout(30 * HZ);
                        remove_wait_queue(&runtime->sleep, &wait);
+                       if (rfile->rmidi->card->shutdown)
+                               return -ENODEV;
                        if (signal_pending(current))
                                return result > 0 ? result : -ERESTARTSYS;
                        if (!runtime->avail && !timeout)
@@ -1609,9 +1621,20 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
 static int snd_rawmidi_dev_disconnect(struct snd_device *device)
 {
        struct snd_rawmidi *rmidi = device->device_data;
+       int dir;
 
        mutex_lock(&register_mutex);
+       mutex_lock(&rmidi->open_mutex);
+       wake_up(&rmidi->open_wait);
        list_del_init(&rmidi->list);
+       for (dir = 0; dir < 2; dir++) {
+               struct snd_rawmidi_substream *s;
+               list_for_each_entry(s, &rmidi->streams[dir].substreams, list) {
+                       if (s->runtime)
+                               wake_up(&s->runtime->sleep);
+               }
+       }
+
 #ifdef CONFIG_SND_OSSEMUL
        if (rmidi->ossreg) {
                if ((int)rmidi->device == midi_map[rmidi->card->number]) {
@@ -1626,6 +1649,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
        }
 #endif /* CONFIG_SND_OSSEMUL */
        snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
+       mutex_unlock(&rmidi->open_mutex);
        mutex_unlock(&register_mutex);
        return 0;
 }
index 6439760..70ccdab 100644 (file)
@@ -98,6 +98,10 @@ static void snd_request_other(int minor)
  *
  * Checks that a minor device with the specified type is registered, and returns
  * its user data pointer.
+ *
+ * This function increments the reference counter of the card instance
+ * if an associated instance with the given minor number and type is found.
+ * The caller must call snd_card_unref() appropriately later.
  */
 void *snd_lookup_minor_data(unsigned int minor, int type)
 {
@@ -108,9 +112,11 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
                return NULL;
        mutex_lock(&sound_mutex);
        mreg = snd_minors[minor];
-       if (mreg && mreg->type == type)
+       if (mreg && mreg->type == type) {
                private_data = mreg->private_data;
-       else
+               if (private_data && mreg->card_ptr)
+                       atomic_inc(&mreg->card_ptr->refcount);
+       } else
                private_data = NULL;
        mutex_unlock(&sound_mutex);
        return private_data;
@@ -275,6 +281,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
        preg->device = dev;
        preg->f_ops = f_ops;
        preg->private_data = private_data;
+       preg->card_ptr = card;
        mutex_lock(&sound_mutex);
 #ifdef CONFIG_SND_DYNAMIC_MINORS
        minor = snd_find_free_minor(type);
index e952833..726a49a 100644 (file)
@@ -40,6 +40,9 @@
 static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS];
 static DEFINE_MUTEX(sound_oss_mutex);
 
+/* NOTE: This function increments the refcount of the associated card like
+ * snd_lookup_minor_data(); the caller must call snd_card_unref() appropriately
+ */
 void *snd_lookup_oss_minor_data(unsigned int minor, int type)
 {
        struct snd_minor *mreg;
@@ -49,9 +52,11 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
                return NULL;
        mutex_lock(&sound_oss_mutex);
        mreg = snd_oss_minors[minor];
-       if (mreg && mreg->type == type)
+       if (mreg && mreg->type == type) {
                private_data = mreg->private_data;
-       else
+               if (private_data && mreg->card_ptr)
+                       atomic_inc(&mreg->card_ptr->refcount);
+       } else
                private_data = NULL;
        mutex_unlock(&sound_oss_mutex);
        return private_data;
@@ -123,6 +128,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
        preg->device = dev;
        preg->f_ops = f_ops;
        preg->private_data = private_data;
+       preg->card_ptr = card;
        mutex_lock(&sound_oss_mutex);
        snd_oss_minors[minor] = preg;
        minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
index ef68d71..e04e750 100644 (file)
@@ -426,7 +426,7 @@ static struct snd_kcontrol_new snd_ak4113_iec958_controls[] = {
 },
 {
        .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
-       .name =         "IEC958 Preample Capture Default",
+       .name =         "IEC958 Preamble Capture Default",
        .access =       SNDRV_CTL_ELEM_ACCESS_READ |
                SNDRV_CTL_ELEM_ACCESS_VOLATILE,
        .info =         snd_ak4113_spdif_pinfo,
index 816e7d2..5bf4fca 100644 (file)
@@ -401,7 +401,7 @@ static struct snd_kcontrol_new snd_ak4114_iec958_controls[] = {
 },
 {
        .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
-       .name =         "IEC958 Preample Capture Default",
+       .name =         "IEC958 Preamble Capture Default",
        .access =       SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
        .info =         snd_ak4114_spdif_pinfo,
        .get =          snd_ak4114_spdif_pget,
index b4b2a51..40e33c9 100644 (file)
@@ -380,7 +380,7 @@ static struct snd_kcontrol_new snd_ak4117_iec958_controls[] = {
 },
 {
        .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
-       .name =         "IEC958 Preample Capture Default",
+       .name =         "IEC958 Preamble Capture Default",
        .access =       SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
        .info =         snd_ak4117_spdif_pinfo,
        .get =          snd_ak4117_spdif_pget,
index 5d0e568..50169bc 100644 (file)
@@ -2655,6 +2655,8 @@ static struct ess_device_list pm_whitelist[] __devinitdata = {
        { TYPE_MAESTRO2E, 0x1179 },
        { TYPE_MAESTRO2E, 0x14c0 },     /* HP omnibook 4150 */
        { TYPE_MAESTRO2E, 0x1558 },
+       { TYPE_MAESTRO2E, 0x125d },     /* a PCI card, e.g. Terratec DMX */
+       { TYPE_MAESTRO2, 0x125d },      /* a PCI card, e.g. SF64-PCE2 */
 };
 
 static struct ess_device_list mpu_blacklist[] __devinitdata = {
index 72b085a..cd2dbaf 100644 (file)
@@ -3563,6 +3563,8 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        /* Teradici */
        { PCI_DEVICE(0x6549, 0x1200),
          .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT },
+       { PCI_DEVICE(0x6549, 0x2200),
+         .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT },
        /* Creative X-Fi (CA0110-IBG) */
        /* CTHDA chips */
        { PCI_DEVICE(0x1102, 0x0010),
index cdd43ea..1eeba73 100644 (file)
@@ -545,6 +545,7 @@ static int ad198x_build_pcms(struct hda_codec *codec)
        if (spec->multiout.dig_out_nid) {
                info++;
                codec->num_pcms++;
+               codec->spdif_status_reset = 1;
                info->name = "AD198x Digital";
                info->pcm_type = HDA_PCM_TYPE_SPDIF;
                info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
index 61a7113..d5f3a26 100644 (file)
@@ -101,8 +101,8 @@ enum {
 #define CS420X_VENDOR_NID      0x11
 #define CS_DIG_OUT1_PIN_NID    0x10
 #define CS_DIG_OUT2_PIN_NID    0x15
-#define CS_DMIC1_PIN_NID       0x12
-#define CS_DMIC2_PIN_NID       0x0e
+#define CS_DMIC1_PIN_NID       0x0e
+#define CS_DMIC2_PIN_NID       0x12
 
 /* coef indices */
 #define IDX_SPDIF_STAT         0x0000
@@ -1079,14 +1079,18 @@ static void init_input(struct hda_codec *codec)
                        cs_automic(codec, NULL);
 
                coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */
+               cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
+
+               coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG);
                if (is_active_pin(codec, CS_DMIC2_PIN_NID))
-                       coef |= 0x0500; /* DMIC2 2 chan on, GPIO1 off */
+                       coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */
                if (is_active_pin(codec, CS_DMIC1_PIN_NID))
-                       coef |= 0x1800; /* DMIC1 2 chan on, GPIO0 off
+                       coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off
                                         * No effect if SPDIF_OUT2 is
                                         * selected in IDX_SPDIF_CTL.
                                        */
-               cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
+
+               cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef);
        } else {
                if (spec->mic_detect)
                        cs_automic(codec, NULL);
@@ -1107,7 +1111,7 @@ static const struct hda_verb cs_coef_init_verbs[] = {
          | 0x0400 /* Disable Coefficient Auto increment */
          )},
        /* Beep */
-       {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
+       {0x11, AC_VERB_SET_COEF_INDEX, IDX_BEEP_CFG},
        {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */
 
        {} /* terminator */
@@ -1728,8 +1732,7 @@ static int cs421x_mux_enum_put(struct snd_kcontrol *kcontrol,
 
 }
 
-static struct snd_kcontrol_new cs421x_capture_source = {
-
+static const struct snd_kcontrol_new cs421x_capture_source = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Capture Source",
        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
@@ -1946,7 +1949,7 @@ static int cs421x_suspend(struct hda_codec *codec)
 }
 #endif
 
-static struct hda_codec_ops cs421x_patch_ops = {
+static const struct hda_codec_ops cs421x_patch_ops = {
        .build_controls = cs421x_build_controls,
        .build_pcms = cs_build_pcms,
        .init = cs421x_init,
index f7397ad..c0ce3b1 100644 (file)
@@ -5840,7 +5840,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        return alc_parse_auto_config(codec, alc269_ignore, ssids);
 }
 
-static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
+static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up)
 {
        int val = alc_read_coef_idx(codec, 0x04);
        if (power_up)
@@ -5857,10 +5857,10 @@ static void alc269_shutup(struct hda_codec *codec)
        if (spec->codec_variant != ALC269_TYPE_ALC269VB)
                return;
 
-       if ((alc_get_coef0(codec) & 0x00ff) == 0x017)
-               alc269_toggle_power_output(codec, 0);
-       if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
-               alc269_toggle_power_output(codec, 0);
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB)
+               alc269vb_toggle_power_output(codec, 0);
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
+                       (alc_get_coef0(codec) & 0x00ff) == 0x018) {
                msleep(150);
        }
 }
@@ -5870,24 +5870,22 @@ static int alc269_resume(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
 
-       if (spec->codec_variant == ALC269_TYPE_ALC269VB ||
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB)
+               alc269vb_toggle_power_output(codec, 0);
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
                        (alc_get_coef0(codec) & 0x00ff) == 0x018) {
-               alc269_toggle_power_output(codec, 0);
                msleep(150);
        }
 
        codec->patch_ops.init(codec);
 
-       if (spec->codec_variant == ALC269_TYPE_ALC269VB ||
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB)
+               alc269vb_toggle_power_output(codec, 1);
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
                        (alc_get_coef0(codec) & 0x00ff) == 0x017) {
-               alc269_toggle_power_output(codec, 1);
                msleep(200);
        }
 
-       if (spec->codec_variant == ALC269_TYPE_ALC269VB ||
-                       (alc_get_coef0(codec) & 0x00ff) == 0x018)
-               alc269_toggle_power_output(codec, 1);
-
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
        hda_call_check_power_status(codec, 0x01);
@@ -7079,6 +7077,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
          .patch = patch_alc662 },
        { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
        { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
+       { .id = 0x10ec0668, .name = "ALC668", .patch = patch_alc662 },
        { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
        { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
        { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
@@ -7096,6 +7095,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
        { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
        { .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 },
+       { .id = 0x10ec0900, .name = "ALC1150", .patch = patch_alc882 },
        {} /* terminator */
 };
 
index 770013f..9ba8af0 100644 (file)
@@ -1763,6 +1763,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
                          "HP", STAC_HP_ZEPHYR),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3660,
                          "HP Mini", STAC_92HD83XXX_HP_LED),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x144E,
+                         "HP Pavilion dv5", STAC_92HD83XXX_HP_INV_LED),
        {} /* terminator */
 };
 
index 72a2f60..019e1a0 100644 (file)
@@ -1809,11 +1809,11 @@ static int via_auto_fill_dac_nids(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        const struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i, dac_num;
+       int i;
        hda_nid_t nid;
 
+       spec->multiout.num_dacs = 0;
        spec->multiout.dac_nids = spec->private_dac_nids;
-       dac_num = 0;
        for (i = 0; i < cfg->line_outs; i++) {
                hda_nid_t dac = 0;
                nid = cfg->line_out_pins[i];
@@ -1824,16 +1824,13 @@ static int via_auto_fill_dac_nids(struct hda_codec *codec)
                if (!i && parse_output_path(codec, nid, dac, 1,
                                            &spec->out_mix_path))
                        dac = spec->out_mix_path.path[0];
-               if (dac) {
-                       spec->private_dac_nids[i] = dac;
-                       dac_num++;
-               }
+               if (dac)
+                       spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
        }
        if (!spec->out_path[0].depth && spec->out_mix_path.depth) {
                spec->out_path[0] = spec->out_mix_path;
                spec->out_mix_path.depth = 0;
        }
-       spec->multiout.num_dacs = dac_num;
        return 0;
 }
 
@@ -3628,6 +3625,7 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
  */
 enum {
        VIA_FIXUP_INTMIC_BOOST,
+       VIA_FIXUP_ASUS_G75,
 };
 
 static void via_fixup_intmic_boost(struct hda_codec *codec,
@@ -3642,13 +3640,35 @@ static const struct hda_fixup via_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = via_fixup_intmic_boost,
        },
+       [VIA_FIXUP_ASUS_G75] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* set 0x24 and 0x33 as speakers */
+                       { 0x24, 0x991301f0 },
+                       { 0x33, 0x991301f1 }, /* subwoofer */
+                       { }
+               }
+       },
 };
 
 static const struct snd_pci_quirk vt2002p_fixups[] = {
+       SND_PCI_QUIRK(0x1043, 0x1487, "Asus G75", VIA_FIXUP_ASUS_G75),
        SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST),
        {}
 };
 
+/* NIDs 0x24 and 0x33 on VT1802 have connections to non-existing NID 0x3e
+ * Replace this with mixer NID 0x1c
+ */
+static void fix_vt1802_connections(struct hda_codec *codec)
+{
+       static hda_nid_t conn_24[] = { 0x14, 0x1c };
+       static hda_nid_t conn_33[] = { 0x1c };
+
+       snd_hda_override_conn_list(codec, 0x24, ARRAY_SIZE(conn_24), conn_24);
+       snd_hda_override_conn_list(codec, 0x33, ARRAY_SIZE(conn_33), conn_33);
+}
+
 /* patch for vt2002P */
 static int patch_vt2002P(struct hda_codec *codec)
 {
@@ -3663,6 +3683,8 @@ static int patch_vt2002P(struct hda_codec *codec)
        spec->aa_mix_nid = 0x21;
        override_mic_boost(codec, 0x2b, 0, 3, 40);
        override_mic_boost(codec, 0x29, 0, 3, 40);
+       if (spec->codec_type == VT1802)
+               fix_vt1802_connections(codec);
        add_secret_dac_path(codec);
 
        snd_hda_pick_fixup(codec, NULL, vt2002p_fixups, via_fixups);
index 3050a52..245d874 100644 (file)
@@ -2859,7 +2859,12 @@ static int snd_vt1724_resume(struct device *dev)
                ice->set_spdif_clock(ice, 0);
        } else {
                /* internal on-card clock */
-               snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
+               int rate;
+               if (ice->cur_rate)
+                       rate = ice->cur_rate;
+               else
+                       rate = ice->pro_rate_default;
+               snd_vt1724_set_pro_rate(ice, rate, 1);
        }
 
        update_spdif_bits(ice, ice->pm_saved_spdif_ctrl);
index f1cd1e3..748e36c 100644 (file)
@@ -3979,7 +3979,8 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol,
                case 8: /* SYNC IN */
                        val = hdspm_sync_in_sync_check(hdspm); break;
                default:
-                       val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1);
+                       val = hdspm_s1_sync_check(hdspm,
+                                       kcontrol->private_value-1);
                }
                break;
 
@@ -4899,7 +4900,7 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
                insel = "Coaxial";
                break;
        default:
-               insel = "Unkown";
+               insel = "Unknown";
        }
 
        snd_iprintf(buffer,
index 6159929..4d8db36 100644 (file)
@@ -763,7 +763,7 @@ static int cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
        if ((freq >= CS42L52_MIN_CLK) && (freq <= CS42L52_MAX_CLK)) {
                cs42l52->sysclk = freq;
        } else {
-               dev_err(codec->dev, "Invalid freq paramter\n");
+               dev_err(codec->dev, "Invalid freq parameter\n");
                return -EINVAL;
        }
        return 0;
index 3fddc7a..b2b2b37 100644 (file)
@@ -3722,7 +3722,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
        } while (count--);
 
        if (count == 0)
-               dev_warn(codec->dev, "No impedence range reported for jack\n");
+               dev_warn(codec->dev, "No impedance range reported for jack\n");
 
 #ifndef CONFIG_SND_SOC_WM8994_MODULE
        trace_snd_soc_jack_irq(dev_name(codec->dev));
index 68f2cd1..5a6aeaf 100644 (file)
@@ -464,9 +464,9 @@ static __devinit int asoc_dmic_probe(struct platform_device *pdev)
 
        mutex_init(&dmic->mutex);
 
-       dmic->fclk = clk_get(dmic->dev, "dmic_fck");
+       dmic->fclk = clk_get(dmic->dev, "fck");
        if (IS_ERR(dmic->fclk)) {
-               dev_err(dmic->dev, "cant get dmic_fck\n");
+               dev_err(dmic->dev, "cant get fck\n");
                return -ENODEV;
        }
 
index 677b567..1ff6bb9 100644 (file)
 
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <mach/board-zoom.h>
 #include <linux/platform_data/asoc-ti-mcbsp.h>
+#include <linux/platform_data/gpio-omap.h>
 
 /* Register descriptions for twl4030 codec part */
 #include <linux/mfd/twl4030-audio.h>
index 561bb74..282f0fc 100644 (file)
@@ -339,7 +339,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
        }
 
        mutex_init(&chip->mutex);
-       mutex_init(&chip->shutdown_mutex);
+       init_rwsem(&chip->shutdown_rwsem);
        chip->index = idx;
        chip->dev = dev;
        chip->card = card;
@@ -560,7 +560,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
 
        card = chip->card;
        mutex_lock(&register_mutex);
-       mutex_lock(&chip->shutdown_mutex);
+       down_write(&chip->shutdown_rwsem);
        chip->shutdown = 1;
        chip->num_interfaces--;
        if (chip->num_interfaces <= 0) {
@@ -582,11 +582,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
                        snd_usb_mixer_disconnect(p);
                }
                usb_chip[chip->index] = NULL;
-               mutex_unlock(&chip->shutdown_mutex);
+               up_write(&chip->shutdown_rwsem);
                mutex_unlock(&register_mutex);
                snd_card_free_when_closed(card);
        } else {
-               mutex_unlock(&chip->shutdown_mutex);
+               up_write(&chip->shutdown_rwsem);
                mutex_unlock(&register_mutex);
        }
 }
@@ -618,16 +618,20 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
 {
        int err = -ENODEV;
 
+       down_read(&chip->shutdown_rwsem);
        if (!chip->shutdown && !chip->probing)
                err = usb_autopm_get_interface(chip->pm_intf);
+       up_read(&chip->shutdown_rwsem);
 
        return err;
 }
 
 void snd_usb_autosuspend(struct snd_usb_audio *chip)
 {
+       down_read(&chip->shutdown_rwsem);
        if (!chip->shutdown && !chip->probing)
                usb_autopm_put_interface(chip->pm_intf);
+       up_read(&chip->shutdown_rwsem);
 }
 
 static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
index afa4f9e..814cb35 100644 (file)
@@ -126,6 +126,7 @@ struct snd_usb_substream {
        struct snd_usb_endpoint *sync_endpoint;
        unsigned long flags;
        bool need_setup_ep;             /* (re)configure EP at prepare? */
+       unsigned int speed;             /* USB_SPEED_XXX */
 
        u64 formats;                    /* format bitmasks (all or'ed) */
        unsigned int num_formats;               /* number of supported audio formats (list) */
index 7f78c6d..34de6f2 100644 (file)
@@ -35,6 +35,7 @@
 
 #define EP_FLAG_ACTIVATED      0
 #define EP_FLAG_RUNNING                1
+#define EP_FLAG_STOPPING       2
 
 /*
  * snd_usb_endpoint is a model that abstracts everything related to an
@@ -502,10 +503,20 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)
        if (alive)
                snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n",
                                        alive, ep->ep_num);
+       clear_bit(EP_FLAG_STOPPING, &ep->flags);
 
        return 0;
 }
 
+/* sync the pending stop operation;
+ * this function itself doesn't trigger the stop operation
+ */
+void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep)
+{
+       if (ep && test_bit(EP_FLAG_STOPPING, &ep->flags))
+               wait_clear_urbs(ep);
+}
+
 /*
  * unlink active urbs.
  */
@@ -918,6 +929,8 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
 
                if (wait)
                        wait_clear_urbs(ep);
+               else
+                       set_bit(EP_FLAG_STOPPING, &ep->flags);
        }
 }
 
index 6376ccf..3d4c970 100644 (file)
@@ -19,6 +19,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
 int  snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep);
 void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
                           int force, int can_sleep, int wait);
+void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep);
 int  snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
 int  snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
 void snd_usb_endpoint_free(struct list_head *head);
index fe56c9d..298070e 100644 (file)
@@ -287,25 +287,32 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v
        unsigned char buf[2];
        int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
        int timeout = 10;
-       int err;
+       int idx = 0, err;
 
        err = snd_usb_autoresume(cval->mixer->chip);
        if (err < 0)
                return -EIO;
+       down_read(&chip->shutdown_rwsem);
        while (timeout-- > 0) {
+               if (chip->shutdown)
+                       break;
+               idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
                if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
                                    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                   validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
-                                   buf, val_len) >= val_len) {
+                                   validx, idx, buf, val_len) >= val_len) {
                        *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
-                       snd_usb_autosuspend(cval->mixer->chip);
-                       return 0;
+                       err = 0;
+                       goto out;
                }
        }
-       snd_usb_autosuspend(cval->mixer->chip);
        snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
-                   request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
-       return -EINVAL;
+                   request, validx, idx, cval->val_type);
+       err = -EINVAL;
+
+ out:
+       up_read(&chip->shutdown_rwsem);
+       snd_usb_autosuspend(cval->mixer->chip);
+       return err;
 }
 
 static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret)
@@ -313,7 +320,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
        struct snd_usb_audio *chip = cval->mixer->chip;
        unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */
        unsigned char *val;
-       int ret, size;
+       int idx = 0, ret, size;
        __u8 bRequest;
 
        if (request == UAC_GET_CUR) {
@@ -330,16 +337,22 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
        if (ret)
                goto error;
 
-       ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
+       down_read(&chip->shutdown_rwsem);
+       if (chip->shutdown)
+               ret = -ENODEV;
+       else {
+               idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
+               ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
                              USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                             validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
-                             buf, size);
+                             validx, idx, buf, size);
+       }
+       up_read(&chip->shutdown_rwsem);
        snd_usb_autosuspend(chip);
 
        if (ret < 0) {
 error:
                snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
-                          request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
+                          request, validx, idx, cval->val_type);
                return ret;
        }
 
@@ -417,7 +430,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
 {
        struct snd_usb_audio *chip = cval->mixer->chip;
        unsigned char buf[2];
-       int val_len, err, timeout = 10;
+       int idx = 0, val_len, err, timeout = 10;
 
        if (cval->mixer->protocol == UAC_VERSION_1) {
                val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
@@ -440,19 +453,27 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
        err = snd_usb_autoresume(chip);
        if (err < 0)
                return -EIO;
-       while (timeout-- > 0)
+       down_read(&chip->shutdown_rwsem);
+       while (timeout-- > 0) {
+               if (chip->shutdown)
+                       break;
+               idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
                if (snd_usb_ctl_msg(chip->dev,
                                    usb_sndctrlpipe(chip->dev, 0), request,
                                    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                   validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
-                                   buf, val_len) >= 0) {
-                       snd_usb_autosuspend(chip);
-                       return 0;
+                                   validx, idx, buf, val_len) >= 0) {
+                       err = 0;
+                       goto out;
                }
-       snd_usb_autosuspend(chip);
+       }
        snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
-                   request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]);
-       return -EINVAL;
+                   request, validx, idx, cval->val_type, buf[0], buf[1]);
+       err = -EINVAL;
+
+ out:
+       up_read(&chip->shutdown_rwsem);
+       snd_usb_autosuspend(chip);
+       return err;
 }
 
 static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value)
index 690000d..ae2b714 100644 (file)
@@ -283,6 +283,11 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        if (value > 1)
                return -EINVAL;
        changed = value != mixer->audigy2nx_leds[index];
+       down_read(&mixer->chip->shutdown_rwsem);
+       if (mixer->chip->shutdown) {
+               err = -ENODEV;
+               goto out;
+       }
        if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042))
                err = snd_usb_ctl_msg(mixer->chip->dev,
                              usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
@@ -299,6 +304,8 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
                              usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
                              value, index + 2, NULL, 0);
+ out:
+       up_read(&mixer->chip->shutdown_rwsem);
        if (err < 0)
                return err;
        mixer->audigy2nx_leds[index] = value;
@@ -392,11 +399,16 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
 
        for (i = 0; jacks[i].name; ++i) {
                snd_iprintf(buffer, "%s: ", jacks[i].name);
-               err = snd_usb_ctl_msg(mixer->chip->dev,
+               down_read(&mixer->chip->shutdown_rwsem);
+               if (mixer->chip->shutdown)
+                       err = 0;
+               else
+                       err = snd_usb_ctl_msg(mixer->chip->dev,
                                      usb_rcvctrlpipe(mixer->chip->dev, 0),
                                      UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS |
                                      USB_RECIP_INTERFACE, 0,
                                      jacks[i].unitid << 8, buf, 3);
+               up_read(&mixer->chip->shutdown_rwsem);
                if (err == 3 && (buf[0] == 3 || buf[0] == 6))
                        snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]);
                else
@@ -426,10 +438,15 @@ static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
        else
                new_status = old_status & ~0x02;
        changed = new_status != old_status;
-       err = snd_usb_ctl_msg(mixer->chip->dev,
+       down_read(&mixer->chip->shutdown_rwsem);
+       if (mixer->chip->shutdown)
+               err = -ENODEV;
+       else
+               err = snd_usb_ctl_msg(mixer->chip->dev,
                              usb_sndctrlpipe(mixer->chip->dev, 0), 0x08,
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
                              50, 0, &new_status, 1);
+       up_read(&mixer->chip->shutdown_rwsem);
        if (err < 0)
                return err;
        mixer->xonar_u1_status = new_status;
@@ -468,11 +485,17 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
        u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
        u16 wIndex = kcontrol->private_value & 0xffff;
        u8 tmp;
+       int ret;
 
-       int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
+       down_read(&mixer->chip->shutdown_rwsem);
+       if (mixer->chip->shutdown)
+               ret = -ENODEV;
+       else
+               ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
                                  USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                                  0, cpu_to_le16(wIndex),
                                  &tmp, sizeof(tmp), 1000);
+       up_read(&mixer->chip->shutdown_rwsem);
 
        if (ret < 0) {
                snd_printk(KERN_ERR
@@ -493,11 +516,17 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
        u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
        u16 wIndex = kcontrol->private_value & 0xffff;
        u16 wValue = ucontrol->value.integer.value[0];
+       int ret;
 
-       int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
+       down_read(&mixer->chip->shutdown_rwsem);
+       if (mixer->chip->shutdown)
+               ret = -ENODEV;
+       else
+               ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
                                  USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                                  cpu_to_le16(wValue), cpu_to_le16(wIndex),
                                  NULL, 0, 1000);
+       up_read(&mixer->chip->shutdown_rwsem);
 
        if (ret < 0) {
                snd_printk(KERN_ERR
@@ -656,11 +685,16 @@ static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
                return -EINVAL;
 
 
-       err = snd_usb_ctl_msg(chip->dev,
+       down_read(&mixer->chip->shutdown_rwsem);
+       if (mixer->chip->shutdown)
+               err = -ENODEV;
+       else
+               err = snd_usb_ctl_msg(chip->dev,
                        usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
                        USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
                        validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
                        value, val_len);
+       up_read(&mixer->chip->shutdown_rwsem);
        if (err < 0)
                return err;
 
@@ -703,11 +737,16 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
 
        if (!pval->is_cached) {
                /* Read current value */
-               err = snd_usb_ctl_msg(chip->dev,
+               down_read(&mixer->chip->shutdown_rwsem);
+               if (mixer->chip->shutdown)
+                       err = -ENODEV;
+               else
+                       err = snd_usb_ctl_msg(chip->dev,
                                usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
                                USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
                                validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
                                value, val_len);
+               up_read(&mixer->chip->shutdown_rwsem);
                if (err < 0)
                        return err;
 
@@ -719,11 +758,16 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
        if (cur_val != new_val) {
                value[0] = new_val;
                value[1] = 0;
-               err = snd_usb_ctl_msg(chip->dev,
+               down_read(&mixer->chip->shutdown_rwsem);
+               if (mixer->chip->shutdown)
+                       err = -ENODEV;
+               else
+                       err = snd_usb_ctl_msg(chip->dev,
                                usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
                                USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
                                validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
                                value, val_len);
+               up_read(&mixer->chip->shutdown_rwsem);
                if (err < 0)
                        return err;
 
index 55e19e1..5c12a3f 100644 (file)
@@ -71,6 +71,8 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
        unsigned int hwptr_done;
 
        subs = (struct snd_usb_substream *)substream->runtime->private_data;
+       if (subs->stream->chip->shutdown)
+               return SNDRV_PCM_POS_XRUN;
        spin_lock(&subs->lock);
        hwptr_done = subs->hwptr_done;
        substream->runtime->delay = snd_usb_pcm_delay(subs,
@@ -444,7 +446,6 @@ static int configure_endpoint(struct snd_usb_substream *subs)
 {
        int ret;
 
-       mutex_lock(&subs->stream->chip->shutdown_mutex);
        /* format changed */
        stop_endpoints(subs, 0, 0, 0);
        ret = snd_usb_endpoint_set_params(subs->data_endpoint,
@@ -455,7 +456,7 @@ static int configure_endpoint(struct snd_usb_substream *subs)
                                          subs->cur_audiofmt,
                                          subs->sync_endpoint);
        if (ret < 0)
-               goto unlock;
+               return ret;
 
        if (subs->sync_endpoint)
                ret = snd_usb_endpoint_set_params(subs->data_endpoint,
@@ -465,9 +466,6 @@ static int configure_endpoint(struct snd_usb_substream *subs)
                                                  subs->cur_rate,
                                                  subs->cur_audiofmt,
                                                  NULL);
-
-unlock:
-       mutex_unlock(&subs->stream->chip->shutdown_mutex);
        return ret;
 }
 
@@ -505,7 +503,13 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       if ((ret = set_format(subs, fmt)) < 0)
+       down_read(&subs->stream->chip->shutdown_rwsem);
+       if (subs->stream->chip->shutdown)
+               ret = -ENODEV;
+       else
+               ret = set_format(subs, fmt);
+       up_read(&subs->stream->chip->shutdown_rwsem);
+       if (ret < 0)
                return ret;
 
        subs->interface = fmt->iface;
@@ -527,10 +531,12 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
        subs->cur_audiofmt = NULL;
        subs->cur_rate = 0;
        subs->period_bytes = 0;
-       mutex_lock(&subs->stream->chip->shutdown_mutex);
-       stop_endpoints(subs, 0, 1, 1);
-       deactivate_endpoints(subs);
-       mutex_unlock(&subs->stream->chip->shutdown_mutex);
+       down_read(&subs->stream->chip->shutdown_rwsem);
+       if (!subs->stream->chip->shutdown) {
+               stop_endpoints(subs, 0, 1, 1);
+               deactivate_endpoints(subs);
+       }
+       up_read(&subs->stream->chip->shutdown_rwsem);
        return snd_pcm_lib_free_vmalloc_buffer(substream);
 }
 
@@ -552,12 +558,22 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
                return -ENXIO;
        }
 
-       if (snd_BUG_ON(!subs->data_endpoint))
-               return -EIO;
+       down_read(&subs->stream->chip->shutdown_rwsem);
+       if (subs->stream->chip->shutdown) {
+               ret = -ENODEV;
+               goto unlock;
+       }
+       if (snd_BUG_ON(!subs->data_endpoint)) {
+               ret = -EIO;
+               goto unlock;
+       }
+
+       snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint);
+       snd_usb_endpoint_sync_pending_stop(subs->data_endpoint);
 
        ret = set_format(subs, subs->cur_audiofmt);
        if (ret < 0)
-               return ret;
+               goto unlock;
 
        iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface);
        alts = &iface->altsetting[subs->cur_audiofmt->altset_idx];
@@ -567,12 +583,12 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
                                       subs->cur_audiofmt,
                                       subs->cur_rate);
        if (ret < 0)
-               return ret;
+               goto unlock;
 
        if (subs->need_setup_ep) {
                ret = configure_endpoint(subs);
                if (ret < 0)
-                       return ret;
+                       goto unlock;
                subs->need_setup_ep = false;
        }
 
@@ -592,9 +608,11 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
        /* for playback, submit the URBs now; otherwise, the first hwptr_done
         * updates for all URBs would happen at the same time when starting */
        if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
-               return start_endpoints(subs, 1);
+               ret = start_endpoints(subs, 1);
 
-       return 0;
+ unlock:
+       up_read(&subs->stream->chip->shutdown_rwsem);
+       return ret;
 }
 
 static struct snd_pcm_hardware snd_usb_hardware =
@@ -647,7 +665,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs,
                return 0;
        }
        /* check whether the period time is >= the data packet interval */
-       if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) {
+       if (subs->speed != USB_SPEED_FULL) {
                ptime = 125 * (1 << fp->datainterval);
                if (ptime > pt->max || (ptime == pt->max && pt->openmax)) {
                        hwc_debug("   > check: ptime %u > max %u\n", ptime, pt->max);
@@ -925,7 +943,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
                return err;
 
        param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
-       if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
+       if (subs->speed == USB_SPEED_FULL)
                /* full speed devices have fixed data packet interval */
                ptmin = 1000;
        if (ptmin == 1000)
index ebc1a5b..d218f76 100644 (file)
@@ -108,7 +108,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
                        }
                        snd_iprintf(buffer, "\n");
                }
-               if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
+               if (subs->speed != USB_SPEED_FULL)
                        snd_iprintf(buffer, "    Data packet interval: %d us\n",
                                    125 * (1 << fp->datainterval));
                // snd_iprintf(buffer, "    Max Packet Size = %d\n", fp->maxpacksize);
@@ -124,7 +124,7 @@ static void proc_dump_ep_status(struct snd_usb_substream *subs,
                return;
        snd_iprintf(buffer, "    Packet Size = %d\n", ep->curpacksize);
        snd_iprintf(buffer, "    Momentary freq = %u Hz (%#x.%04x)\n",
-                   snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
+                   subs->speed == USB_SPEED_FULL
                    ? get_full_speed_hz(ep->freqm)
                    : get_high_speed_hz(ep->freqm),
                    ep->freqm >> 16, ep->freqm & 0xffff);
index 083ed81..1de0c8c 100644 (file)
@@ -90,6 +90,7 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
        subs->direction = stream;
        subs->dev = as->chip->dev;
        subs->txfr_quirk = as->chip->txfr_quirk;
+       subs->speed = snd_usb_get_speed(subs->dev);
 
        snd_usb_set_pcm_ops(as->pcm, stream);
 
index b8233eb..ef42797 100644 (file)
@@ -37,7 +37,7 @@ struct snd_usb_audio {
        struct usb_interface *pm_intf;
        u32 usb_id;
        struct mutex mutex;
-       struct mutex shutdown_mutex;
+       struct rw_semaphore shutdown_rwsem;
        unsigned int shutdown:1;
        unsigned int probing:1;
        unsigned int autosuspended:1;   
index 4348014..85baf11 100644 (file)
@@ -1,4 +1,4 @@
-TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug epoll
+TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug
 
 all:
        for TARGET in $(TARGETS); do \
diff --git a/tools/testing/selftests/epoll/Makefile b/tools/testing/selftests/epoll/Makefile
deleted file mode 100644 (file)
index 19806ed..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# Makefile for epoll selftests
-
-all: test_epoll
-%: %.c
-       gcc -pthread -g -o $@ $^
-
-run_tests: all
-       ./test_epoll
-
-clean:
-       $(RM) test_epoll
diff --git a/tools/testing/selftests/epoll/test_epoll.c b/tools/testing/selftests/epoll/test_epoll.c
deleted file mode 100644 (file)
index f752539..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- *  tools/testing/selftests/epoll/test_epoll.c
- *
- *  Copyright 2012 Adobe Systems Incorporated
- *
- *  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.
- *
- *  Paton J. Lewis <palewis@adobe.com>
- *
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/epoll.h>
-#include <sys/socket.h>
-
-/*
- * A pointer to an epoll_item_private structure will be stored in the epoll
- * item's event structure so that we can get access to the epoll_item_private
- * data after calling epoll_wait:
- */
-struct epoll_item_private {
-       int index;  /* Position of this struct within the epoll_items array. */
-       int fd;
-       uint32_t events;
-       pthread_mutex_t mutex;  /* Guards the following variables... */
-       int stop;
-       int status;  /* Stores any error encountered while handling item. */
-       /* The following variable allows us to test whether we have encountered
-          a problem while attempting to cancel and delete the associated
-          event. When the test program exits, 'deleted' should be exactly
-          one. If it is greater than one, then the failed test reflects a real
-          world situation where we would have tried to access the epoll item's
-          private data after deleting it: */
-       int deleted;
-};
-
-struct epoll_item_private *epoll_items;
-
-/*
- * Delete the specified item from the epoll set. In a real-world secneario this
- * is where we would free the associated data structure, but in this testing
- * environment we retain the structure so that we can test for double-deletion:
- */
-void delete_item(int index)
-{
-       __sync_fetch_and_add(&epoll_items[index].deleted, 1);
-}
-
-/*
- * A pointer to a read_thread_data structure will be passed as the argument to
- * each read thread:
- */
-struct read_thread_data {
-       int stop;
-       int status;  /* Indicates any error encountered by the read thread. */
-       int epoll_set;
-};
-
-/*
- * The function executed by the read threads:
- */
-void *read_thread_function(void *function_data)
-{
-       struct read_thread_data *thread_data =
-               (struct read_thread_data *)function_data;
-       struct epoll_event event_data;
-       struct epoll_item_private *item_data;
-       char socket_data;
-
-       /* Handle events until we encounter an error or this thread's 'stop'
-          condition is set: */
-       while (1) {
-               int result = epoll_wait(thread_data->epoll_set,
-                                       &event_data,
-                                       1,      /* Number of desired events */
-                                       1000);  /* Timeout in ms */
-               if (result < 0) {
-                       /* Breakpoints signal all threads. Ignore that while
-                          debugging: */
-                       if (errno == EINTR)
-                               continue;
-                       thread_data->status = errno;
-                       return 0;
-               } else if (thread_data->stop)
-                       return 0;
-               else if (result == 0)  /* Timeout */
-                       continue;
-
-               /* We need the mutex here because checking for the stop
-                  condition and re-enabling the epoll item need to be done
-                  together as one atomic operation when EPOLL_CTL_DISABLE is
-                  available: */
-               item_data = (struct epoll_item_private *)event_data.data.ptr;
-               pthread_mutex_lock(&item_data->mutex);
-
-               /* Remove the item from the epoll set if we want to stop
-                  handling that event: */
-               if (item_data->stop)
-                       delete_item(item_data->index);
-               else {
-                       /* Clear the data that was written to the other end of
-                          our non-blocking socket: */
-                       do {
-                               if (read(item_data->fd, &socket_data, 1) < 1) {
-                                       if ((errno == EAGAIN) ||
-                                           (errno == EWOULDBLOCK))
-                                               break;
-                                       else
-                                               goto error_unlock;
-                               }
-                       } while (item_data->events & EPOLLET);
-
-                       /* The item was one-shot, so re-enable it: */
-                       event_data.events = item_data->events;
-                       if (epoll_ctl(thread_data->epoll_set,
-                                                 EPOLL_CTL_MOD,
-                                                 item_data->fd,
-                                                 &event_data) < 0)
-                               goto error_unlock;
-               }
-
-               pthread_mutex_unlock(&item_data->mutex);
-       }
-
-error_unlock:
-       thread_data->status = item_data->status = errno;
-       pthread_mutex_unlock(&item_data->mutex);
-       return 0;
-}
-
-/*
- * A pointer to a write_thread_data structure will be passed as the argument to
- * the write thread:
- */
-struct write_thread_data {
-       int stop;
-       int status;  /* Indicates any error encountered by the write thread. */
-       int n_fds;
-       int *fds;
-};
-
-/*
- * The function executed by the write thread. It writes a single byte to each
- * socket in turn until the stop condition for this thread is set. If writing to
- * a socket would block (i.e. errno was EAGAIN), we leave that socket alone for
- * the moment and just move on to the next socket in the list. We don't care
- * about the order in which we deliver events to the epoll set. In fact we don't
- * care about the data we're writing to the pipes at all; we just want to
- * trigger epoll events:
- */
-void *write_thread_function(void *function_data)
-{
-       const char data = 'X';
-       int index;
-       struct write_thread_data *thread_data =
-               (struct write_thread_data *)function_data;
-       while (!thread_data->stop)
-               for (index = 0;
-                    !thread_data->stop && (index < thread_data->n_fds);
-                    ++index)
-                       if ((write(thread_data->fds[index], &data, 1) < 1) &&
-                               (errno != EAGAIN) &&
-                               (errno != EWOULDBLOCK)) {
-                               thread_data->status = errno;
-                               return;
-                       }
-}
-
-/*
- * Arguments are currently ignored:
- */
-int main(int argc, char **argv)
-{
-       const int n_read_threads = 100;
-       const int n_epoll_items = 500;
-       int index;
-       int epoll_set = epoll_create1(0);
-       struct write_thread_data write_thread_data = {
-               0, 0, n_epoll_items, malloc(n_epoll_items * sizeof(int))
-       };
-       struct read_thread_data *read_thread_data =
-               malloc(n_read_threads * sizeof(struct read_thread_data));
-       pthread_t *read_threads = malloc(n_read_threads * sizeof(pthread_t));
-       pthread_t write_thread;
-
-       printf("-----------------\n");
-       printf("Runing test_epoll\n");
-       printf("-----------------\n");
-
-       epoll_items = malloc(n_epoll_items * sizeof(struct epoll_item_private));
-
-       if (epoll_set < 0 || epoll_items == 0 || write_thread_data.fds == 0 ||
-               read_thread_data == 0 || read_threads == 0)
-               goto error;
-
-       if (sysconf(_SC_NPROCESSORS_ONLN) < 2) {
-               printf("Error: please run this test on a multi-core system.\n");
-               goto error;
-       }
-
-       /* Create the socket pairs and epoll items: */
-       for (index = 0; index < n_epoll_items; ++index) {
-               int socket_pair[2];
-               struct epoll_event event_data;
-               if (socketpair(AF_UNIX,
-                              SOCK_STREAM | SOCK_NONBLOCK,
-                              0,
-                              socket_pair) < 0)
-                       goto error;
-               write_thread_data.fds[index] = socket_pair[0];
-               epoll_items[index].index = index;
-               epoll_items[index].fd = socket_pair[1];
-               if (pthread_mutex_init(&epoll_items[index].mutex, NULL) != 0)
-                       goto error;
-               /* We always use EPOLLONESHOT because this test is currently
-                  structured to demonstrate the need for EPOLL_CTL_DISABLE,
-                  which only produces useful information in the EPOLLONESHOT
-                  case (without EPOLLONESHOT, calling epoll_ctl with
-                  EPOLL_CTL_DISABLE will never return EBUSY). If support for
-                  testing events without EPOLLONESHOT is desired, it should
-                  probably be implemented in a separate unit test. */
-               epoll_items[index].events = EPOLLIN | EPOLLONESHOT;
-               if (index < n_epoll_items / 2)
-                       epoll_items[index].events |= EPOLLET;
-               epoll_items[index].stop = 0;
-               epoll_items[index].status = 0;
-               epoll_items[index].deleted = 0;
-               event_data.events = epoll_items[index].events;
-               event_data.data.ptr = &epoll_items[index];
-               if (epoll_ctl(epoll_set,
-                             EPOLL_CTL_ADD,
-                             epoll_items[index].fd,
-                             &event_data) < 0)
-                       goto error;
-       }
-
-       /* Create and start the read threads: */
-       for (index = 0; index < n_read_threads; ++index) {
-               read_thread_data[index].stop = 0;
-               read_thread_data[index].status = 0;
-               read_thread_data[index].epoll_set = epoll_set;
-               if (pthread_create(&read_threads[index],
-                                  NULL,
-                                  read_thread_function,
-                                  &read_thread_data[index]) != 0)
-                       goto error;
-       }
-
-       if (pthread_create(&write_thread,
-                          NULL,
-                          write_thread_function,
-                          &write_thread_data) != 0)
-               goto error;
-
-       /* Cancel all event pollers: */
-#ifdef EPOLL_CTL_DISABLE
-       for (index = 0; index < n_epoll_items; ++index) {
-               pthread_mutex_lock(&epoll_items[index].mutex);
-               ++epoll_items[index].stop;
-               if (epoll_ctl(epoll_set,
-                             EPOLL_CTL_DISABLE,
-                             epoll_items[index].fd,
-                             NULL) == 0)
-                       delete_item(index);
-               else if (errno != EBUSY) {
-                       pthread_mutex_unlock(&epoll_items[index].mutex);
-                       goto error;
-               }
-               /* EBUSY means events were being handled; allow the other thread
-                  to delete the item. */
-               pthread_mutex_unlock(&epoll_items[index].mutex);
-       }
-#else
-       for (index = 0; index < n_epoll_items; ++index) {
-               pthread_mutex_lock(&epoll_items[index].mutex);
-               ++epoll_items[index].stop;
-               pthread_mutex_unlock(&epoll_items[index].mutex);
-               /* Wait in case a thread running read_thread_function is
-                  currently executing code between epoll_wait and
-                  pthread_mutex_lock with this item. Note that a longer delay
-                  would make double-deletion less likely (at the expense of
-                  performance), but there is no guarantee that any delay would
-                  ever be sufficient. Note also that we delete all event
-                  pollers at once for testing purposes, but in a real-world
-                  environment we are likely to want to be able to cancel event
-                  pollers at arbitrary times. Therefore we can't improve this
-                  situation by just splitting this loop into two loops
-                  (i.e. signal 'stop' for all items, sleep, and then delete all
-                  items). We also can't fix the problem via EPOLL_CTL_DEL
-                  because that command can't prevent the case where some other
-                  thread is executing read_thread_function within the region
-                  mentioned above: */
-               usleep(1);
-               pthread_mutex_lock(&epoll_items[index].mutex);
-               if (!epoll_items[index].deleted)
-                       delete_item(index);
-               pthread_mutex_unlock(&epoll_items[index].mutex);
-       }
-#endif
-
-       /* Shut down the read threads: */
-       for (index = 0; index < n_read_threads; ++index)
-               __sync_fetch_and_add(&read_thread_data[index].stop, 1);
-       for (index = 0; index < n_read_threads; ++index) {
-               if (pthread_join(read_threads[index], NULL) != 0)
-                       goto error;
-               if (read_thread_data[index].status)
-                       goto error;
-       }
-
-       /* Shut down the write thread: */
-       __sync_fetch_and_add(&write_thread_data.stop, 1);
-       if ((pthread_join(write_thread, NULL) != 0) || write_thread_data.status)
-               goto error;
-
-       /* Check for final error conditions: */
-       for (index = 0; index < n_epoll_items; ++index) {
-               if (epoll_items[index].status != 0)
-                       goto error;
-               if (pthread_mutex_destroy(&epoll_items[index].mutex) < 0)
-                       goto error;
-       }
-       for (index = 0; index < n_epoll_items; ++index)
-               if (epoll_items[index].deleted != 1) {
-                       printf("Error: item data deleted %1d times.\n",
-                                  epoll_items[index].deleted);
-                       goto error;
-               }
-
-       printf("[PASS]\n");
-       return 0;
-
- error:
-       printf("[FAIL]\n");
-       return errno;
-}