]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-post-merge-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 15 Jan 2011 00:29:49 +0000 (16:29 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 15 Jan 2011 00:29:49 +0000 (16:29 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-post-merge-2.6:
  [SCSI] target: Add LIO target core v4.0.0-rc6
  [SCSI] sd,sr: kill compat SDEV_MEDIA_CHANGE event
  [SCSI] sd: implement sd_check_events()

300 files changed:
Documentation/DocBook/80211.tmpl
Documentation/cgroups/memory.txt
Documentation/filesystems/Locking
MAINTAINERS
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-igep0030.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-omap2/board-zoom-peripherals.c
arch/arm/mach-omap2/clock3xxx_data.c
arch/arm/mach-omap2/clockdomain.h
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/mux34xx.c
arch/arm/mach-omap2/mux44xx.c
arch/arm/mach-omap2/omap_twl.c
arch/arm/mach-omap2/pm_bus.c
arch/arm/mach-omap2/prm2xxx_3xxx.h
arch/arm/mach-omap2/sr_device.c
arch/arm/mach-omap2/wd_timer.c
arch/arm/mm/Kconfig
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/include/plat/voltage.h
arch/ia64/include/asm/page.h
arch/s390/defconfig
arch/s390/include/asm/compat.h
arch/s390/include/asm/elf.h
arch/s390/include/asm/system.h
arch/s390/include/asm/thread_info.h
arch/s390/kernel/process.c
arch/s390/kernel/vdso.c
arch/s390/mm/mmap.c
arch/x86/Kconfig
arch/x86/pci/broadcom_bus.c
arch/x86/pci/common.c
arch/x86/pci/irq.c
arch/x86/platform/olpc/olpc-xo1.c
arch/x86/xen/mmu.c
block/cfq-iosched.c
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/evmisc.c
drivers/acpi/acpica/utmutex.c
drivers/acpi/apei/hest.c
drivers/acpi/pci_root.c
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-gtt.c
drivers/gpio/cs5535-gpio.c
drivers/gpio/timbgpio.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/i2c/busses/scx200_acb.c
drivers/i2c/i2c-core.c
drivers/md/dm-table.c
drivers/md/md.c
drivers/media/video/cafe_ccic.c
drivers/mfd/88pm860x-core.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab3550-core.c
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-debugfs.c
drivers/mfd/ab8500-spi.c [deleted file]
drivers/mfd/asic3.c
drivers/mfd/cs5535-mfd.c [new file with mode: 0644]
drivers/mfd/ezx-pcap.c
drivers/mfd/htc-egpio.c
drivers/mfd/htc-i2cpld.c
drivers/mfd/jz4740-adc.c
drivers/mfd/max8925-core.c
drivers/mfd/max8998-irq.c
drivers/mfd/max8998.c
drivers/mfd/mc13xxx-core.c
drivers/mfd/mfd-core.c
drivers/mfd/sm501.c
drivers/mfd/stmpe.c
drivers/mfd/t7l66xb.c
drivers/mfd/tc6393xb.c
drivers/mfd/tps65010.c
drivers/mfd/tps6586x.c
drivers/mfd/twl-core.c
drivers/mfd/twl4030-irq.c
drivers/mfd/twl6030-irq.c
drivers/mfd/vx855.c
drivers/mfd/wm831x-core.c
drivers/mfd/wm831x-i2c.c
drivers/mfd/wm831x-irq.c
drivers/mfd/wm831x-spi.c
drivers/mfd/wm8350-irq.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8994-irq.c
drivers/misc/Kconfig
drivers/misc/cs5535-mfgpt.c
drivers/mmc/host/sdhci-of-core.c
drivers/net/arm/ks8695net.c
drivers/net/bfin_mac.c
drivers/net/bna/bnad_ethtool.c
drivers/net/cassini.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000e/82571.c
drivers/net/e1000e/Makefile
drivers/net/e1000e/defines.h
drivers/net/e1000e/e1000.h
drivers/net/e1000e/es2lan.c
drivers/net/e1000e/ethtool.c
drivers/net/e1000e/hw.h
drivers/net/e1000e/ich8lan.c
drivers/net/e1000e/lib.c
drivers/net/e1000e/netdev.c
drivers/net/e1000e/param.c
drivers/net/e1000e/phy.c
drivers/net/gianfar.c
drivers/net/gianfar.h
drivers/net/greth.c
drivers/net/greth.h
drivers/net/ixgbe/ixgbe_main.c
drivers/net/macvtap.c
drivers/net/myri10ge/myri10ge.c
drivers/net/r8169.c
drivers/net/sfc/efx.c
drivers/net/sfc/falcon.c
drivers/net/sfc/net_driver.h
drivers/net/tile/tilepro.c
drivers/net/ucc_geth.c
drivers/net/usb/cdc_ncm.c
drivers/net/vxge/vxge-main.c
drivers/net/wireless/ath/ath9k/ar9002_calib.c
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/pci/msi.c
drivers/pci/msi.h
drivers/pci/pci-acpi.c
drivers/pci/pci-driver.c
drivers/pci/pci-stub.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer/aerdrv.c
drivers/pci/pcie/aer/aerdrv.h
drivers/pci/pcie/aspm.c
drivers/pci/pcie/pme.c
drivers/pci/pcie/portdrv.h
drivers/pci/pcie/portdrv_acpi.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/pcie/portdrv_pci.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/collie_battery.c
drivers/power/ds2760_battery.c
drivers/power/gpio-charger.c [new file with mode: 0644]
drivers/power/intel_mid_battery.c
drivers/power/isp1704_charger.c
drivers/power/jz4740-battery.c
drivers/power/max17042_battery.c [new file with mode: 0644]
drivers/power/olpc_battery.c
drivers/power/power_supply_core.c
drivers/power/s3c_adc_battery.c
drivers/power/tosa_battery.c
drivers/power/wm97xx_battery.c
drivers/power/z2_battery.c
drivers/regulator/max8998.c
drivers/rtc/rtc-max8998.c
drivers/s390/cio/device.c
drivers/scsi/ipr.c
drivers/scsi/pmcraid.c
drivers/spi/Kconfig
drivers/spi/amba-pl022.c
drivers/spi/dw_spi_mmio.c
drivers/spi/spi_imx.c
drivers/spi/spi_tegra.c
drivers/ssb/scan.c
drivers/staging/sm7xx/smtcfb.c
drivers/vhost/vhost.c
fs/afs/cmservice.c
fs/afs/internal.h
fs/afs/main.c
fs/afs/mntpt.c
fs/afs/rxrpc.c
fs/afs/server.c
fs/afs/vlocation.c
fs/block_dev.c
fs/dcache.c
fs/fscache/operation.c
fs/locks.c
fs/namei.c
fs/nfsd/acl.h [moved from include/linux/nfs4_acl.h with 98% similarity]
fs/nfsd/export.c
fs/nfsd/idmap.h [moved from include/linux/nfsd_idmap.h with 92% similarity]
fs/nfsd/nfs3proc.c
fs/nfsd/nfs4acl.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4idmap.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4recover.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsd.h
fs/nfsd/nfsproc.c
fs/nfsd/nfssvc.c
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nfsd/xdr4.h
fs/xfs/Makefile
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_buf.h
fs/xfs/linux-2.6/xfs_discard.c [new file with mode: 0644]
fs/xfs/linux-2.6/xfs_discard.h [new file with mode: 0644]
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/linux-2.6/xfs_sync.c
fs/xfs/linux-2.6/xfs_sysctl.c
fs/xfs/linux-2.6/xfs_trace.h
fs/xfs/support/debug.c
fs/xfs/support/debug.h
fs/xfs/xfs_alloc.c
fs/xfs/xfs_alloc.h
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_error.c
fs/xfs/xfs_error.h
fs/xfs/xfs_fsops.c
fs/xfs/xfs_fsops.h
fs/xfs/xfs_log.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_trans.c
include/acpi/apei.h
include/drm/drm_fb_helper.h
include/linux/etherdevice.h
include/linux/fs.h
include/linux/gpio.h
include/linux/list_bl.h
include/linux/mfd/ab8500.h
include/linux/mfd/core.h
include/linux/mfd/max8998-private.h
include/linux/mfd/max8998.h
include/linux/mfd/wm831x/core.h
include/linux/netdevice.h
include/linux/nfs4.h
include/linux/nfsd/export.h
include/linux/nl80211.h
include/linux/page_cgroup.h
include/linux/pci-acpi.h
include/linux/pci-aspm.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/pci_regs.h
include/linux/power/gpio-charger.h [new file with mode: 0644]
include/linux/power/max17042_battery.h [new file with mode: 0644]
include/linux/s3c_adc_battery.h
include/linux/skbuff.h
include/linux/sunrpc/cache.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/svc_xprt.h
include/linux/sunrpc/svcsock.h
include/linux/sunrpc/xprt.h
include/net/ah.h
include/net/cfg80211.h
include/net/mac80211.h
include/net/netfilter/ipv6/nf_conntrack_ipv6.h
include/net/netfilter/ipv6/nf_defrag_ipv6.h
include/net/red.h
kernel/cgroup.c
net/ax25/af_ax25.c
net/core/dev.c
net/core/skbuff.c
net/ethernet/eth.c
net/ipv6/ip6_output.c
net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
net/netfilter/nf_conntrack_netlink.c
net/rxrpc/af_rxrpc.c
net/sched/sch_teql.c
net/sunrpc/auth_gss/gss_krb5_crypto.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcauth.c
net/sunrpc/svcauth_unix.c
net/sunrpc/svcsock.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c
sound/pci/cs5535audio/cs5535audio_pm.c

index 03641a08e2753416fb3d32362771c9fed7ca7ed4..8906648f962b137fdd6ffb811a2c4059d034910b 100644 (file)
 !Finclude/net/mac80211.h ieee80211_ops
 !Finclude/net/mac80211.h ieee80211_alloc_hw
 !Finclude/net/mac80211.h ieee80211_register_hw
-!Finclude/net/mac80211.h ieee80211_get_tx_led_name
-!Finclude/net/mac80211.h ieee80211_get_rx_led_name
-!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
-!Finclude/net/mac80211.h ieee80211_get_radio_led_name
 !Finclude/net/mac80211.h ieee80211_unregister_hw
 !Finclude/net/mac80211.h ieee80211_free_hw
       </chapter>
         </para>
       </partintro>
 
+      <chapter id="led-support">
+        <title>LED support</title>
+        <para>
+         Mac80211 supports various ways of blinking LEDs. Wherever possible,
+         device LEDs should be exposed as LED class devices and hooked up to
+         the appropriate trigger, which will then be triggered appropriately
+         by mac80211.
+        </para>
+!Finclude/net/mac80211.h ieee80211_get_tx_led_name
+!Finclude/net/mac80211.h ieee80211_get_rx_led_name
+!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
+!Finclude/net/mac80211.h ieee80211_get_radio_led_name
+!Finclude/net/mac80211.h ieee80211_tpt_blink
+!Finclude/net/mac80211.h ieee80211_tpt_led_trigger_flags
+!Finclude/net/mac80211.h ieee80211_create_tpt_led_trigger
+      </chapter>
+
       <chapter id="hardware-crypto-offload">
         <title>Hardware crypto acceleration</title>
 !Pinclude/net/mac80211.h Hardware crypto acceleration
index bac328c232f5129183f391b7de0c2bc3bf7fe01c..7781857dc940ea01d60e7bc0b249cbd15623182d 100644 (file)
@@ -385,10 +385,6 @@ mapped_file        - # of bytes of mapped file (includes tmpfs/shmem)
 pgpgin         - # of pages paged in (equivalent to # of charging events).
 pgpgout                - # of pages paged out (equivalent to # of uncharging events).
 swap           - # of bytes of swap usage
-dirty          - # of bytes that are waiting to get written back to the disk.
-writeback      - # of bytes that are actively being written back to the disk.
-nfs_unstable   - # of bytes sent to the NFS server, but not yet committed to
-               the actual storage.
 inactive_anon  - # of bytes of anonymous memory and swap cache memory on
                LRU list.
 active_anon    - # of bytes of anonymous and swap cache memory on active
@@ -410,9 +406,6 @@ total_mapped_file   - sum of all children's "cache"
 total_pgpgin           - sum of all children's "pgpgin"
 total_pgpgout          - sum of all children's "pgpgout"
 total_swap             - sum of all children's "swap"
-total_dirty            - sum of all children's "dirty"
-total_writeback                - sum of all children's "writeback"
-total_nfs_unstable     - sum of all children's "nfs_unstable"
 total_inactive_anon    - sum of all children's "inactive_anon"
 total_active_anon      - sum of all children's "active_anon"
 total_inactive_file    - sum of all children's "inactive_file"
@@ -460,73 +453,6 @@ memory under it will be reclaimed.
 You can reset failcnt by writing 0 to failcnt file.
 # echo 0 > .../memory.failcnt
 
-5.5 dirty memory
-
-Control the maximum amount of dirty pages a cgroup can have at any given time.
-
-Limiting dirty memory is like fixing the max amount of dirty (hard to reclaim)
-page cache used by a cgroup.  So, in case of multiple cgroup writers, they will
-not be able to consume more than their designated share of dirty pages and will
-be forced to perform write-out if they cross that limit.
-
-The interface is equivalent to the procfs interface: /proc/sys/vm/dirty_*.  It
-is possible to configure a limit to trigger both a direct writeback or a
-background writeback performed by per-bdi flusher threads.  The root cgroup
-memory.dirty_* control files are read-only and match the contents of
-the /proc/sys/vm/dirty_* files.
-
-Per-cgroup dirty limits can be set using the following files in the cgroupfs:
-
-- memory.dirty_ratio: the amount of dirty memory (expressed as a percentage of
-  cgroup memory) at which a process generating dirty pages will itself start
-  writing out dirty data.
-
-- memory.dirty_limit_in_bytes: the amount of dirty memory (expressed in bytes)
-  in the cgroup at which a process generating dirty pages will start itself
-  writing out dirty data.  Suffix (k, K, m, M, g, or G) can be used to indicate
-  that value is kilo, mega or gigabytes.
-
-  Note: memory.dirty_limit_in_bytes is the counterpart of memory.dirty_ratio.
-  Only one of them may be specified at a time.  When one is written it is
-  immediately taken into account to evaluate the dirty memory limits and the
-  other appears as 0 when read.
-
-- memory.dirty_background_ratio: the amount of dirty memory of the cgroup
-  (expressed as a percentage of cgroup memory) at which background writeback
-  kernel threads will start writing out dirty data.
-
-- memory.dirty_background_limit_in_bytes: the amount of dirty memory (expressed
-  in bytes) in the cgroup at which background writeback kernel threads will
-  start writing out dirty data.  Suffix (k, K, m, M, g, or G) can be used to
-  indicate that value is kilo, mega or gigabytes.
-
-  Note: memory.dirty_background_limit_in_bytes is the counterpart of
-  memory.dirty_background_ratio.  Only one of them may be specified at a time.
-  When one is written it is immediately taken into account to evaluate the dirty
-  memory limits and the other appears as 0 when read.
-
-A cgroup may contain more dirty memory than its dirty limit.  This is possible
-because of the principle that the first cgroup to touch a page is charged for
-it.  Subsequent page counting events (dirty, writeback, nfs_unstable) are also
-counted to the originally charged cgroup.
-
-Example: If page is allocated by a cgroup A task, then the page is charged to
-cgroup A.  If the page is later dirtied by a task in cgroup B, then the cgroup A
-dirty count will be incremented.  If cgroup A is over its dirty limit but cgroup
-B is not, then dirtying a cgroup A page from a cgroup B task may push cgroup A
-over its dirty limit without throttling the dirtying cgroup B task.
-
-When use_hierarchy=0, each cgroup has dirty memory usage and limits.
-System-wide dirty limits are also consulted.  Dirty memory consumption is
-checked against both system-wide and per-cgroup dirty limits.
-
-The current implementation does not enforce per-cgroup dirty limits when
-use_hierarchy=1.  System-wide dirty limits are used for processes in such
-cgroups.  Attempts to read memory.dirty_* files return the system-wide
-values.  Writes to the memory.dirty_* files return error.  An enhanced
-implementation is needed to check the chain of parents to ensure that no
-dirty limit is exceeded.
-
 6. Hierarchy support
 
 The memory controller supports a deep hierarchy and hierarchical accounting.
index 977d8919cc69c80e9dd3f0e4a4e5327bac608376..ef9349a4b5d1ae9a4bc47eaedce49d3ed071c319 100644 (file)
@@ -343,7 +343,6 @@ prototypes:
        int (*fl_grant)(struct file_lock *, struct file_lock *, int);
        void (*fl_release_private)(struct file_lock *);
        void (*fl_break)(struct file_lock *); /* break_lease callback */
-       int (*fl_mylease)(struct file_lock *, struct file_lock *);
        int (*fl_change)(struct file_lock **, int);
 
 locking rules:
@@ -353,7 +352,6 @@ fl_notify:          yes             no
 fl_grant:              no              no
 fl_release_private:    maybe           no
 fl_break:              yes             no
-fl_mylease:            yes             no
 fl_change              yes             no
 
 --------------------------- buffer_head -----------------------------------
index af656ded404ef0ffe2502604ae44bc536ea7c7a2..89e4d4b145bb7e73b4c45671a84b401a5d8694c1 100644 (file)
@@ -5272,8 +5272,7 @@ S:        Supported
 F:     drivers/s390/net/
 
 S390 ZCRYPT DRIVER
-M:     Felix Beck <felix.beck@de.ibm.com>
-M:     Ralph Wuerthner <ralph.wuerthner@de.ibm.com>
+M:     Holger Dengler <hd@linux.vnet.ibm.com>
 M:     linux390@de.ibm.com
 L:     linux-s390@vger.kernel.org
 W:     http://www.ibm.com/developerworks/linux/linux390/
index a70bdf28e2bc2d718666f26a54338a7a147f25cc..07d1b20b11486a6c4c8629e654474e4dd7e5cb56 100644 (file)
@@ -554,6 +554,7 @@ static void __init omap_sfh7741prox_init(void)
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+       OMAP4_MUX(USBB2_ULPITLL_CLK, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
        { .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #else
@@ -576,11 +577,12 @@ static void __init omap_4430sdp_init(void)
        omap4_twl6030_hsmmc_init(mmc);
 
        /* Power on the ULPI PHY */
-       if (gpio_is_valid(OMAP4SDP_MDM_PWR_EN_GPIO)) {
-               /* FIXME: Assumes pad is already muxed for GPIO mode */
-               gpio_request(OMAP4SDP_MDM_PWR_EN_GPIO, "USBB1 PHY VMDM_3V3");
+       status = gpio_request(OMAP4SDP_MDM_PWR_EN_GPIO, "USBB1 PHY VMDM_3V3");
+       if (status)
+               pr_err("%s: Could not get USBB1 PHY GPIO\n", __func__);
+       else
                gpio_direction_output(OMAP4SDP_MDM_PWR_EN_GPIO, 1);
-       }
+
        usb_ehci_init(&ehci_pdata);
        usb_musb_init(&musb_board_data);
 
index ebaa230e67ed909658238f44483b668ad5d1358b..3be85a1f55f4d7ab5d1a9ca11f6bbc6292ef647d 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
+#include <linux/input.h>
 
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
@@ -541,6 +542,37 @@ static struct twl4030_codec_data igep2_codec_data = {
        .audio = &igep2_audio_data,
 };
 
+static int igep2_keymap[] = {
+       KEY(0, 0, KEY_LEFT),
+       KEY(0, 1, KEY_RIGHT),
+       KEY(0, 2, KEY_A),
+       KEY(0, 3, KEY_B),
+       KEY(1, 0, KEY_DOWN),
+       KEY(1, 1, KEY_UP),
+       KEY(1, 2, KEY_E),
+       KEY(1, 3, KEY_F),
+       KEY(2, 0, KEY_ENTER),
+       KEY(2, 1, KEY_I),
+       KEY(2, 2, KEY_J),
+       KEY(2, 3, KEY_K),
+       KEY(3, 0, KEY_M),
+       KEY(3, 1, KEY_N),
+       KEY(3, 2, KEY_O),
+       KEY(3, 3, KEY_P)
+};
+
+static struct matrix_keymap_data igep2_keymap_data = {
+       .keymap                 = igep2_keymap,
+       .keymap_size            = ARRAY_SIZE(igep2_keymap),
+};
+
+static struct twl4030_keypad_data igep2_keypad_pdata = {
+       .keymap_data    = &igep2_keymap_data,
+       .rows           = 4,
+       .cols           = 4,
+       .rep            = 1,
+};
+
 static struct twl4030_platform_data igep2_twldata = {
        .irq_base       = TWL4030_IRQ_BASE,
        .irq_end        = TWL4030_IRQ_END,
@@ -549,6 +581,7 @@ static struct twl4030_platform_data igep2_twldata = {
        .usb            = &igep2_usb_data,
        .codec          = &igep2_codec_data,
        .gpio           = &igep2_twl4030_gpio_pdata,
+       .keypad         = &igep2_keypad_pdata,
        .vmmc1          = &igep2_vmmc1,
        .vpll2          = &igep2_vpll2,
        .vio            = &igep2_vio,
index bcccd68f185685652a24e34718e2a8ca7b065dd1..4dc62a9b9cb24811fae3f0c1fc1149f31e7e0f34 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/interrupt.h>
 
 #include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
 #include <linux/i2c/twl.h>
 #include <linux/mmc/host.h>
 
@@ -43,7 +44,7 @@
 #define IGEP3_GPIO_WIFI_NRESET 139
 #define IGEP3_GPIO_BT_NRESET   137
 
-#define IGEP3_GPIO_USBH_NRESET  115
+#define IGEP3_GPIO_USBH_NRESET  183
 
 
 #if defined(CONFIG_MTD_ONENAND_OMAP2) || \
@@ -103,7 +104,7 @@ static struct platform_device igep3_onenand_device = {
        },
 };
 
-void __init igep3_flash_init(void)
+static void __init igep3_flash_init(void)
 {
        u8 cs = 0;
        u8 onenandcs = GPMC_CS_NUM + 1;
@@ -137,12 +138,11 @@ void __init igep3_flash_init(void)
 }
 
 #else
-void __init igep3_flash_init(void) {}
+static void __init igep3_flash_init(void) {}
 #endif
 
-static struct regulator_consumer_supply igep3_vmmc1_supply = {
-       .supply         = "vmmc",
-};
+static struct regulator_consumer_supply igep3_vmmc1_supply =
+       REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.0");
 
 /* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
 static struct regulator_init_data igep3_vmmc1 = {
@@ -159,6 +159,52 @@ static struct regulator_init_data igep3_vmmc1 = {
        .consumer_supplies      = &igep3_vmmc1_supply,
 };
 
+static struct regulator_consumer_supply igep3_vio_supply =
+       REGULATOR_SUPPLY("vmmc_aux", "mmci-omap-hs.1");
+
+static struct regulator_init_data igep3_vio = {
+       .constraints = {
+               .min_uV                 = 1800000,
+               .max_uV                 = 1800000,
+               .apply_uV               = 1,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
+                                       | REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &igep3_vio_supply,
+};
+
+static struct regulator_consumer_supply igep3_vmmc2_supply =
+       REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1");
+
+static struct regulator_init_data igep3_vmmc2 = {
+       .constraints    = {
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL,
+               .always_on              = 1,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &igep3_vmmc2_supply,
+};
+
+static struct fixed_voltage_config igep3_vwlan = {
+       .supply_name            = "vwlan",
+       .microvolts             = 3300000,
+       .gpio                   = -EINVAL,
+       .enabled_at_boot        = 1,
+       .init_data              = &igep3_vmmc2,
+};
+
+static struct platform_device igep3_vwlan_device = {
+       .name   = "reg-fixed-voltage",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &igep3_vwlan,
+       },
+};
+
 static struct omap2_hsmmc_info mmc[] = {
        [0] = {
                .mmc            = 1,
@@ -254,12 +300,6 @@ static int igep3_twl4030_gpio_setup(struct device *dev,
        mmc[0].gpio_cd = gpio + 0;
        omap2_hsmmc_init(mmc);
 
-       /*
-        * link regulators to MMC adapters ... we "know" the
-        * regulators will be set up only *after* we return.
-        */
-       igep3_vmmc1_supply.dev = mmc[0].dev;
-
        /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
 #if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
        if ((gpio_request(gpio+TWL4030_GPIO_MAX+1, "gpio-led:green:d1") == 0)
@@ -287,6 +327,10 @@ static struct twl4030_usb_data igep3_twl4030_usb_data = {
        .usb_mode       = T2_USB_MODE_ULPI,
 };
 
+static struct platform_device *igep3_devices[] __initdata = {
+       &igep3_vwlan_device,
+};
+
 static void __init igep3_init_irq(void)
 {
        omap2_init_common_infrastructure();
@@ -303,6 +347,7 @@ static struct twl4030_platform_data igep3_twl4030_pdata = {
        .usb            = &igep3_twl4030_usb_data,
        .gpio           = &igep3_twl4030_gpio_pdata,
        .vmmc1          = &igep3_vmmc1,
+       .vio            = &igep3_vio,
 };
 
 static struct i2c_board_info __initdata igep3_i2c_boardinfo[] = {
@@ -363,8 +408,20 @@ static void __init igep3_wifi_bt_init(void)
 void __init igep3_wifi_bt_init(void) {}
 #endif
 
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+       .port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+       .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+       .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+       .phy_reset = true,
+       .reset_gpio_port[0] = -EINVAL,
+       .reset_gpio_port[1] = IGEP3_GPIO_USBH_NRESET,
+       .reset_gpio_port[2] = -EINVAL,
+};
+
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+       OMAP3_MUX(I2C2_SDA, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
        { .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #endif
@@ -375,9 +432,10 @@ static void __init igep3_init(void)
 
        /* Register I2C busses and drivers */
        igep3_i2c_init();
-
+       platform_add_devices(igep3_devices, ARRAY_SIZE(igep3_devices));
        omap_serial_init();
        usb_musb_init(&musb_board_data);
+       usb_ehci_init(&ehci_pdata);
 
        igep3_flash_init();
        igep3_leds_init();
@@ -392,6 +450,7 @@ static void __init igep3_init(void)
 
 MACHINE_START(IGEP0030, "IGEP OMAP3 module")
        .boot_params    = 0x80000100,
+       .reserve        = omap_reserve,
        .map_io         = omap3_map_io,
        .init_irq       = igep3_init_irq,
        .init_machine   = igep3_init,
index a4fe8e1ee1bd6ae379c8875f48b6b71832069fa0..46d814ab5656c078e6fad0a013c2ce8c39e312e5 100644 (file)
@@ -207,7 +207,7 @@ static struct omap_dss_device beagle_dvi_device = {
        .driver_name = "generic_dpi_panel",
        .data = &dvi_panel,
        .phy.dpi.data_lines = 24,
-       .reset_gpio = 170,
+       .reset_gpio = -EINVAL,
 };
 
 static struct omap_dss_device beagle_tv_device = {
@@ -279,6 +279,8 @@ static struct gpio_led gpio_leds[];
 static int beagle_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
+       int r;
+
        if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
                mmc[0].gpio_wp = -EINVAL;
        } else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) ||
@@ -299,17 +301,63 @@ static int beagle_twl_gpio_setup(struct device *dev,
        /* REVISIT: need ehci-omap hooks for external VBUS
         * power switch and overcurrent detect
         */
+       if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM) {
+               r = gpio_request(gpio + 1, "EHCI_nOC");
+               if (!r) {
+                       r = gpio_direction_input(gpio + 1);
+                       if (r)
+                               gpio_free(gpio + 1);
+               }
+               if (r)
+                       pr_err("%s: unable to configure EHCI_nOC\n", __func__);
+       }
 
-       gpio_request(gpio + 1, "EHCI_nOC");
-       gpio_direction_input(gpio + 1);
-
-       /* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, active low) */
+       /*
+        * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
+        * high / others active low)
+        */
        gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR");
-       gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+       if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
+               gpio_direction_output(gpio + TWL4030_GPIO_MAX, 1);
+       else
+               gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+
+       /* DVI reset GPIO is different between beagle revisions */
+       if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
+               beagle_dvi_device.reset_gpio = 129;
+       else
+               beagle_dvi_device.reset_gpio = 170;
 
        /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
        gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
 
+       /*
+        * gpio + 1 on Xm controls the TFP410's enable line (active low)
+        * gpio + 2 control varies depending on the board rev as follows:
+        * P7/P8 revisions(prototype): Camera EN
+        * A2+ revisions (production): LDO (supplies DVI, serial, led blocks)
+        */
+       if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
+               r = gpio_request(gpio + 1, "nDVI_PWR_EN");
+               if (!r) {
+                       r = gpio_direction_output(gpio + 1, 0);
+                       if (r)
+                               gpio_free(gpio + 1);
+               }
+               if (r)
+                       pr_err("%s: unable to configure nDVI_PWR_EN\n",
+                               __func__);
+               r = gpio_request(gpio + 2, "DVI_LDO_EN");
+               if (!r) {
+                       r = gpio_direction_output(gpio + 2, 1);
+                       if (r)
+                               gpio_free(gpio + 2);
+               }
+               if (r)
+                       pr_err("%s: unable to configure DVI_LDO_EN\n",
+                               __func__);
+       }
+
        return 0;
 }
 
index 3094e20078448d0b010bca36cfe750c3b2216230..e001a048dc0c8a5b20bc916b675f2b6a81e8c6e9 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/leds.h>
 #include <linux/gpio.h>
@@ -95,7 +96,16 @@ static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
 static void __init omap4_ehci_init(void)
 {
        int ret;
+       struct clk *phy_ref_clk;
 
+       /* FREF_CLK3 provides the 19.2 MHz reference clock to the PHY */
+       phy_ref_clk = clk_get(NULL, "auxclk3_ck");
+       if (IS_ERR(phy_ref_clk)) {
+               pr_err("Cannot request auxclk3\n");
+               goto error1;
+       }
+       clk_set_rate(phy_ref_clk, 19200000);
+       clk_enable(phy_ref_clk);
 
        /* disable the power to the usb hub prior to init */
        ret = gpio_request(GPIO_HUB_POWER, "hub_power");
index 14d95afa3f0d8d73654b952bfde399fa79160c28..e0e040f34c68f7652e4d2c9e302fa2945f5f08e1 100644 (file)
@@ -192,7 +192,7 @@ static struct platform_device omap_vwlan_device = {
        },
 };
 
-struct wl12xx_platform_data omap_zoom_wlan_data __initdata = {
+static struct wl12xx_platform_data omap_zoom_wlan_data __initdata = {
        .irq = OMAP_GPIO_IRQ(OMAP_ZOOM_WLAN_IRQ_GPIO),
        /* ZOOM ref clock is 26 MHz */
        .board_ref_clock = 1,
@@ -286,7 +286,7 @@ static int zoom_twl_gpio_setup(struct device *dev,
 }
 
 /* EXTMUTE callback function */
-void zoom2_set_hs_extmute(int mute)
+static void zoom2_set_hs_extmute(int mute)
 {
        gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
 }
index d3ab1c9e50b0ebc86571ea62512c1d56a97b901b..403a4a1d3f9c4d0e4362cd768c2781dc32329ec1 100644 (file)
@@ -3286,7 +3286,7 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK(NULL,       "cpefuse_fck",  &cpefuse_fck,   CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
        CLK(NULL,       "ts_fck",       &ts_fck,        CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
        CLK(NULL,       "usbtll_fck",   &usbtll_fck,    CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
-       CLK("ehci-omap.0",      "usbtll_fck",   &usbtll_fck,    CK_3430ES2 | CK_AM35XX),
+       CLK("ehci-omap.0",      "usbtll_fck",   &usbtll_fck,    CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
        CLK("omap-mcbsp.1",     "prcm_fck",     &core_96m_fck,  CK_3XXX),
        CLK("omap-mcbsp.5",     "prcm_fck",     &core_96m_fck,  CK_3XXX),
        CLK(NULL,       "core_96m_fck", &core_96m_fck,  CK_3XXX),
index de3faa20b46b658eb53daa4d7af90388ad6a5d58..9b459c26fb852d14033e17a0f6b7653a7bad2ccf 100644 (file)
@@ -103,9 +103,7 @@ struct clockdomain {
                const char *name;
                struct powerdomain *ptr;
        } pwrdm;
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
        const u16 clktrctrl_mask;
-#endif
        const u8 flags;
        const u8 dep_bit;
        const u8 prcm_partition;
index 381f4eb923520f125f48bf4420139b9c13a2e502..2c9c912f2c424014d11d8fb53aa5e8eb9ef1afb8 100644 (file)
@@ -978,7 +978,7 @@ static int __init omap2_init_devices(void)
 arch_initcall(omap2_init_devices);
 
 #if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
-struct omap_device_pm_latency omap_wdt_latency[] = {
+static struct omap_device_pm_latency omap_wdt_latency[] = {
        [0] = {
                .deactivate_func = omap_device_idle_hwmods,
                .activate_func   = omap_device_enable_hwmods,
index 17bd6394d22453e1fb83a35cade10c4e1ad29ef8..df8d2f2872c6edce5e8d72a2ac668c7f10ebe336 100644 (file)
@@ -893,7 +893,7 @@ static struct omap_mux * __init omap_mux_list_add(
                return NULL;
 
        m = &entry->mux;
-       memcpy(m, src, sizeof(struct omap_mux_entry));
+       entry->mux = *src;
 
 #ifdef CONFIG_OMAP_MUX
        if (omap_mux_copy_names(src, m)) {
index 440c98e9a510950b0c43a0fc878c21950836f183..17f80e4ab162e4f2d4f15f8d99ccfa03496e225b 100644 (file)
@@ -703,7 +703,7 @@ static struct omap_mux __initdata omap3_muxmodes[] = {
  * Signals different on CBC package compared to the superset
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_OMAP_PACKAGE_CBC)
-struct omap_mux __initdata omap3_cbc_subset[] = {
+static struct omap_mux __initdata omap3_cbc_subset[] = {
        { .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #else
@@ -721,7 +721,7 @@ struct omap_mux __initdata omap3_cbc_subset[] = {
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS)       \
                && defined(CONFIG_OMAP_PACKAGE_CBC)
-struct omap_ball __initdata omap3_cbc_ball[] = {
+static struct omap_ball __initdata omap3_cbc_ball[] = {
        _OMAP3_BALLENTRY(CAM_D0, "ae16", NULL),
        _OMAP3_BALLENTRY(CAM_D1, "ae15", NULL),
        _OMAP3_BALLENTRY(CAM_D10, "d25", NULL),
index 980f11d45c79adc4fbbc4cb2d670a443dad935fb..c322e7bdaa17f39f79b3be91f9ce0a4fdbb65538 100644 (file)
@@ -544,7 +544,7 @@ static struct omap_mux __initdata omap4_core_muxmodes[] = {
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS)               \
                && defined(CONFIG_OMAP_PACKAGE_CBL)
-struct omap_ball __initdata omap4_core_cbl_ball[] = {
+static struct omap_ball __initdata omap4_core_cbl_ball[] = {
        _OMAP4_BALLENTRY(GPMC_AD0, "c12", NULL),
        _OMAP4_BALLENTRY(GPMC_AD1, "d12", NULL),
        _OMAP4_BALLENTRY(GPMC_AD2, "c13", NULL),
@@ -1262,7 +1262,7 @@ static struct omap_mux __initdata omap4_es2_core_muxmodes[] = {
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS)               \
                && defined(CONFIG_OMAP_PACKAGE_CBS)
-struct omap_ball __initdata omap4_core_cbs_ball[] = {
+static struct omap_ball __initdata omap4_core_cbs_ball[] = {
        _OMAP4_BALLENTRY(GPMC_AD0, "c12", NULL),
        _OMAP4_BALLENTRY(GPMC_AD1, "d12", NULL),
        _OMAP4_BALLENTRY(GPMC_AD2, "c13", NULL),
@@ -1546,7 +1546,7 @@ static struct omap_mux __initdata omap4_wkup_muxmodes[] = {
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS)               \
                && defined(CONFIG_OMAP_PACKAGE_CBL)
-struct omap_ball __initdata omap4_wkup_cbl_cbs_ball[] = {
+static struct omap_ball __initdata omap4_wkup_cbl_cbs_ball[] = {
        _OMAP4_BALLENTRY(SIM_IO, "h4", NULL),
        _OMAP4_BALLENTRY(SIM_CLK, "j2", NULL),
        _OMAP4_BALLENTRY(SIM_RESET, "g2", NULL),
index 15f8c6c1bb0f61cc496304a689cebb72c5a4f5ec..00e1d2b53683373928c6dd33509393ce7e0dcace 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <plat/voltage.h>
 
+#include "pm.h"
+
 #define OMAP3_SRI2C_SLAVE_ADDR         0x12
 #define OMAP3_VDD_MPU_SR_CONTROL_REG   0x00
 #define OMAP3_VDD_CORE_SR_CONTROL_REG  0x01
@@ -60,17 +62,17 @@ static u8 smps_offset;
 
 #define REG_SMPS_OFFSET         0xE0
 
-unsigned long twl4030_vsel_to_uv(const u8 vsel)
+static unsigned long twl4030_vsel_to_uv(const u8 vsel)
 {
        return (((vsel * 125) + 6000)) * 100;
 }
 
-u8 twl4030_uv_to_vsel(unsigned long uv)
+static u8 twl4030_uv_to_vsel(unsigned long uv)
 {
        return DIV_ROUND_UP(uv - 600000, 12500);
 }
 
-unsigned long twl6030_vsel_to_uv(const u8 vsel)
+static unsigned long twl6030_vsel_to_uv(const u8 vsel)
 {
        /*
         * In TWL6030 depending on the value of SMPS_OFFSET
@@ -102,7 +104,7 @@ unsigned long twl6030_vsel_to_uv(const u8 vsel)
                return ((((vsel - 1) * 125) + 6000)) * 100;
 }
 
-u8 twl6030_uv_to_vsel(unsigned long uv)
+static u8 twl6030_uv_to_vsel(unsigned long uv)
 {
        /*
         * In TWL6030 depending on the value of SMPS_OFFSET
index 784989f8f2f5ef79c65b1cec3c5b4cda84d16a07..5acd2ab298b107786bb57433f608f487884377b6 100644 (file)
@@ -20,7 +20,7 @@
 #include <plat/omap-pm.h>
 
 #ifdef CONFIG_PM_RUNTIME
-int omap_pm_runtime_suspend(struct device *dev)
+static int omap_pm_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        int r, ret = 0;
@@ -37,7 +37,7 @@ int omap_pm_runtime_suspend(struct device *dev)
        return ret;
 };
 
-int omap_pm_runtime_resume(struct device *dev)
+static int omap_pm_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        int r;
index 53d44f6e37366a4d9a4a4b550b7b24dd42084845..49654c8d18f53880c4107722aa90f2f3833d9ea8 100644 (file)
 
 
 #ifndef __ASSEMBLER__
-
+/*
+ * Stub omap2xxx/omap3xxx functions so that common files
+ * continue to build when custom builds are used
+ */
+#if defined(CONFIG_ARCH_OMAP4) && !(defined(CONFIG_ARCH_OMAP2) ||      \
+                                       defined(CONFIG_ARCH_OMAP3))
+static inline u32 omap2_prm_read_mod_reg(s16 module, u16 idx)
+{
+       WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+               "not suppose to be used on omap4\n");
+       return 0;
+}
+static inline void omap2_prm_write_mod_reg(u32 val, s16 module, u16 idx)
+{
+       WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+               "not suppose to be used on omap4\n");
+}
+static inline u32 omap2_prm_rmw_mod_reg_bits(u32 mask, u32 bits,
+               s16 module, s16 idx)
+{
+       WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+               "not suppose to be used on omap4\n");
+       return 0;
+}
+static inline u32 omap2_prm_set_mod_reg_bits(u32 bits, s16 module, s16 idx)
+{
+       WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+               "not suppose to be used on omap4\n");
+       return 0;
+}
+static inline u32 omap2_prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
+{
+       WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+               "not suppose to be used on omap4\n");
+       return 0;
+}
+static inline u32 omap2_prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask)
+{
+       WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+               "not suppose to be used on omap4\n");
+       return 0;
+}
+static inline int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift)
+{
+       WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+               "not suppose to be used on omap4\n");
+       return 0;
+}
+static inline int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
+{
+       WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+               "not suppose to be used on omap4\n");
+       return 0;
+}
+static inline int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift)
+{
+       WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+               "not suppose to be used on omap4\n");
+       return 0;
+}
+#else
 /* Power/reset management domain register get/set */
 extern u32 omap2_prm_read_mod_reg(s16 module, u16 idx);
 extern void omap2_prm_write_mod_reg(u32 val, s16 module, u16 idx);
@@ -242,6 +302,7 @@ extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift);
 extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift);
 extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift);
 
+#endif /* CONFIG_ARCH_OMAP4 */
 #endif
 
 /*
index 786d685c09a92a7f91a5cd51669e2de71ce782bc..b1e0af18a26a06a6e75924d6cfc5dbcabadf8d8c 100644 (file)
@@ -27,6 +27,7 @@
 #include <plat/voltage.h>
 
 #include "control.h"
+#include "pm.h"
 
 static bool sr_enable_on_init;
 
index b0c4907ab3caa216b8cdfd37a9f35f50ac2eab48..4067669d96c47433889da4e92124426bee89bcaa 100644 (file)
@@ -13,6 +13,8 @@
 
 #include <plat/omap_hwmod.h>
 
+#include "wd_timer.h"
+
 /*
  * In order to avoid any assumptions from bootloader regarding WDT
  * settings, WDT module is reset during init. This enables the watchdog
index fcc1e628e050471d7bfde79e772075dbb0735b97..9d30c6f804b9de6454c9dc7b8bb16974ed487a16 100644 (file)
@@ -644,7 +644,7 @@ config ARM_THUMBEE
 
 config SWP_EMULATE
        bool "Emulate SWP/SWPB instructions"
-       depends on CPU_V7
+       depends on CPU_V7 && !CPU_V6
        select HAVE_PROC_CPU if PROC_FS
        default y if SMP
        help
index 1f98e0b948478dc92abccc71580c66b02223e73e..ccf2660f4151718a01562213753f4d652c6bbff1 100644 (file)
@@ -718,7 +718,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
        case METHOD_GPIO_24XX:
        case METHOD_GPIO_44XX:
                set_24xx_gpio_triggering(bank, gpio, trigger);
-               break;
+               return 0;
 #endif
        default:
                goto bad;
@@ -756,8 +756,10 @@ static int gpio_irq_type(unsigned irq, unsigned type)
        spin_lock_irqsave(&bank->lock, flags);
        retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type);
        if (retval == 0) {
-               irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK;
-               irq_desc[irq].status |= type;
+               struct irq_desc *d = irq_to_desc(irq);
+
+               d->status &= ~IRQ_TYPE_SENSE_MASK;
+               d->status |= type;
        }
        spin_unlock_irqrestore(&bank->lock, flags);
 
@@ -1671,7 +1673,9 @@ static void __init omap_gpio_chip_init(struct gpio_bank *bank)
 
        for (j = bank->virtual_irq_start;
                     j < bank->virtual_irq_start + bank_width; j++) {
-               lockdep_set_class(&irq_desc[j].lock, &gpio_lock_class);
+               struct irq_desc *d = irq_to_desc(j);
+
+               lockdep_set_class(&d->lock, &gpio_lock_class);
                set_irq_chip_data(j, bank);
                if (bank_is_mpuio(bank))
                        set_irq_chip(j, &mpuio_irq_chip);
index 0ff123399f3b6576f631646bb3fd8320087c7c85..5bd204e55c32552e21d9093a07c34ce7d17b39dc 100644 (file)
@@ -14,6 +14,8 @@
 #ifndef __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
 #define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
 
+#include <linux/err.h>
+
 #define VOLTSCALE_VPFORCEUPDATE                1
 #define VOLTSCALE_VCBYPASS             2
 
@@ -65,9 +67,6 @@ struct voltagedomain {
        char *name;
 };
 
-/* API to get the voltagedomain pointer */
-struct voltagedomain *omap_voltage_domain_lookup(char *name);
-
 /**
  * struct omap_volt_data - Omap voltage specific data.
  * @voltage_nominal:   The possible voltage value in uV
@@ -131,16 +130,26 @@ int omap_voltage_register_pmic(struct voltagedomain *voltdm,
                struct omap_volt_pmic_info *pmic_info);
 void omap_change_voltscale_method(struct voltagedomain *voltdm,
                int voltscale_method);
+/* API to get the voltagedomain pointer */
+struct voltagedomain *omap_voltage_domain_lookup(char *name);
+
 int omap_voltage_late_init(void);
 #else
 static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm,
-               struct omap_volt_pmic_info *pmic_info) {}
+               struct omap_volt_pmic_info *pmic_info)
+{
+       return -EINVAL;
+}
 static inline  void omap_change_voltscale_method(struct voltagedomain *voltdm,
                int voltscale_method) {}
 static inline int omap_voltage_late_init(void)
 {
        return -EINVAL;
 }
+static inline struct voltagedomain *omap_voltage_domain_lookup(char *name)
+{
+       return ERR_PTR(-EINVAL);
+}
 #endif
 
 #endif
index 41b6d31110fd697384dfacd959213f8792d23209..961a16f43e6b9d2f7e1c845a4fedf493f28b57ca 100644 (file)
@@ -189,6 +189,7 @@ get_order (unsigned long size)
 # define pgprot_val(x) ((x).pgprot)
 
 # define __pte(x)      ((pte_t) { (x) } )
+# define __pmd(x)      ((pmd_t) { (x) } )
 # define __pgprot(x)   ((pgprot_t) { (x) } )
 
 #else /* !STRICT_MM_TYPECHECKS */
index d79697157ac098869afdfc7d57ba6b402e9f7f32..29c82c640a8829a49ce82f3a61a2cfddfd4ae91d 100644 (file)
@@ -5,10 +5,21 @@ CONFIG_AUDIT=y
 CONFIG_RCU_TRACE=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_MEM_RES_CTLR=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_PERF_EVENTS=y
+# CONFIG_COMPAT_BRK is not set
 CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -19,7 +30,9 @@ CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT=y
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
+CONFIG_KSM=y
 CONFIG_BINFMT_MISC=m
+CONFIG_CMM=m
 CONFIG_HZ_100=y
 CONFIG_KEXEC=y
 CONFIG_PM=y
@@ -105,6 +118,7 @@ CONFIG_DEBUG_LIST=y
 CONFIG_DEBUG_NOTIFIERS=y
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_KPROBES_SANITY_TEST=y
+CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
 CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
 CONFIG_LATENCYTOP=y
 CONFIG_SYSCTL_SYSCALL_CHECK=y
index a875c2f542e1070a120b484c96a0d2fc10fc55cb..da359ca6fe55efdc9e9aff257622550bf55f008c 100644 (file)
@@ -169,7 +169,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
 
 static inline int is_compat_task(void)
 {
-       return test_thread_flag(TIF_31BIT);
+       return is_32bit_task();
 }
 
 #else
index 354d42616c7e6dc057a4bbf1bbfbb80805f7d880..10c029cfcc7d3c7d8e8feda790c6c3e885fa34a9 100644 (file)
@@ -161,7 +161,9 @@ extern unsigned int vdso_enabled;
    use of this is to invoke "./ld.so someprog" to test out a new version of
    the loader.  We need to make sure that it is out of the way of the program
    that it will "exec", and that there is sufficient room for the brk.  */
-#define ELF_ET_DYN_BASE                (STACK_TOP / 3 * 2)
+
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE                (randomize_et_dyn(STACK_TOP / 3 * 2))
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this CPU supports. */
@@ -206,6 +208,8 @@ do {                                                                \
        current->mm->context.noexec == 0;               \
 })
 
+#define STACK_RND_MASK 0x7ffUL
+
 #define ARCH_DLINFO                                                        \
 do {                                                                       \
        if (vdso_enabled)                                                   \
@@ -218,4 +222,7 @@ struct linux_binprm;
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
 int arch_setup_additional_pages(struct linux_binprm *, int);
 
+extern unsigned long arch_randomize_brk(struct mm_struct *mm);
+#define arch_randomize_brk arch_randomize_brk
+
 #endif
index 6710b0eac165765f2835f214464ad5f9750c3866..8f8d759f6a7b696327955c2643312a52fd900c90 100644 (file)
@@ -449,7 +449,7 @@ extern void (*_machine_restart)(char *command);
 extern void (*_machine_halt)(void);
 extern void (*_machine_power_off)(void);
 
-#define arch_align_stack(x) (x)
+extern unsigned long arch_align_stack(unsigned long sp);
 
 static inline int tprot(unsigned long addr)
 {
index ebc77091466fbf59b96aaf6a35d7089b99d67125..ad1382f7932e83152e59bff9d020d9ba84cb5c98 100644 (file)
@@ -118,6 +118,12 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SINGLE_STEP       (1<<TIF_FREEZE)
 #define _TIF_FREEZE            (1<<TIF_FREEZE)
 
+#ifdef CONFIG_64BIT
+#define is_32bit_task()                (test_thread_flag(TIF_31BIT))
+#else
+#define is_32bit_task()                (1)
+#endif
+
 #endif /* __KERNEL__ */
 
 #define PREEMPT_ACTIVE         0x4000000
index 6ba42222b5423d6e2a6e294f5bbcfcdb9529759a..a895e69379f75233a84ab98681fbd9dc6421fbe1 100644 (file)
 #include <linux/tick.h>
 #include <linux/elfcore.h>
 #include <linux/kernel_stat.h>
+#include <linux/personality.h>
 #include <linux/syscalls.h>
 #include <linux/compat.h>
 #include <linux/kprobes.h>
+#include <linux/random.h>
 #include <asm/compat.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -332,3 +334,39 @@ unsigned long get_wchan(struct task_struct *p)
        }
        return 0;
 }
+
+unsigned long arch_align_stack(unsigned long sp)
+{
+       if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+               sp -= get_random_int() & ~PAGE_MASK;
+       return sp & ~0xf;
+}
+
+static inline unsigned long brk_rnd(void)
+{
+       /* 8MB for 32bit, 1GB for 64bit */
+       if (is_32bit_task())
+               return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
+       else
+               return (get_random_int() & 0x3ffffUL) << PAGE_SHIFT;
+}
+
+unsigned long arch_randomize_brk(struct mm_struct *mm)
+{
+       unsigned long ret = PAGE_ALIGN(mm->brk + brk_rnd());
+
+       if (ret < mm->brk)
+               return mm->brk;
+       return ret;
+}
+
+unsigned long randomize_et_dyn(unsigned long base)
+{
+       unsigned long ret = PAGE_ALIGN(base + brk_rnd());
+
+       if (!(current->flags & PF_RANDOMIZE))
+               return base;
+       if (ret < base)
+               return base;
+       return ret;
+}
index e3150dd2fe7457604a9e041a9a274dee6861addd..f438d74dedbd171fa151f234a96e4f173358403a 100644 (file)
@@ -203,7 +203,6 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
        if (!uses_interp)
                return 0;
 
-       vdso_base = mm->mmap_base;
 #ifdef CONFIG_64BIT
        vdso_pagelist = vdso64_pagelist;
        vdso_pages = vdso64_pages;
@@ -233,8 +232,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
         * fail and end up putting it elsewhere.
         */
        down_write(&mm->mmap_sem);
-       vdso_base = get_unmapped_area(NULL, vdso_base,
-                                     vdso_pages << PAGE_SHIFT, 0, 0);
+       vdso_base = get_unmapped_area(NULL, 0, vdso_pages << PAGE_SHIFT, 0, 0);
        if (IS_ERR_VALUE(vdso_base)) {
                rc = vdso_base;
                goto out_up;
index 869efbaed3eadf76db6c90de2bd75550fb630bf6..c9a9f7f1818818cddc4eac89b57fa7e8d6cb65fb 100644 (file)
 #include <linux/personality.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/random.h>
 #include <asm/pgalloc.h>
 #include <asm/compat.h>
 
+static unsigned long stack_maxrandom_size(void)
+{
+       if (!(current->flags & PF_RANDOMIZE))
+               return 0;
+       if (current->personality & ADDR_NO_RANDOMIZE)
+               return 0;
+       return STACK_RND_MASK << PAGE_SHIFT;
+}
+
 /*
  * Top of mmap area (just below the process stack).
  *
- * Leave an at least ~128 MB hole.
+ * Leave at least a ~32 MB hole.
  */
-#define MIN_GAP (128*1024*1024)
+#define MIN_GAP (32*1024*1024)
 #define MAX_GAP (STACK_TOP/6*5)
 
+static inline int mmap_is_legacy(void)
+{
+       if (current->personality & ADDR_COMPAT_LAYOUT)
+               return 1;
+       if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
+               return 1;
+       return sysctl_legacy_va_layout;
+}
+
+static unsigned long mmap_rnd(void)
+{
+       if (!(current->flags & PF_RANDOMIZE))
+               return 0;
+       /* 8MB randomization for mmap_base */
+       return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
+}
+
 static inline unsigned long mmap_base(void)
 {
        unsigned long gap = rlimit(RLIMIT_STACK);
@@ -46,22 +73,8 @@ static inline unsigned long mmap_base(void)
                gap = MIN_GAP;
        else if (gap > MAX_GAP)
                gap = MAX_GAP;
-
-       return STACK_TOP - (gap & PAGE_MASK);
-}
-
-static inline int mmap_is_legacy(void)
-{
-#ifdef CONFIG_64BIT
-       /*
-        * Force standard allocation for 64 bit programs.
-        */
-       if (!is_compat_task())
-               return 1;
-#endif
-       return sysctl_legacy_va_layout ||
-           (current->personality & ADDR_COMPAT_LAYOUT) ||
-           rlimit(RLIMIT_STACK) == RLIM_INFINITY;
+       gap &= PAGE_MASK;
+       return STACK_TOP - stack_maxrandom_size() - mmap_rnd() - gap;
 }
 
 #ifndef CONFIG_64BIT
index 36ed2e2c896b47d9b6982f515046b768fa995a86..47ae4a751a59212982bb2a92191c94ebd712e187 100644 (file)
@@ -1934,13 +1934,19 @@ config PCI_MMCONFIG
        depends on X86_64 && PCI && ACPI
 
 config PCI_CNB20LE_QUIRK
-       bool "Read CNB20LE Host Bridge Windows"
-       depends on PCI
+       bool "Read CNB20LE Host Bridge Windows" if EMBEDDED
+       default n
+       depends on PCI && EXPERIMENTAL
        help
          Read the PCI windows out of the CNB20LE host bridge. This allows
          PCI hotplug to work on systems with the CNB20LE chipset which do
          not have ACPI.
 
+         There's no public spec for this chipset, and this functionality
+         is known to be incomplete.
+
+         You should say N unless you know you need this.
+
 config DMAR
        bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
        depends on PCI_MSI && ACPI && EXPERIMENTAL
@@ -2068,7 +2074,7 @@ config OLPC
 
 config OLPC_XO1
        tristate "OLPC XO-1 support"
-       depends on OLPC && PCI
+       depends on OLPC && MFD_CS5535
        ---help---
          Add support for non-essential features of the OLPC XO-1 laptop.
 
index 0846a5bbbfbd927bf94978cf7c2b90018b8f9304..ab8269b0da29e3c5ce000fefc5429f86cdd23dfd 100644 (file)
@@ -9,6 +9,7 @@
  * option) any later version.
  */
 
+#include <linux/acpi.h>
 #include <linux/delay.h>
 #include <linux/dmi.h>
 #include <linux/pci.h>
@@ -25,12 +26,14 @@ static void __devinit cnb20le_res(struct pci_dev *dev)
        u8 fbus, lbus;
        int i;
 
+#ifdef CONFIG_ACPI
        /*
-        * The x86_pci_root_bus_res_quirks() function already refuses to use
-        * this information if ACPI _CRS was used. Therefore, we don't bother
-        * checking if ACPI is enabled, and just generate the information
-        * for both the ACPI _CRS and no ACPI cases.
+        * We should get host bridge information from ACPI unless the BIOS
+        * doesn't support it.
         */
+       if (acpi_os_get_root_pointer())
+               return;
+#endif
 
        info = &pci_root_info[pci_root_num];
        pci_root_num++;
index f7c8a399978ccdfe266d7919b0f8a59db8fbea25..5fe75026ecc29a89a914b2c8a8c5cc367d96477d 100644 (file)
@@ -22,6 +22,7 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
 
 unsigned int pci_early_dump_regs;
 static int pci_bf_sort;
+static int smbios_type_b1_flag;
 int pci_routeirq;
 int noioapicquirk;
 #ifdef CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS
@@ -185,6 +186,39 @@ static int __devinit set_bf_sort(const struct dmi_system_id *d)
        return 0;
 }
 
+static void __devinit read_dmi_type_b1(const struct dmi_header *dm,
+                                      void *private_data)
+{
+       u8 *d = (u8 *)dm + 4;
+
+       if (dm->type != 0xB1)
+               return;
+       switch (((*(u32 *)d) >> 9) & 0x03) {
+       case 0x00:
+               printk(KERN_INFO "dmi type 0xB1 record - unknown flag\n");
+               break;
+       case 0x01: /* set pci=bfsort */
+               smbios_type_b1_flag = 1;
+               break;
+       case 0x02: /* do not set pci=bfsort */
+               smbios_type_b1_flag = 2;
+               break;
+       default:
+               break;
+       }
+}
+
+static int __devinit find_sort_method(const struct dmi_system_id *d)
+{
+       dmi_walk(read_dmi_type_b1, NULL);
+
+       if (smbios_type_b1_flag == 1) {
+               set_bf_sort(d);
+               return 0;
+       }
+       return -1;
+}
+
 /*
  * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus)
  */
@@ -212,6 +246,13 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = {
                },
        },
 #endif         /* __i386__ */
+       {
+               .callback = find_sort_method,
+               .ident = "Dell System",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+               },
+       },
        {
                .callback = set_bf_sort,
                .ident = "Dell PowerEdge 1950",
index 9f9bfb705cf98bdfb22258100a6643409d1621b2..87e6c83231172f8bc70bb389b03f498dd0b28c7a 100644 (file)
@@ -589,7 +589,8 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
        case PCI_DEVICE_ID_INTEL_ICH10_1:
        case PCI_DEVICE_ID_INTEL_ICH10_2:
        case PCI_DEVICE_ID_INTEL_ICH10_3:
-       case PCI_DEVICE_ID_INTEL_PATSBURG_LPC:
+       case PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0:
+       case PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1:
                r->name = "PIIX/ICH";
                r->get = pirq_piix_get;
                r->set = pirq_piix_set;
index f5442c03abc34dd47b58e4742df180516aa6a7be..127775696d6c34c254c3390d3180e929314fc3b3 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Support for features of the OLPC XO-1 laptop
  *
+ * Copyright (C) 2010 Andres Salomon <dilinger@queued.net>
  * Copyright (C) 2010 One Laptop per Child
  * Copyright (C) 2006 Red Hat, Inc.
  * Copyright (C) 2006 Advanced Micro Devices, Inc.
@@ -12,8 +13,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 
@@ -22,9 +21,6 @@
 
 #define DRV_NAME "olpc-xo1"
 
-#define PMS_BAR                4
-#define ACPI_BAR       5
-
 /* PMC registers (PMS block) */
 #define PM_SCLK                0x10
 #define PM_IN_SLPCTL   0x20
@@ -57,65 +53,67 @@ static void xo1_power_off(void)
        outl(0x00002000, acpi_base + PM1_CNT);
 }
 
-/* Read the base addresses from the PCI BAR info */
-static int __devinit setup_bases(struct pci_dev *pdev)
+static int __devinit olpc_xo1_probe(struct platform_device *pdev)
 {
-       int r;
+       struct resource *res;
 
-       r = pci_enable_device_io(pdev);
-       if (r) {
-               dev_err(&pdev->dev, "can't enable device IO\n");
-               return r;
-       }
+       /* don't run on non-XOs */
+       if (!machine_is_olpc())
+               return -ENODEV;
 
-       r = pci_request_region(pdev, ACPI_BAR, DRV_NAME);
-       if (r) {
-               dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", ACPI_BAR);
-               return r;
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "can't fetch device resource info\n");
+               return -EIO;
        }
 
-       r = pci_request_region(pdev, PMS_BAR, DRV_NAME);
-       if (r) {
-               dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", PMS_BAR);
-               pci_release_region(pdev, ACPI_BAR);
-               return r;
+       if (!request_region(res->start, resource_size(res), DRV_NAME)) {
+               dev_err(&pdev->dev, "can't request region\n");
+               return -EIO;
        }
 
-       acpi_base = pci_resource_start(pdev, ACPI_BAR);
-       pms_base = pci_resource_start(pdev, PMS_BAR);
+       if (strcmp(pdev->name, "cs5535-pms") == 0)
+               pms_base = res->start;
+       else if (strcmp(pdev->name, "cs5535-acpi") == 0)
+               acpi_base = res->start;
+
+       /* If we have both addresses, we can override the poweroff hook */
+       if (pms_base && acpi_base) {
+               pm_power_off = xo1_power_off;
+               printk(KERN_INFO "OLPC XO-1 support registered\n");
+       }
 
        return 0;
 }
 
-static int __devinit olpc_xo1_probe(struct platform_device *pdev)
+static int __devexit olpc_xo1_remove(struct platform_device *pdev)
 {
-       struct pci_dev *pcidev;
-       int r;
-
-       pcidev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
-                               NULL);
-       if (!pdev)
-               return -ENODEV;
-
-       r = setup_bases(pcidev);
-       if (r)
-               return r;
+       struct resource *r;
 
-       pm_power_off = xo1_power_off;
+       r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       release_region(r->start, resource_size(r));
 
-       printk(KERN_INFO "OLPC XO-1 support registered\n");
-       return 0;
-}
+       if (strcmp(pdev->name, "cs5535-pms") == 0)
+               pms_base = 0;
+       else if (strcmp(pdev->name, "cs5535-acpi") == 0)
+               acpi_base = 0;
 
-static int __devexit olpc_xo1_remove(struct platform_device *pdev)
-{
        pm_power_off = NULL;
        return 0;
 }
 
-static struct platform_driver olpc_xo1_driver = {
+static struct platform_driver cs5535_pms_drv = {
+       .driver = {
+               .name = "cs5535-pms",
+               .owner = THIS_MODULE,
+       },
+       .probe = olpc_xo1_probe,
+       .remove = __devexit_p(olpc_xo1_remove),
+};
+
+static struct platform_driver cs5535_acpi_drv = {
        .driver = {
-               .name = DRV_NAME,
+               .name = "cs5535-acpi",
                .owner = THIS_MODULE,
        },
        .probe = olpc_xo1_probe,
@@ -124,12 +122,23 @@ static struct platform_driver olpc_xo1_driver = {
 
 static int __init olpc_xo1_init(void)
 {
-       return platform_driver_register(&olpc_xo1_driver);
+       int r;
+
+       r = platform_driver_register(&cs5535_pms_drv);
+       if (r)
+               return r;
+
+       r = platform_driver_register(&cs5535_acpi_drv);
+       if (r)
+               platform_driver_unregister(&cs5535_pms_drv);
+
+       return r;
 }
 
 static void __exit olpc_xo1_exit(void)
 {
-       platform_driver_unregister(&olpc_xo1_driver);
+       platform_driver_unregister(&cs5535_acpi_drv);
+       platform_driver_unregister(&cs5535_pms_drv);
 }
 
 MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
index 7575e55cd52e4b453f4d53c1010cba73cb72083c..5e92b61ad574dd6514f09644737dd450d0311dd0 100644 (file)
@@ -201,6 +201,7 @@ xmaddr_t arbitrary_virt_to_machine(void *vaddr)
        offset = address & ~PAGE_MASK;
        return XMADDR(((phys_addr_t)pte_mfn(*pte) << PAGE_SHIFT) + offset);
 }
+EXPORT_SYMBOL_GPL(arbitrary_virt_to_machine);
 
 void make_lowmem_page_readonly(void *vaddr)
 {
index 8427697c5437c2961633d1a7b7c10465a96f1fa2..501ffdf0399c9b848ac5379531b5aac8b0172a35 100644 (file)
@@ -598,8 +598,8 @@ cfq_group_slice(struct cfq_data *cfqd, struct cfq_group *cfqg)
        return cfq_target_latency * cfqg->weight / st->total_weight;
 }
 
-static inline void
-cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+static inline unsigned
+cfq_scaled_group_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        unsigned slice = cfq_prio_to_slice(cfqd, cfqq);
        if (cfqd->cfq_latency) {
@@ -625,6 +625,14 @@ cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
                                    low_slice);
                }
        }
+       return slice;
+}
+
+static inline void
+cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+       unsigned slice = cfq_scaled_group_slice(cfqd, cfqq);
+
        cfqq->slice_start = jiffies;
        cfqq->slice_end = jiffies + slice;
        cfqq->allocated_slice = slice;
@@ -1661,8 +1669,11 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        /*
         * store what was left of this slice, if the queue idled/timed out
         */
-       if (timed_out && !cfq_cfqq_slice_new(cfqq)) {
-               cfqq->slice_resid = cfqq->slice_end - jiffies;
+       if (timed_out) {
+               if (cfq_cfqq_slice_new(cfqq))
+                       cfqq->slice_resid = cfq_scaled_group_slice(cfqd, cfqq);
+               else
+                       cfqq->slice_resid = cfqq->slice_end - jiffies;
                cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid);
        }
 
@@ -3284,9 +3295,18 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
  */
 static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
+       struct cfq_queue *old_cfqq = cfqd->active_queue;
+
        cfq_log_cfqq(cfqd, cfqq, "preempt");
        cfq_slice_expired(cfqd, 1);
 
+       /*
+        * workload type is changed, don't save slice, otherwise preempt
+        * doesn't happen
+        */
+       if (cfqq_type(old_cfqq) != cfqq_type(cfqq))
+               cfqq->cfqg->saved_workload_slice = 0;
+
        /*
         * Put the new queue at the front of the of the current list,
         * so we know that it will be selected next.
index 9bb69c59bb12978fb0c33d239f6014007253d28f..0e4dba0d0325329da4c4ebb508c4978c1094190f 100644 (file)
@@ -228,8 +228,10 @@ ACPI_EXTERN u8 acpi_gbl_global_lock_present;
  */
 ACPI_EXTERN spinlock_t _acpi_gbl_gpe_lock;     /* For GPE data structs and registers */
 ACPI_EXTERN spinlock_t _acpi_gbl_hardware_lock;        /* For ACPI H/W except GPE registers */
+ACPI_EXTERN spinlock_t _acpi_ev_global_lock_pending_lock; /* For global lock */
 #define acpi_gbl_gpe_lock      &_acpi_gbl_gpe_lock
 #define acpi_gbl_hardware_lock &_acpi_gbl_hardware_lock
+#define acpi_ev_global_lock_pending_lock &_acpi_ev_global_lock_pending_lock
 
 /*****************************************************************************
  *
index 8e31bb5a973ae2483129781eb756089554d7b694..38bba66fcce554a62ed63b3f5afd76d7d18186ba 100644 (file)
@@ -293,8 +293,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
  *
  ******************************************************************************/
 static u8 acpi_ev_global_lock_pending;
-static spinlock_t _acpi_ev_global_lock_pending_lock;
-#define acpi_ev_global_lock_pending_lock &_acpi_ev_global_lock_pending_lock
 
 static u32 acpi_ev_global_lock_handler(void *context)
 {
index d9efa495b4330049a1fa57fde968938c6cb18f0b..199528ff7f1d2edde7b17d832940117b33449a16 100644 (file)
@@ -85,6 +85,7 @@ acpi_status acpi_ut_mutex_initialize(void)
 
        spin_lock_init(acpi_gbl_gpe_lock);
        spin_lock_init(acpi_gbl_hardware_lock);
+       spin_lock_init(acpi_ev_global_lock_pending_lock);
 
        /* Mutex for _OSI support */
        status = acpi_os_create_mutex(&acpi_gbl_osi_mutex);
index daa7bc63f1d4bad00fd988ddcce3681fdc74f804..4ee58e72b730569fc3e16d4412be078b107baf03 100644 (file)
@@ -195,24 +195,24 @@ static int __init setup_hest_disable(char *str)
 
 __setup("hest_disable", setup_hest_disable);
 
-static int __init hest_init(void)
+void __init acpi_hest_init(void)
 {
        acpi_status status;
        int rc = -ENODEV;
        unsigned int ghes_count = 0;
 
        if (acpi_disabled)
-               goto err;
+               return;
 
        if (hest_disable) {
-               pr_info(HEST_PFX "HEST tabling parsing is disabled.\n");
-               goto err;
+               pr_info(HEST_PFX "Table parsing disabled.\n");
+               return;
        }
 
        status = acpi_get_table(ACPI_SIG_HEST, 0,
                                (struct acpi_table_header **)&hest_tab);
        if (status == AE_NOT_FOUND) {
-               pr_info(HEST_PFX "Table is not found!\n");
+               pr_info(HEST_PFX "Table not found.\n");
                goto err;
        } else if (ACPI_FAILURE(status)) {
                const char *msg = acpi_format_exception(status);
@@ -226,15 +226,11 @@ static int __init hest_init(void)
                goto err;
 
        rc = hest_ghes_dev_register(ghes_count);
-       if (rc)
-               goto err;
-
-       pr_info(HEST_PFX "HEST table parsing is initialized.\n");
+       if (!rc) {
+               pr_info(HEST_PFX "Table parsing has been initialized.\n");
+               return;
+       }
 
-       return 0;
 err:
        hest_disable = 1;
-       return rc;
 }
-
-subsys_initcall(hest_init);
index 96668ad096227add7ca952fd66cb9cf8c80bf20f..d9766797cd982721d35182882af470a3c3094e2d 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/slab.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
+#include <acpi/apei.h>
 
 #define PREFIX "ACPI: "
 
@@ -47,6 +48,11 @@ static int acpi_pci_root_add(struct acpi_device *device);
 static int acpi_pci_root_remove(struct acpi_device *device, int type);
 static int acpi_pci_root_start(struct acpi_device *device);
 
+#define ACPI_PCIE_REQ_SUPPORT (OSC_EXT_PCI_CONFIG_SUPPORT \
+                               | OSC_ACTIVE_STATE_PWR_SUPPORT \
+                               | OSC_CLOCK_PWR_CAPABILITY_SUPPORT \
+                               | OSC_MSI_SUPPORT)
+
 static const struct acpi_device_id root_device_ids[] = {
        {"PNP0A03", 0},
        {"", 0},
@@ -566,6 +572,33 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
        if (flags != base_flags)
                acpi_pci_osc_support(root, flags);
 
+       if (!pcie_ports_disabled
+           && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) {
+               flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
+                       | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
+                       | OSC_PCI_EXPRESS_PME_CONTROL;
+
+               if (pci_aer_available()) {
+                       if (aer_acpi_firmware_first())
+                               dev_dbg(root->bus->bridge,
+                                       "PCIe errors handled by BIOS.\n");
+                       else
+                               flags |= OSC_PCI_EXPRESS_AER_CONTROL;
+               }
+
+               dev_info(root->bus->bridge,
+                       "Requesting ACPI _OSC control (0x%02x)\n", flags);
+
+               status = acpi_pci_osc_control_set(device->handle, &flags,
+                                       OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+               if (ACPI_SUCCESS(status))
+                       dev_info(root->bus->bridge,
+                               "ACPI _OSC control (0x%02x) granted\n", flags);
+               else
+                       dev_dbg(root->bus->bridge,
+                               "ACPI _OSC request failed (code %d)\n", status);
+       }
+
        pci_acpi_add_bus_pm_notifier(device, root->bus);
        if (device->wakeup.flags.run_wake)
                device_set_run_wake(root->bus->bridge, true);
@@ -603,6 +636,8 @@ static int __init acpi_pci_root_init(void)
        if (acpi_pci_disabled)
                return 0;
 
+       acpi_hest_init();
+
        pci_acpi_crs_quirks();
        if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0)
                return -ENODEV;
index 07e9796fead7a879ecdba8a0504408e2a391b134..857df10c04284c82b9f97f47538ea0cca376568c 100644 (file)
@@ -717,8 +717,8 @@ static const struct intel_agp_driver_description {
        { PCI_DEVICE_ID_INTEL_82820_UP_HB, "i820", &intel_820_driver },
        { PCI_DEVICE_ID_INTEL_82830_HB, "830M", &intel_830mp_driver },
        { PCI_DEVICE_ID_INTEL_82840_HB, "i840", &intel_840_driver },
-       { PCI_DEVICE_ID_INTEL_82845_HB, "845G", &intel_845_driver },
-       { PCI_DEVICE_ID_INTEL_82845G_HB, "830M", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82845_HB, "i845", &intel_845_driver },
+       { PCI_DEVICE_ID_INTEL_82845G_HB, "845G", &intel_845_driver },
        { PCI_DEVICE_ID_INTEL_82850_HB, "i850", &intel_850_driver },
        { PCI_DEVICE_ID_INTEL_82854_HB, "854", &intel_845_driver },
        { PCI_DEVICE_ID_INTEL_82855PM_HB, "855PM", &intel_845_driver },
index e921b693412b9ec4dc994340c3724ee99dcc94b4..826ab0939a128308b294207eda495207884f5361 100644 (file)
@@ -1361,7 +1361,7 @@ static const struct intel_gtt_driver_description {
                &i81x_gtt_driver},
        { PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
                &i8xx_gtt_driver},
-       { PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
+       { PCI_DEVICE_ID_INTEL_82845G_IG, "845G",
                &i8xx_gtt_driver},
        { PCI_DEVICE_ID_INTEL_82854_IG, "854",
                &i8xx_gtt_driver},
index 815d98b2c1ba7aa02b92ee72401009f6925a6ed0..0d05ea7d499b8cb60932807c4861bfd8a1c03be2 100644 (file)
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/module.h>
-#include <linux/pci.h>
+#include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
 #include <linux/cs5535.h>
 #include <asm/msr.h>
 
 #define DRV_NAME "cs5535-gpio"
-#define GPIO_BAR 1
 
 /*
  * Some GPIO pins
@@ -47,7 +46,7 @@ static struct cs5535_gpio_chip {
        struct gpio_chip chip;
        resource_size_t base;
 
-       struct pci_dev *pdev;
+       struct platform_device *pdev;
        spinlock_t lock;
 } cs5535_gpio_chip;
 
@@ -301,10 +300,10 @@ static struct cs5535_gpio_chip cs5535_gpio_chip = {
        },
 };
 
-static int __init cs5535_gpio_probe(struct pci_dev *pdev,
-               const struct pci_device_id *pci_id)
+static int __devinit cs5535_gpio_probe(struct platform_device *pdev)
 {
-       int err;
+       struct resource *res;
+       int err = -EIO;
        ulong mask_orig = mask;
 
        /* There are two ways to get the GPIO base address; one is by
@@ -314,25 +313,23 @@ static int __init cs5535_gpio_probe(struct pci_dev *pdev,
         * it turns out to be unreliable in the face of crappy BIOSes, we
         * can always go back to using MSRs.. */
 
-       err = pci_enable_device_io(pdev);
-       if (err) {
-               dev_err(&pdev->dev, "can't enable device IO\n");
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "can't fetch device resource info\n");
                goto done;
        }
 
-       err = pci_request_region(pdev, GPIO_BAR, DRV_NAME);
-       if (err) {
-               dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR);
+       if (!request_region(res->start, resource_size(res), pdev->name)) {
+               dev_err(&pdev->dev, "can't request region\n");
                goto done;
        }
 
        /* set up the driver-specific struct */
-       cs5535_gpio_chip.base = pci_resource_start(pdev, GPIO_BAR);
+       cs5535_gpio_chip.base = res->start;
        cs5535_gpio_chip.pdev = pdev;
        spin_lock_init(&cs5535_gpio_chip.lock);
 
-       dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", GPIO_BAR,
-                       (unsigned long long) cs5535_gpio_chip.base);
+       dev_info(&pdev->dev, "reserved resource region %pR\n", res);
 
        /* mask out reserved pins */
        mask &= 0x1F7FFFFF;
@@ -350,78 +347,49 @@ static int __init cs5535_gpio_probe(struct pci_dev *pdev,
        if (err)
                goto release_region;
 
-       dev_info(&pdev->dev, DRV_NAME ": GPIO support successfully loaded.\n");
+       dev_info(&pdev->dev, "GPIO support successfully loaded.\n");
        return 0;
 
 release_region:
-       pci_release_region(pdev, GPIO_BAR);
+       release_region(res->start, resource_size(res));
 done:
        return err;
 }
 
-static void __exit cs5535_gpio_remove(struct pci_dev *pdev)
+static int __devexit cs5535_gpio_remove(struct platform_device *pdev)
 {
+       struct resource *r;
        int err;
 
        err = gpiochip_remove(&cs5535_gpio_chip.chip);
        if (err) {
                /* uhh? */
                dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
+               return err;
        }
-       pci_release_region(pdev, GPIO_BAR);
-}
-
-static struct pci_device_id cs5535_gpio_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
-       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
-       { 0, },
-};
-MODULE_DEVICE_TABLE(pci, cs5535_gpio_pci_tbl);
 
-/*
- * We can't use the standard PCI driver registration stuff here, since
- * that allows only one driver to bind to each PCI device (and we want
- * multiple drivers to be able to bind to the device).  Instead, manually
- * scan for the PCI device, request a single region, and keep track of the
- * devices that we're using.
- */
-
-static int __init cs5535_gpio_scan_pci(void)
-{
-       struct pci_dev *pdev;
-       int err = -ENODEV;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(cs5535_gpio_pci_tbl); i++) {
-               pdev = pci_get_device(cs5535_gpio_pci_tbl[i].vendor,
-                               cs5535_gpio_pci_tbl[i].device, NULL);
-               if (pdev) {
-                       err = cs5535_gpio_probe(pdev, &cs5535_gpio_pci_tbl[i]);
-                       if (err)
-                               pci_dev_put(pdev);
-
-                       /* we only support a single CS5535/6 southbridge */
-                       break;
-               }
-       }
-
-       return err;
+       r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       release_region(r->start, resource_size(r));
+       return 0;
 }
 
-static void __exit cs5535_gpio_free_pci(void)
-{
-       cs5535_gpio_remove(cs5535_gpio_chip.pdev);
-       pci_dev_put(cs5535_gpio_chip.pdev);
-}
+static struct platform_driver cs5535_gpio_drv = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = cs5535_gpio_probe,
+       .remove = __devexit_p(cs5535_gpio_remove),
+};
 
 static int __init cs5535_gpio_init(void)
 {
-       return cs5535_gpio_scan_pci();
+       return platform_driver_register(&cs5535_gpio_drv);
 }
 
 static void __exit cs5535_gpio_exit(void)
 {
-       cs5535_gpio_free_pci();
+       platform_driver_unregister(&cs5535_gpio_drv);
 }
 
 module_init(cs5535_gpio_init);
@@ -430,3 +398,4 @@ module_exit(cs5535_gpio_exit);
 MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
 MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index 349131eb1ce00dbca70a39082f18ae88c537648d..58c8f30352dddbd4eda7b3cd2ac45455b51d92a4 100644 (file)
@@ -193,13 +193,13 @@ out:
        return ret;
 }
 
-static void timbgpio_irq(struct irq_data *d, struct irq_desc *desc)
+static void timbgpio_irq(unsigned int irq, struct irq_desc *desc)
 {
-       struct timbgpio *tgpio = irq_data_get_irq_data(d);
+       struct timbgpio *tgpio = get_irq_data(irq);
        unsigned long ipr;
        int offset;
 
-       desc->irq_data.chip->ack(irq_get_irq_data(d));
+       desc->irq_data.chip->irq_ack(irq_get_irq_data(irq));
        ipr = ioread32(tgpio->membase + TGPIO_IPR);
        iowrite32(ipr, tgpio->membase + TGPIO_ICR);
 
index 0307d601f5e5018db2cc545a4cb7db3d49743903..5c4f9b9ecdc0759d590b691dd75587a0efd25970 100644 (file)
@@ -607,25 +607,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 }
 EXPORT_SYMBOL(drm_fb_helper_fini);
 
-void drm_fb_helper_fill_fix(struct fb_info *info, struct drm_framebuffer *fb)
-{
-       info->fix.type = FB_TYPE_PACKED_PIXELS;
-       info->fix.visual = fb->depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
-               FB_VISUAL_TRUECOLOR;
-       info->fix.mmio_start = 0;
-       info->fix.mmio_len = 0;
-       info->fix.type_aux = 0;
-       info->fix.xpanstep = 1; /* doing it in hw */
-       info->fix.ypanstep = 1; /* doing it in hw */
-       info->fix.ywrapstep = 0;
-       info->fix.accel = FB_ACCEL_NONE;
-       info->fix.type_aux = 0;
-
-       info->fix.line_length = fb->pitch;
-       return;
-}
-EXPORT_SYMBOL(drm_fb_helper_fill_fix);
-
 static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
                     u16 blue, u16 regno, struct fb_info *info)
 {
@@ -835,7 +816,6 @@ int drm_fb_helper_set_par(struct fb_info *info)
                        mutex_unlock(&dev->mode_config.mutex);
                        return ret;
                }
-               drm_fb_helper_fill_fix(info, fb_helper->fb);
        }
        mutex_unlock(&dev->mode_config.mutex);
 
@@ -973,7 +953,6 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 
        if (new_fb) {
                info->var.pixclock = 0;
-               drm_fb_helper_fill_fix(info, fb_helper->fb);
                if (register_framebuffer(info) < 0) {
                        return -EINVAL;
                }
@@ -1000,6 +979,26 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 }
 EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
 
+void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
+                           uint32_t depth)
+{
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
+               FB_VISUAL_TRUECOLOR;
+       info->fix.mmio_start = 0;
+       info->fix.mmio_len = 0;
+       info->fix.type_aux = 0;
+       info->fix.xpanstep = 1; /* doing it in hw */
+       info->fix.ypanstep = 1; /* doing it in hw */
+       info->fix.ywrapstep = 0;
+       info->fix.accel = FB_ACCEL_NONE;
+       info->fix.type_aux = 0;
+
+       info->fix.line_length = pitch;
+       return;
+}
+EXPORT_SYMBOL(drm_fb_helper_fill_fix);
+
 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
                            uint32_t fb_width, uint32_t fb_height)
 {
index 19a3d58044dd7667c5498cf373cc68f9629cd0f2..3601466c55027391c355fe1c11186913394fbf2d 100644 (file)
@@ -703,7 +703,7 @@ static void print_error_buffers(struct seq_file *m,
        seq_printf(m, "%s [%d]:\n", name, count);
 
        while (count--) {
-               seq_printf(m, "  %08x %8zd %04x %04x %08x%s%s%s%s%s%s",
+               seq_printf(m, "  %08x %8u %04x %04x %08x%s%s%s%s%s%s",
                           err->gtt_offset,
                           err->size,
                           err->read_domains,
index 0de75a23f8e7d4ee147266d8f38f2e618281a8e6..72fea2bcfc4f77241a7b1087e558637841279afb 100644 (file)
@@ -49,6 +49,9 @@ module_param_named(powersave, i915_powersave, int, 0600);
 unsigned int i915_lvds_downclock = 0;
 module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
 
+unsigned int i915_panel_use_ssc = 1;
+module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
+
 bool i915_try_reset = true;
 module_param_named(reset, i915_try_reset, bool, 0600);
 
index 385fc7ec39d3c987f3b4cc4c420922382da0ca69..5969f46ac2d6023740204c74e62d25265cfc736f 100644 (file)
@@ -954,6 +954,7 @@ extern int i915_max_ioctl;
 extern unsigned int i915_fbpercrtc;
 extern unsigned int i915_powersave;
 extern unsigned int i915_lvds_downclock;
+extern unsigned int i915_panel_use_ssc;
 
 extern int i915_suspend(struct drm_device *dev, pm_message_t state);
 extern int i915_resume(struct drm_device *dev);
index e69834341ef068b4ebbbb500fc4484d64826a879..dcfdf4151b6dedddec0f45ba21f2c81156e1fe27 100644 (file)
@@ -464,8 +464,6 @@ i915_gem_execbuffer_relocate(struct drm_device *dev,
        int ret;
 
        list_for_each_entry(obj, objects, exec_list) {
-               obj->base.pending_read_domains = 0;
-               obj->base.pending_write_domain = 0;
                ret = i915_gem_execbuffer_relocate_object(obj, eb);
                if (ret)
                        return ret;
@@ -505,6 +503,9 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
                        list_move(&obj->exec_list, &ordered_objects);
                else
                        list_move_tail(&obj->exec_list, &ordered_objects);
+
+               obj->base.pending_read_domains = 0;
+               obj->base.pending_write_domain = 0;
        }
        list_splice(&ordered_objects, objects);
 
@@ -636,6 +637,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
 {
        struct drm_i915_gem_relocation_entry *reloc;
        struct drm_i915_gem_object *obj;
+       int *reloc_offset;
        int i, total, ret;
 
        /* We may process another execbuffer during the unlock... */
@@ -653,8 +655,11 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
        for (i = 0; i < count; i++)
                total += exec[i].relocation_count;
 
+       reloc_offset = drm_malloc_ab(count, sizeof(*reloc_offset));
        reloc = drm_malloc_ab(total, sizeof(*reloc));
-       if (reloc == NULL) {
+       if (reloc == NULL || reloc_offset == NULL) {
+               drm_free_large(reloc);
+               drm_free_large(reloc_offset);
                mutex_lock(&dev->struct_mutex);
                return -ENOMEM;
        }
@@ -672,6 +677,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
                        goto err;
                }
 
+               reloc_offset[i] = total;
                total += exec[i].relocation_count;
        }
 
@@ -705,17 +711,12 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
        if (ret)
                goto err;
 
-       total = 0;
        list_for_each_entry(obj, objects, exec_list) {
-               obj->base.pending_read_domains = 0;
-               obj->base.pending_write_domain = 0;
+               int offset = obj->exec_entry - exec;
                ret = i915_gem_execbuffer_relocate_object_slow(obj, eb,
-                                                              reloc + total);
+                                                              reloc + reloc_offset[offset]);
                if (ret)
                        goto err;
-
-               total += exec->relocation_count;
-               exec++;
        }
 
        /* Leave the user relocations as are, this is the painfully slow path,
@@ -726,6 +727,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
 
 err:
        drm_free_large(reloc);
+       drm_free_large(reloc_offset);
        return ret;
 }
 
@@ -770,7 +772,8 @@ i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj,
        if (from == NULL || to == from)
                return 0;
 
-       if (INTEL_INFO(obj->base.dev)->gen < 6)
+       /* XXX gpu semaphores are currently causing hard hangs on SNB mobile */
+       if (INTEL_INFO(obj->base.dev)->gen < 6 || IS_MOBILE(obj->base.dev))
                return i915_gem_object_wait_rendering(obj, true);
 
        idx = intel_ring_sync_index(from, to);
index e418e8bb61e66f4de9baadaafa23c3a286cb00f4..b8e509ae065e41c0e5580b48454609dfc3314b55 100644 (file)
@@ -720,7 +720,7 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
                if (obj->ring != ring)
                        continue;
 
-               if (!i915_seqno_passed(obj->last_rendering_seqno, seqno))
+               if (i915_seqno_passed(seqno, obj->last_rendering_seqno))
                        continue;
 
                if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0)
index b0b1200ed6500055b05bc1e51a932df26b6600ef..0b44956c336bf61388c256381140c478ed7105c2 100644 (file)
@@ -264,17 +264,12 @@ parse_general_features(struct drm_i915_private *dev_priv,
                dev_priv->int_crt_support = general->int_crt_support;
                dev_priv->lvds_use_ssc = general->enable_ssc;
 
-               if (dev_priv->lvds_use_ssc) {
-                       if (IS_I85X(dev))
-                               dev_priv->lvds_ssc_freq =
-                                       general->ssc_freq ? 66 : 48;
-                       else if (IS_GEN5(dev) || IS_GEN6(dev))
-                               dev_priv->lvds_ssc_freq =
-                                       general->ssc_freq ? 100 : 120;
-                       else
-                               dev_priv->lvds_ssc_freq =
-                                       general->ssc_freq ? 100 : 96;
-               }
+               if (IS_I85X(dev))
+                       dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48;
+               else if (IS_GEN5(dev) || IS_GEN6(dev))
+                       dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 120;
+               else
+                       dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96;
        }
 }
 
index 25d96889d7d245a60a4d9ef15d9279032f73b6fd..98967f3b7724e1554713fa665e62b67f6abbddcd 100644 (file)
@@ -3822,6 +3822,11 @@ static void intel_update_watermarks(struct drm_device *dev)
                                    sr_hdisplay, sr_htotal, pixel_size);
 }
 
+static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
+{
+       return dev_priv->lvds_use_ssc && i915_panel_use_ssc;
+}
+
 static int intel_crtc_mode_set(struct drm_crtc *crtc,
                               struct drm_display_mode *mode,
                               struct drm_display_mode *adjusted_mode,
@@ -3884,7 +3889,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                num_connectors++;
        }
 
-       if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) {
+       if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
                refclk = dev_priv->lvds_ssc_freq * 1000;
                DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
                              refclk / 1000);
@@ -4059,7 +4064,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                udelay(200);
 
                if (has_edp_encoder) {
-                       if (dev_priv->lvds_use_ssc) {
+                       if (intel_panel_use_ssc(dev_priv)) {
                                temp |= DREF_SSC1_ENABLE;
                                I915_WRITE(PCH_DREF_CONTROL, temp);
 
@@ -4070,13 +4075,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
                        /* Enable CPU source on CPU attached eDP */
                        if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-                               if (dev_priv->lvds_use_ssc)
+                               if (intel_panel_use_ssc(dev_priv))
                                        temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
                                else
                                        temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
                        } else {
                                /* Enable SSC on PCH eDP if needed */
-                               if (dev_priv->lvds_use_ssc) {
+                               if (intel_panel_use_ssc(dev_priv)) {
                                        DRM_ERROR("enabling SSC on PCH\n");
                                        temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
                                }
@@ -4104,7 +4109,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                int factor = 21;
 
                if (is_lvds) {
-                       if ((dev_priv->lvds_use_ssc &&
+                       if ((intel_panel_use_ssc(dev_priv) &&
                             dev_priv->lvds_ssc_freq == 100) ||
                            (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
                                factor = 25;
@@ -4183,7 +4188,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                /* XXX: just matching BIOS for now */
                /*      dpll |= PLL_REF_INPUT_TVCLKINBC; */
                dpll |= 3;
-       else if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2)
+       else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
        else
                dpll |= PLL_REF_INPUT_DREFCLK;
index ee145a25728798c28b6426a2f953763b3cab6347..512782728e5127aed5ea383efb7f4d79dd2b8cb7 100644 (file)
@@ -148,6 +148,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
 
 //     memset(info->screen_base, 0, size);
 
+       drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
        drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
 
        info->pixmap.size = 64*1024;
index 8f4f6bd33ee9ec99684eeafd7d6a778f50df9bff..ace8d5d30dd21b25b3f0390cdd2b8d13659f666e 100644 (file)
@@ -702,6 +702,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "i915GMx-F"),
                },
        },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "AOpen i915GMm-HFS",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+                       DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+               },
+       },
        {
                .callback = intel_no_lvds_dmi_callback,
                .ident = "Aopen i945GTt-VFA",
index e00d200df3db1fe2b4dd7c2f2c8789003e58fc86..c65992df458d6a905c1bab7dcb38f38d9dfeab49 100644 (file)
@@ -278,6 +278,6 @@ void intel_panel_setup_backlight(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
+       dev_priv->backlight_level = intel_panel_get_backlight(dev);
        dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
 }
index a26d04740c88b44936e909a8f83d20befdbf4513..6d56a54b6e2ed0ee12d38dec2f38f916894cd89c 100644 (file)
@@ -359,6 +359,7 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
        info->screen_base = nvbo_kmap_obj_iovirtual(nouveau_fb->nvbo);
        info->screen_size = size;
 
+       drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
        drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height);
 
        /* Set aperture base/size for vesafb takeover */
index ca32e9c1e91db3b6714de8e3a7df91640e944f98..66324b5bb5ba0f038f393f1a4464514c41159ca9 100644 (file)
@@ -225,6 +225,8 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev,
 
        strcpy(info->fix.id, "radeondrmfb");
 
+       drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
+
        info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
        info->fbops = &radeonfb_ops;
 
index 53fab518b3dac3fbf6dba85048163bf35d133e36..986e5f62debe95c2d5ba0fa8886be20fa250e176 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/pci.h>
+#include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
@@ -40,6 +41,7 @@
 
 MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
 MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_ALIAS("platform:cs5535-smb");
 MODULE_LICENSE("GPL");
 
 #define MAX_DEVICES 4
@@ -84,10 +86,6 @@ struct scx200_acb_iface {
        u8 *ptr;
        char needs_reset;
        unsigned len;
-
-       /* PCI device info */
-       struct pci_dev *pdev;
-       int bar;
 };
 
 /* Register Definitions */
@@ -391,7 +389,7 @@ static const struct i2c_algorithm scx200_acb_algorithm = {
 static struct scx200_acb_iface *scx200_acb_list;
 static DEFINE_MUTEX(scx200_acb_list_mutex);
 
-static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
+static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface)
 {
        u8 val;
 
@@ -427,7 +425,7 @@ static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
        return 0;
 }
 
-static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
+static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text,
                struct device *dev, int index)
 {
        struct scx200_acb_iface *iface;
@@ -452,7 +450,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
        return iface;
 }
 
-static int __init scx200_acb_create(struct scx200_acb_iface *iface)
+static int __devinit scx200_acb_create(struct scx200_acb_iface *iface)
 {
        struct i2c_adapter *adapter;
        int rc;
@@ -472,183 +470,145 @@ static int __init scx200_acb_create(struct scx200_acb_iface *iface)
                return -ENODEV;
        }
 
-       mutex_lock(&scx200_acb_list_mutex);
-       iface->next = scx200_acb_list;
-       scx200_acb_list = iface;
-       mutex_unlock(&scx200_acb_list_mutex);
+       if (!adapter->dev.parent) {
+               /* If there's no dev, we're tracking (ISA) ifaces manually */
+               mutex_lock(&scx200_acb_list_mutex);
+               iface->next = scx200_acb_list;
+               scx200_acb_list = iface;
+               mutex_unlock(&scx200_acb_list_mutex);
+       }
 
        return 0;
 }
 
-static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
-               int bar)
+static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text,
+               unsigned long base, int index, struct device *dev)
 {
        struct scx200_acb_iface *iface;
        int rc;
 
-       iface = scx200_create_iface(text, &pdev->dev, 0);
+       iface = scx200_create_iface(text, dev, index);
 
        if (iface == NULL)
-               return -ENOMEM;
-
-       iface->pdev = pdev;
-       iface->bar = bar;
-
-       rc = pci_enable_device_io(iface->pdev);
-       if (rc)
-               goto errout_free;
+               return NULL;
 
-       rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name);
-       if (rc) {
-               printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n",
-                               iface->bar);
+       if (!request_region(base, 8, iface->adapter.name)) {
+               printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
+                      base, base + 8 - 1);
                goto errout_free;
        }
 
-       iface->base = pci_resource_start(iface->pdev, iface->bar);
+       iface->base = base;
        rc = scx200_acb_create(iface);
 
        if (rc == 0)
-               return 0;
+               return iface;
 
-       pci_release_region(iface->pdev, iface->bar);
-       pci_dev_put(iface->pdev);
+       release_region(base, 8);
  errout_free:
        kfree(iface);
-       return rc;
+       return NULL;
 }
 
-static int __init scx200_create_isa(const char *text, unsigned long base,
-               int index)
+static int __devinit scx200_probe(struct platform_device *pdev)
 {
        struct scx200_acb_iface *iface;
-       int rc;
-
-       iface = scx200_create_iface(text, NULL, index);
-
-       if (iface == NULL)
-               return -ENOMEM;
+       struct resource *res;
 
-       if (!request_region(base, 8, iface->adapter.name)) {
-               printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
-                      base, base + 8 - 1);
-               rc = -EBUSY;
-               goto errout_free;
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "can't fetch device resource info\n");
+               return -ENODEV;
        }
 
-       iface->base = base;
-       rc = scx200_acb_create(iface);
+       iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev);
+       if (!iface)
+               return -EIO;
 
-       if (rc == 0)
-               return 0;
+       dev_info(&pdev->dev, "SCx200 device '%s' registered\n",
+                       iface->adapter.name);
+       platform_set_drvdata(pdev, iface);
 
-       release_region(base, 8);
- errout_free:
-       kfree(iface);
-       return rc;
+       return 0;
 }
 
-/* Driver data is an index into the scx200_data array that indicates
- * the name and the BAR where the I/O address resource is located.  ISA
- * devices are flagged with a bar value of -1 */
-
-static const struct pci_device_id scx200_pci[] __initconst = {
-       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE),
-         .driver_data = 0 },
-       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE),
-         .driver_data = 0 },
-       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),
-         .driver_data = 1 },
-       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA),
-         .driver_data = 2 },
-       { 0, }
-};
-
-static struct {
-       const char *name;
-       int bar;
-} scx200_data[] = {
-       { "SCx200", -1 },
-       { "CS5535",  0 },
-       { "CS5536",  0 }
-};
+static void __devexit scx200_cleanup_iface(struct scx200_acb_iface *iface)
+{
+       i2c_del_adapter(&iface->adapter);
+       release_region(iface->base, 8);
+       kfree(iface);
+}
 
-static __init int scx200_scan_pci(void)
+static int __devexit scx200_remove(struct platform_device *pdev)
 {
-       int data, dev;
-       int rc = -ENODEV;
-       struct pci_dev *pdev;
+       struct scx200_acb_iface *iface;
 
-       for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) {
-               pdev = pci_get_device(scx200_pci[dev].vendor,
-                               scx200_pci[dev].device, NULL);
+       iface = platform_get_drvdata(pdev);
+       platform_set_drvdata(pdev, NULL);
+       scx200_cleanup_iface(iface);
 
-               if (pdev == NULL)
-                       continue;
+       return 0;
+}
 
-               data = scx200_pci[dev].driver_data;
+static struct platform_driver scx200_pci_drv = {
+       .driver = {
+               .name = "cs5535-smb",
+               .owner = THIS_MODULE,
+       },
+       .probe = scx200_probe,
+       .remove = __devexit_p(scx200_remove),
+};
 
-               /* if .bar is greater or equal to zero, this is a
-                * PCI device - otherwise, we assume
-                  that the ports are ISA based
-               */
+static const struct pci_device_id scx200_isa[] __initconst = {
+       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
+       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
+       { 0, }
+};
 
-               if (scx200_data[data].bar >= 0)
-                       rc = scx200_create_pci(scx200_data[data].name, pdev,
-                                       scx200_data[data].bar);
-               else {
-                       int i;
+static __init void scx200_scan_isa(void)
+{
+       int i;
 
-                       pci_dev_put(pdev);
-                       for (i = 0; i < MAX_DEVICES; ++i) {
-                               if (base[i] == 0)
-                                       continue;
+       if (!pci_dev_present(scx200_isa))
+               return;
 
-                               rc = scx200_create_isa(scx200_data[data].name,
-                                               base[i],
-                                               i);
-                       }
-               }
+       for (i = 0; i < MAX_DEVICES; ++i) {
+               if (base[i] == 0)
+                       continue;
 
-               break;
+               /* XXX: should we care about failures? */
+               scx200_create_dev("SCx200", base[i], i, NULL);
        }
-
-       return rc;
 }
 
 static int __init scx200_acb_init(void)
 {
-       int rc;
-
        pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
 
-       rc = scx200_scan_pci();
+       /* First scan for ISA-based devices */
+       scx200_scan_isa();      /* XXX: should we care about errors? */
 
        /* If at least one bus was created, init must succeed */
        if (scx200_acb_list)
                return 0;
-       return rc;
+
+       /* No ISA devices; register the platform driver for PCI-based devices */
+       return platform_driver_register(&scx200_pci_drv);
 }
 
 static void __exit scx200_acb_cleanup(void)
 {
        struct scx200_acb_iface *iface;
 
+       platform_driver_unregister(&scx200_pci_drv);
+
        mutex_lock(&scx200_acb_list_mutex);
        while ((iface = scx200_acb_list) != NULL) {
                scx200_acb_list = iface->next;
                mutex_unlock(&scx200_acb_list_mutex);
 
-               i2c_del_adapter(&iface->adapter);
-
-               if (iface->pdev) {
-                       pci_release_region(iface->pdev, iface->bar);
-                       pci_dev_put(iface->pdev);
-               }
-               else
-                       release_region(iface->base, 8);
+               scx200_cleanup_iface(iface);
 
-               kfree(iface);
                mutex_lock(&scx200_acb_list_mutex);
        }
        mutex_unlock(&scx200_acb_list_mutex);
index c7db6980e3a3cd91ad035a6dd8ff25087e6c07d1..f0bd5bcdf56329294b5cab85a0fe41ce06600dd6 100644 (file)
@@ -196,88 +196,60 @@ static int i2c_device_pm_suspend(struct device *dev)
 {
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
-       if (pm) {
-               if (pm_runtime_suspended(dev))
-                       return 0;
-               else
-                       return pm->suspend ? pm->suspend(dev) : 0;
-       }
-
-       return i2c_legacy_suspend(dev, PMSG_SUSPEND);
+       if (pm)
+               return pm_generic_suspend(dev);
+       else
+               return i2c_legacy_suspend(dev, PMSG_SUSPEND);
 }
 
 static int i2c_device_pm_resume(struct device *dev)
 {
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-       int ret;
 
        if (pm)
-               ret = pm->resume ? pm->resume(dev) : 0;
+               return pm_generic_resume(dev);
        else
-               ret = i2c_legacy_resume(dev);
-
-       return ret;
+               return i2c_legacy_resume(dev);
 }
 
 static int i2c_device_pm_freeze(struct device *dev)
 {
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
-       if (pm) {
-               if (pm_runtime_suspended(dev))
-                       return 0;
-               else
-                       return pm->freeze ? pm->freeze(dev) : 0;
-       }
-
-       return i2c_legacy_suspend(dev, PMSG_FREEZE);
+       if (pm)
+               return pm_generic_freeze(dev);
+       else
+               return i2c_legacy_suspend(dev, PMSG_FREEZE);
 }
 
 static int i2c_device_pm_thaw(struct device *dev)
 {
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
-       if (pm) {
-               if (pm_runtime_suspended(dev))
-                       return 0;
-               else
-                       return pm->thaw ? pm->thaw(dev) : 0;
-       }
-
-       return i2c_legacy_resume(dev);
+       if (pm)
+               return pm_generic_thaw(dev);
+       else
+               return i2c_legacy_resume(dev);
 }
 
 static int i2c_device_pm_poweroff(struct device *dev)
 {
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
-       if (pm) {
-               if (pm_runtime_suspended(dev))
-                       return 0;
-               else
-                       return pm->poweroff ? pm->poweroff(dev) : 0;
-       }
-
-       return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
+       if (pm)
+               return pm_generic_poweroff(dev);
+       else
+               return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
 }
 
 static int i2c_device_pm_restore(struct device *dev)
 {
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-       int ret;
 
        if (pm)
-               ret = pm->restore ? pm->restore(dev) : 0;
+               return pm_generic_restore(dev);
        else
-               ret = i2c_legacy_resume(dev);
-
-       if (!ret) {
-               pm_runtime_disable(dev);
-               pm_runtime_set_active(dev);
-               pm_runtime_enable(dev);
-       }
-
-       return ret;
+               return i2c_legacy_resume(dev);
 }
 #else /* !CONFIG_PM_SLEEP */
 #define i2c_device_pm_suspend  NULL
@@ -1019,6 +991,14 @@ static int i2c_do_del_adapter(struct i2c_driver *driver,
 }
 
 static int __unregister_client(struct device *dev, void *dummy)
+{
+       struct i2c_client *client = i2c_verify_client(dev);
+       if (client && strcmp(client->name, "dummy"))
+               i2c_unregister_device(client);
+       return 0;
+}
+
+static int __unregister_dummy(struct device *dev, void *dummy)
 {
        struct i2c_client *client = i2c_verify_client(dev);
        if (client)
@@ -1075,8 +1055,12 @@ int i2c_del_adapter(struct i2c_adapter *adap)
        mutex_unlock(&adap->userspace_clients_lock);
 
        /* Detach any active clients. This can't fail, thus we do not
-          checking the returned value. */
+        * check the returned value. This is a two-pass process, because
+        * we can't remove the dummy devices during the first pass: they
+        * could have been instantiated by real devices wishing to clean
+        * them up properly, so we give them a chance to do that first. */
        res = device_for_each_child(&adap->dev, NULL, __unregister_client);
+       res = device_for_each_child(&adap->dev, NULL, __unregister_dummy);
 
 #ifdef CONFIG_I2C_COMPAT
        class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,
@@ -1140,6 +1124,14 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
        if (res)
                return res;
 
+       /* Drivers should switch to dev_pm_ops instead. */
+       if (driver->suspend)
+               pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
+                       driver->driver.name);
+       if (driver->resume)
+               pr_warn("i2c-core: driver [%s] using legacy resume method\n",
+                       driver->driver.name);
+
        pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
 
        INIT_LIST_HEAD(&driver->clients);
index dffa0ac7c4f0e135ec410bcc0e30dff9a443a78d..38e4eb1bb9656ba565150a48d68594836f51c4f9 100644 (file)
@@ -350,6 +350,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
        if (!d->dm_dev.bdev)
                return;
 
+       bd_unlink_disk_holder(d->dm_dev.bdev, dm_disk(md));
        blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL);
        d->dm_dev.bdev = NULL;
 }
index cf8594c5ea21a481577705b17b95da1186bfb044..b76cfc89e1b57ce5557d7d4d931132c6f4efcc82 100644 (file)
@@ -1912,6 +1912,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
                MD_BUG();
                return;
        }
+       bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
        list_del_rcu(&rdev->same_set);
        printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
        rdev->mddev = NULL;
index 789087cd6a9ca318570fd89485ab6621d71bde42..49f1b8f1418e94ae36e6b80219581056246da045 100644 (file)
@@ -2184,9 +2184,7 @@ static int cafe_pci_resume(struct pci_dev *pdev)
        struct cafe_camera *cam = to_cam(v4l2_dev);
        int ret = 0;
 
-       ret = pci_restore_state(pdev);
-       if (ret)
-               return ret;
+       pci_restore_state(pdev);
        ret = pci_enable_device(pdev);
 
        if (ret) {
index 20895e7a99c963538d05d89b43a2bdcb7d8b61ec..793300c554b4210eb44011b5a991119c4155b589 100644 (file)
@@ -361,12 +361,6 @@ static struct pm860x_irq_data pm860x_irqs[] = {
        },
 };
 
-static inline struct pm860x_irq_data *irq_to_pm860x(struct pm860x_chip *chip,
-                                                   int irq)
-{
-       return &pm860x_irqs[irq - chip->irq_base];
-}
-
 static irqreturn_t pm860x_irq(int irq, void *data)
 {
        struct pm860x_chip *chip = data;
@@ -388,16 +382,16 @@ static irqreturn_t pm860x_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static void pm860x_irq_lock(unsigned int irq)
+static void pm860x_irq_lock(struct irq_data *data)
 {
-       struct pm860x_chip *chip = get_irq_chip_data(irq);
+       struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
 
        mutex_lock(&chip->irq_lock);
 }
 
-static void pm860x_irq_sync_unlock(unsigned int irq)
+static void pm860x_irq_sync_unlock(struct irq_data *data)
 {
-       struct pm860x_chip *chip = get_irq_chip_data(irq);
+       struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
        struct pm860x_irq_data *irq_data;
        struct i2c_client *i2c;
        static unsigned char cached[3] = {0x0, 0x0, 0x0};
@@ -439,25 +433,25 @@ static void pm860x_irq_sync_unlock(unsigned int irq)
        mutex_unlock(&chip->irq_lock);
 }
 
-static void pm860x_irq_enable(unsigned int irq)
+static void pm860x_irq_enable(struct irq_data *data)
 {
-       struct pm860x_chip *chip = get_irq_chip_data(irq);
-       pm860x_irqs[irq - chip->irq_base].enable
-               = pm860x_irqs[irq - chip->irq_base].offs;
+       struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
+       pm860x_irqs[data->irq - chip->irq_base].enable
+               = pm860x_irqs[data->irq - chip->irq_base].offs;
 }
 
-static void pm860x_irq_disable(unsigned int irq)
+static void pm860x_irq_disable(struct irq_data *data)
 {
-       struct pm860x_chip *chip = get_irq_chip_data(irq);
-       pm860x_irqs[irq - chip->irq_base].enable = 0;
+       struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
+       pm860x_irqs[data->irq - chip->irq_base].enable = 0;
 }
 
 static struct irq_chip pm860x_irq_chip = {
        .name           = "88pm860x",
-       .bus_lock       = pm860x_irq_lock,
-       .bus_sync_unlock = pm860x_irq_sync_unlock,
-       .enable         = pm860x_irq_enable,
-       .disable        = pm860x_irq_disable,
+       .irq_bus_lock   = pm860x_irq_lock,
+       .irq_bus_sync_unlock = pm860x_irq_sync_unlock,
+       .irq_enable     = pm860x_irq_enable,
+       .irq_disable    = pm860x_irq_disable,
 };
 
 static int __devinit device_gpadc_init(struct pm860x_chip *chip,
index da9d2971102e572fe1abff9e8037e5594d747c47..fd018366d6701528916ab36d0eb3a92dbc047037 100644 (file)
@@ -496,13 +496,13 @@ config EZX_PCAP
 
 config AB8500_CORE
        bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
-       depends on GENERIC_HARDIRQS && ABX500_CORE && SPI_MASTER && ARCH_U8500
+       depends on GENERIC_HARDIRQS && ABX500_CORE
        select MFD_CORE
        help
          Select this option to enable access to AB8500 power management
-         chip. This connects to U8500 either on the SSP/SPI bus
-         or the I2C bus via PRCMU. It also adds the irq_chip
-         parts for handling the Mixed Signal chip events.
+         chip. This connects to U8500 either on the SSP/SPI bus (deprecated
+         since hardware version v1.0) or the I2C bus via PRCMU. It also adds
+         the irq_chip parts for handling the Mixed Signal chip events.
          This chip embeds various other multimedia funtionalities as well.
 
 config AB8500_I2C_CORE
@@ -537,6 +537,14 @@ config AB3550_CORE
          LEDs, vibrator, system power and temperature, power management
          and ALSA sound.
 
+config MFD_CS5535
+       tristate "Support for CS5535 and CS5536 southbridge core functions"
+       select MFD_CORE
+       depends on PCI
+       ---help---
+         This is the core driver for CS5535/CS5536 MFD functions.  This is
+          necessary for using the board's GPIO and MFGPT functionality.
+
 config MFD_TIMBERDALE
        tristate "Support for the Timberdale FPGA"
        select MFD_CORE
index 848e7eac75aa70756a7cf762e151ef0430b1b0e6..a54e2c7c6a1c566b6e46b70595a48f26d60199b4 100644 (file)
@@ -70,7 +70,7 @@ obj-$(CONFIG_ABX500_CORE)     += abx500-core.o
 obj-$(CONFIG_AB3100_CORE)      += ab3100-core.o
 obj-$(CONFIG_AB3100_OTP)       += ab3100-otp.o
 obj-$(CONFIG_AB3550_CORE)      += ab3550-core.o
-obj-$(CONFIG_AB8500_CORE)      += ab8500-core.o ab8500-spi.o
+obj-$(CONFIG_AB8500_CORE)      += ab8500-core.o
 obj-$(CONFIG_AB8500_I2C_CORE)  += ab8500-i2c.o
 obj-$(CONFIG_AB8500_DEBUG)     += ab8500-debugfs.o
 obj-$(CONFIG_MFD_TIMBERDALE)    += timberdale.o
@@ -82,3 +82,4 @@ obj-$(CONFIG_MFD_JZ4740_ADC)  += jz4740-adc.o
 obj-$(CONFIG_MFD_TPS6586X)     += tps6586x.o
 obj-$(CONFIG_MFD_VX855)                += vx855.o
 obj-$(CONFIG_MFD_WL1273_CORE)  += wl1273-core.o
+obj-$(CONFIG_MFD_CS5535)       += cs5535-mfd.o
index 8a98739e6d9c0e75e658459636e954f2056f1e3f..5fbca346b998d4a5316790306bc60c32fb8eb623 100644 (file)
@@ -1159,15 +1159,16 @@ static void ab3550_mask_work(struct work_struct *work)
        }
 }
 
-static void ab3550_mask(unsigned int irq)
+static void ab3550_mask(struct irq_data *data)
 {
        unsigned long flags;
        struct ab3550 *ab;
        struct ab3550_platform_data *plf_data;
+       int irq;
 
-       ab = get_irq_chip_data(irq);
+       ab = irq_data_get_irq_chip_data(data);
        plf_data = ab->i2c_client[0]->dev.platform_data;
-       irq -= plf_data->irq.base;
+       irq = data->irq - plf_data->irq.base;
 
        spin_lock_irqsave(&ab->event_lock, flags);
        ab->event_mask[irq / 8] |= BIT(irq % 8);
@@ -1176,15 +1177,16 @@ static void ab3550_mask(unsigned int irq)
        schedule_work(&ab->mask_work);
 }
 
-static void ab3550_unmask(unsigned int irq)
+static void ab3550_unmask(struct irq_data *data)
 {
        unsigned long flags;
        struct ab3550 *ab;
        struct ab3550_platform_data *plf_data;
+       int irq;
 
-       ab = get_irq_chip_data(irq);
+       ab = irq_data_get_irq_chip_data(data);
        plf_data = ab->i2c_client[0]->dev.platform_data;
-       irq -= plf_data->irq.base;
+       irq = data->irq - plf_data->irq.base;
 
        spin_lock_irqsave(&ab->event_lock, flags);
        ab->event_mask[irq / 8] &= ~BIT(irq % 8);
@@ -1193,20 +1195,16 @@ static void ab3550_unmask(unsigned int irq)
        schedule_work(&ab->mask_work);
 }
 
-static void noop(unsigned int irq)
+static void noop(struct irq_data *data)
 {
 }
 
 static struct irq_chip ab3550_irq_chip = {
        .name           = "ab3550-core", /* Keep the same name as the request */
-       .startup        = NULL, /* defaults to enable */
-       .shutdown       = NULL, /* defaults to disable */
-       .enable         = NULL, /* defaults to unmask */
-       .disable        = ab3550_mask, /* No default to mask in chip.c */
-       .ack            = noop,
-       .mask           = ab3550_mask,
-       .unmask         = ab3550_unmask,
-       .end            = NULL,
+       .irq_disable    = ab3550_mask, /* No default to mask in chip.c */
+       .irq_ack        = noop,
+       .irq_mask       = ab3550_mask,
+       .irq_unmask     = ab3550_unmask,
 };
 
 struct ab_family_id {
index d9640a623ff483446822e4370127c376d3c631c5..b6887014d687bbe03c608f029fa5d4f2634b93ad 100644 (file)
@@ -52,6 +52,7 @@
 #define AB8500_IT_LATCH8_REG           0x27
 #define AB8500_IT_LATCH9_REG           0x28
 #define AB8500_IT_LATCH10_REG          0x29
+#define AB8500_IT_LATCH12_REG          0x2B
 #define AB8500_IT_LATCH19_REG          0x32
 #define AB8500_IT_LATCH20_REG          0x33
 #define AB8500_IT_LATCH21_REG          0x34
  * offset 0.
  */
 static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
-       0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21,
+       0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
 };
 
 static int ab8500_get_chip_id(struct device *dev)
 {
-       struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
-       return (int)ab8500->chip_id;
+       struct ab8500 *ab8500;
+
+       if (!dev)
+               return -EINVAL;
+       ab8500 = dev_get_drvdata(dev->parent);
+       return ab8500 ? (int)ab8500->chip_id : -EINVAL;
 }
 
 static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
@@ -228,16 +233,16 @@ static struct abx500_ops ab8500_ops = {
        .startup_irq_enabled = NULL,
 };
 
-static void ab8500_irq_lock(unsigned int irq)
+static void ab8500_irq_lock(struct irq_data *data)
 {
-       struct ab8500 *ab8500 = get_irq_chip_data(irq);
+       struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
 
        mutex_lock(&ab8500->irq_lock);
 }
 
-static void ab8500_irq_sync_unlock(unsigned int irq)
+static void ab8500_irq_sync_unlock(struct irq_data *data)
 {
-       struct ab8500 *ab8500 = get_irq_chip_data(irq);
+       struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
        int i;
 
        for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
@@ -248,6 +253,10 @@ static void ab8500_irq_sync_unlock(unsigned int irq)
                if (new == old)
                        continue;
 
+               /* Interrupt register 12 does'nt exist prior to version 0x20 */
+               if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+                       continue;
+
                ab8500->oldmask[i] = new;
 
                reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
@@ -257,20 +266,20 @@ static void ab8500_irq_sync_unlock(unsigned int irq)
        mutex_unlock(&ab8500->irq_lock);
 }
 
-static void ab8500_irq_mask(unsigned int irq)
+static void ab8500_irq_mask(struct irq_data *data)
 {
-       struct ab8500 *ab8500 = get_irq_chip_data(irq);
-       int offset = irq - ab8500->irq_base;
+       struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
+       int offset = data->irq - ab8500->irq_base;
        int index = offset / 8;
        int mask = 1 << (offset % 8);
 
        ab8500->mask[index] |= mask;
 }
 
-static void ab8500_irq_unmask(unsigned int irq)
+static void ab8500_irq_unmask(struct irq_data *data)
 {
-       struct ab8500 *ab8500 = get_irq_chip_data(irq);
-       int offset = irq - ab8500->irq_base;
+       struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
+       int offset = data->irq - ab8500->irq_base;
        int index = offset / 8;
        int mask = 1 << (offset % 8);
 
@@ -279,10 +288,10 @@ static void ab8500_irq_unmask(unsigned int irq)
 
 static struct irq_chip ab8500_irq_chip = {
        .name                   = "ab8500",
-       .bus_lock               = ab8500_irq_lock,
-       .bus_sync_unlock        = ab8500_irq_sync_unlock,
-       .mask                   = ab8500_irq_mask,
-       .unmask                 = ab8500_irq_unmask,
+       .irq_bus_lock           = ab8500_irq_lock,
+       .irq_bus_sync_unlock    = ab8500_irq_sync_unlock,
+       .irq_mask               = ab8500_irq_mask,
+       .irq_unmask             = ab8500_irq_unmask,
 };
 
 static irqreturn_t ab8500_irq(int irq, void *dev)
@@ -297,6 +306,10 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
                int status;
                u8 value;
 
+               /* Interrupt register 12 does'nt exist prior to version 0x20 */
+               if (regoffset == 11 && ab8500->chip_id < 0x20)
+                       continue;
+
                status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
                        AB8500_IT_LATCH1_REG + regoffset, &value);
                if (status < 0 || value == 0)
@@ -393,12 +406,194 @@ static struct resource ab8500_poweronkey_db_resources[] = {
        },
 };
 
+static struct resource ab8500_bm_resources[] = {
+       {
+               .name = "MAIN_EXT_CH_NOT_OK",
+               .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+               .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "BATT_OVV",
+               .start = AB8500_INT_BATT_OVV,
+               .end = AB8500_INT_BATT_OVV,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "MAIN_CH_UNPLUG_DET",
+               .start = AB8500_INT_MAIN_CH_UNPLUG_DET,
+               .end = AB8500_INT_MAIN_CH_UNPLUG_DET,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "MAIN_CHARGE_PLUG_DET",
+               .start = AB8500_INT_MAIN_CH_PLUG_DET,
+               .end = AB8500_INT_MAIN_CH_PLUG_DET,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "VBUS_DET_F",
+               .start = AB8500_INT_VBUS_DET_F,
+               .end = AB8500_INT_VBUS_DET_F,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "VBUS_DET_R",
+               .start = AB8500_INT_VBUS_DET_R,
+               .end = AB8500_INT_VBUS_DET_R,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "BAT_CTRL_INDB",
+               .start = AB8500_INT_BAT_CTRL_INDB,
+               .end = AB8500_INT_BAT_CTRL_INDB,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "CH_WD_EXP",
+               .start = AB8500_INT_CH_WD_EXP,
+               .end = AB8500_INT_CH_WD_EXP,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "VBUS_OVV",
+               .start = AB8500_INT_VBUS_OVV,
+               .end = AB8500_INT_VBUS_OVV,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "NCONV_ACCU",
+               .start = AB8500_INT_CCN_CONV_ACC,
+               .end = AB8500_INT_CCN_CONV_ACC,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "LOW_BAT_F",
+               .start = AB8500_INT_LOW_BAT_F,
+               .end = AB8500_INT_LOW_BAT_F,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "LOW_BAT_R",
+               .start = AB8500_INT_LOW_BAT_R,
+               .end = AB8500_INT_LOW_BAT_R,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "BTEMP_LOW",
+               .start = AB8500_INT_BTEMP_LOW,
+               .end = AB8500_INT_BTEMP_LOW,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "BTEMP_HIGH",
+               .start = AB8500_INT_BTEMP_HIGH,
+               .end = AB8500_INT_BTEMP_HIGH,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_CHARGER_NOT_OKR",
+               .start = AB8500_INT_USB_CHARGER_NOT_OK,
+               .end = AB8500_INT_USB_CHARGER_NOT_OK,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_CHARGE_DET_DONE",
+               .start = AB8500_INT_USB_CHG_DET_DONE,
+               .end = AB8500_INT_USB_CHG_DET_DONE,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_CH_TH_PROT_R",
+               .start = AB8500_INT_USB_CH_TH_PROT_R,
+               .end = AB8500_INT_USB_CH_TH_PROT_R,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "MAIN_CH_TH_PROT_R",
+               .start = AB8500_INT_MAIN_CH_TH_PROT_R,
+               .end = AB8500_INT_MAIN_CH_TH_PROT_R,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_CHARGER_NOT_OKF",
+               .start = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource ab8500_debug_resources[] = {
+       {
+               .name   = "IRQ_FIRST",
+               .start  = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+               .end    = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "IRQ_LAST",
+               .start  = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .end    = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource ab8500_usb_resources[] = {
+       {
+               .name = "ID_WAKEUP_R",
+               .start = AB8500_INT_ID_WAKEUP_R,
+               .end = AB8500_INT_ID_WAKEUP_R,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "ID_WAKEUP_F",
+               .start = AB8500_INT_ID_WAKEUP_F,
+               .end = AB8500_INT_ID_WAKEUP_F,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "VBUS_DET_F",
+               .start = AB8500_INT_VBUS_DET_F,
+               .end = AB8500_INT_VBUS_DET_F,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "VBUS_DET_R",
+               .start = AB8500_INT_VBUS_DET_R,
+               .end = AB8500_INT_VBUS_DET_R,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_LINK_STATUS",
+               .start = AB8500_INT_USB_LINK_STATUS,
+               .end = AB8500_INT_USB_LINK_STATUS,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource ab8500_temp_resources[] = {
+       {
+               .name  = "AB8500_TEMP_WARM",
+               .start = AB8500_INT_TEMP_WARM,
+               .end   = AB8500_INT_TEMP_WARM,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
 static struct mfd_cell ab8500_devs[] = {
 #ifdef CONFIG_DEBUG_FS
        {
                .name = "ab8500-debug",
+               .num_resources = ARRAY_SIZE(ab8500_debug_resources),
+               .resources = ab8500_debug_resources,
        },
 #endif
+       {
+               .name = "ab8500-sysctrl",
+       },
+       {
+               .name = "ab8500-regulator",
+       },
        {
                .name = "ab8500-gpadc",
                .num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
@@ -409,6 +604,22 @@ static struct mfd_cell ab8500_devs[] = {
                .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
                .resources = ab8500_rtc_resources,
        },
+       {
+               .name = "ab8500-bm",
+               .num_resources = ARRAY_SIZE(ab8500_bm_resources),
+               .resources = ab8500_bm_resources,
+       },
+       { .name = "ab8500-codec", },
+       {
+               .name = "ab8500-usb",
+               .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+               .resources = ab8500_usb_resources,
+       },
+       {
+               .name = "ab8500-poweron-key",
+               .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+               .resources = ab8500_poweronkey_db_resources,
+       },
        {
                .name = "ab8500-pwm",
                .id = 1,
@@ -421,17 +632,37 @@ static struct mfd_cell ab8500_devs[] = {
                .name = "ab8500-pwm",
                .id = 3,
        },
-       { .name = "ab8500-charger", },
-       { .name = "ab8500-audio", },
-       { .name = "ab8500-usb", },
-       { .name = "ab8500-regulator", },
+       { .name = "ab8500-leds", },
        {
-               .name = "ab8500-poweron-key",
-               .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
-               .resources = ab8500_poweronkey_db_resources,
+               .name = "ab8500-denc",
+       },
+       {
+               .name = "ab8500-temp",
+               .num_resources = ARRAY_SIZE(ab8500_temp_resources),
+               .resources = ab8500_temp_resources,
        },
 };
 
+static ssize_t show_chip_id(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct ab8500 *ab8500;
+
+       ab8500 = dev_get_drvdata(dev);
+       return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
+}
+
+static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
+
+static struct attribute *ab8500_sysfs_entries[] = {
+       &dev_attr_chip_id.attr,
+       NULL,
+};
+
+static struct attribute_group ab8500_attr_group = {
+       .attrs  = ab8500_sysfs_entries,
+};
+
 int __devinit ab8500_init(struct ab8500 *ab8500)
 {
        struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
@@ -454,8 +685,9 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
         * 0x0 - Early Drop
         * 0x10 - Cut 1.0
         * 0x11 - Cut 1.1
+        * 0x20 - Cut 2.0
         */
-       if (value == 0x0 || value == 0x10 || value == 0x11) {
+       if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20) {
                ab8500->revision = value;
                dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
        } else {
@@ -468,18 +700,16 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
                plat->init(ab8500);
 
        /* Clear and mask all interrupts */
-       for (i = 0; i < 10; i++) {
-               get_register_interruptible(ab8500, AB8500_INTERRUPT,
-                       AB8500_IT_LATCH1_REG + i, &value);
-               set_register_interruptible(ab8500, AB8500_INTERRUPT,
-                       AB8500_IT_MASK1_REG + i, 0xff);
-       }
+       for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
+               /* Interrupt register 12 does'nt exist prior to version 0x20 */
+               if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+                       continue;
 
-       for (i = 18; i < 24; i++) {
                get_register_interruptible(ab8500, AB8500_INTERRUPT,
-                       AB8500_IT_LATCH1_REG + i, &value);
+                       AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
+                       &value);
                set_register_interruptible(ab8500, AB8500_INTERRUPT,
-                       AB8500_IT_MASK1_REG + i, 0xff);
+                       AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
        }
 
        ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
@@ -495,7 +725,8 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
                        return ret;
 
                ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
-                                          IRQF_ONESHOT, "ab8500", ab8500);
+                                          IRQF_ONESHOT | IRQF_NO_SUSPEND,
+                                          "ab8500", ab8500);
                if (ret)
                        goto out_removeirq;
        }
@@ -506,6 +737,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
        if (ret)
                goto out_freeirq;
 
+       ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
+       if (ret)
+               dev_err(ab8500->dev, "error creating sysfs entries\n");
+
        return ret;
 
 out_freeirq:
@@ -519,6 +754,7 @@ out_removeirq:
 
 int __devexit ab8500_exit(struct ab8500 *ab8500)
 {
+       sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
        mfd_remove_devices(ab8500->dev);
        if (ab8500->irq_base) {
                free_irq(ab8500->irq, ab8500);
index 8d1e05a3981595463774d8018ca8c67c615e42ab..3c1541ae722321f43b27a01294e553a6d4bcdf58 100644 (file)
@@ -24,9 +24,9 @@ static u32 debug_address;
  * @perm: access permissions for the range
  */
 struct ab8500_reg_range {
-       u8 first;
-       u8 last;
-       u8 perm;
+       u8 first;
+       u8 last;
+       u8 perm;
 };
 
 /**
@@ -36,9 +36,9 @@ struct ab8500_reg_range {
  * @range: the list of register ranges
  */
 struct ab8500_i2c_ranges {
-       u8 num_ranges;
-       u8 bankid;
-       const struct ab8500_reg_range *range;
+       u8 num_ranges;
+       u8 bankid;
+       const struct ab8500_reg_range *range;
 };
 
 #define AB8500_NAME_STRING "ab8500"
@@ -47,521 +47,521 @@ struct ab8500_i2c_ranges {
 #define AB8500_REV_REG 0x80
 
 static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = {
-       [0x0] = {
-               .num_ranges = 0,
-               .range = 0,
-       },
-       [AB8500_SYS_CTRL1_BLOCK] = {
-               .num_ranges = 3,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x00,
-                               .last = 0x02,
-                       },
-                       {
-                               .first = 0x42,
-                               .last = 0x42,
-                       },
-                       {
-                               .first = 0x80,
-                               .last = 0x81,
-                       },
-               },
-       },
-       [AB8500_SYS_CTRL2_BLOCK] = {
-               .num_ranges = 4,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x00,
-                               .last = 0x0D,
-                       },
-                       {
-                               .first = 0x0F,
-                               .last = 0x17,
-                       },
-                       {
-                               .first = 0x30,
-                               .last = 0x30,
-                       },
-                       {
-                               .first = 0x32,
-                               .last = 0x33,
-                       },
-               },
-       },
-       [AB8500_REGU_CTRL1] = {
-               .num_ranges = 3,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x00,
-                               .last = 0x00,
-                       },
-                       {
-                               .first = 0x03,
-                               .last = 0x10,
-                       },
-                       {
-                               .first = 0x80,
-                               .last = 0x84,
-                       },
-               },
-       },
-       [AB8500_REGU_CTRL2] = {
-               .num_ranges = 5,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x00,
-                               .last = 0x15,
-                       },
-                       {
-                               .first = 0x17,
-                               .last = 0x19,
-                       },
-                       {
-                               .first = 0x1B,
-                               .last = 0x1D,
-                       },
-                       {
-                               .first = 0x1F,
-                               .last = 0x22,
-                       },
-                       {
-                               .first = 0x40,
-                               .last = 0x44,
-                       },
-                       /* 0x80-0x8B is SIM registers and should
-                        * not be accessed from here */
-               },
-       },
-       [AB8500_USB] = {
-               .num_ranges = 2,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x80,
-                               .last = 0x83,
-                       },
-                       {
-                               .first = 0x87,
-                               .last = 0x8A,
-                       },
-               },
-       },
-       [AB8500_TVOUT] = {
-               .num_ranges = 9,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x00,
-                               .last = 0x12,
-                       },
-                       {
-                               .first = 0x15,
-                               .last = 0x17,
-                       },
-                       {
-                               .first = 0x19,
-                               .last = 0x21,
-                       },
-                       {
-                               .first = 0x27,
-                               .last = 0x2C,
-                       },
-                       {
-                               .first = 0x41,
-                               .last = 0x41,
-                       },
-                       {
-                               .first = 0x45,
-                               .last = 0x5B,
-                       },
-                       {
-                               .first = 0x5D,
-                               .last = 0x5D,
-                       },
-                       {
-                               .first = 0x69,
-                               .last = 0x69,
-                       },
-                       {
-                               .first = 0x80,
-                               .last = 0x81,
-                       },
-               },
-       },
-       [AB8500_DBI] = {
-               .num_ranges = 0,
-               .range = 0,
-       },
-       [AB8500_ECI_AV_ACC] = {
-               .num_ranges = 1,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x80,
-                               .last = 0x82,
-                       },
-               },
-       },
-       [0x9] = {
-               .num_ranges = 0,
-               .range = 0,
-       },
-       [AB8500_GPADC] = {
-               .num_ranges = 1,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x00,
-                               .last = 0x08,
-                       },
-               },
-       },
-       [AB8500_CHARGER] = {
-               .num_ranges = 8,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x00,
-                               .last = 0x03,
-                       },
-                       {
-                               .first = 0x05,
-                               .last = 0x05,
-                       },
-                       {
-                               .first = 0x40,
-                               .last = 0x40,
-                       },
-                       {
-                               .first = 0x42,
-                               .last = 0x42,
-                       },
-                       {
-                               .first = 0x44,
-                               .last = 0x44,
-                       },
-                       {
-                               .first = 0x50,
-                               .last = 0x55,
-                       },
-                       {
-                               .first = 0x80,
-                               .last = 0x82,
-                       },
-                       {
-                               .first = 0xC0,
-                               .last = 0xC2,
-                       },
-               },
-       },
-       [AB8500_GAS_GAUGE] = {
-               .num_ranges = 3,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x00,
-                               .last = 0x00,
-                       },
-                       {
-                               .first = 0x07,
-                               .last = 0x0A,
-                       },
-                       {
-                               .first = 0x10,
-                               .last = 0x14,
-                       },
-               },
-       },
-       [AB8500_AUDIO] = {
-               .num_ranges = 1,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x00,
-                               .last = 0x6F,
-                       },
-               },
-       },
-       [AB8500_INTERRUPT] = {
-               .num_ranges = 0,
-               .range = 0,
-       },
-       [AB8500_RTC] = {
-               .num_ranges = 1,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x00,
-                               .last = 0x0F,
-                       },
-               },
-       },
-       [AB8500_MISC] = {
-               .num_ranges = 8,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x00,
-                               .last = 0x05,
-                       },
-                       {
-                               .first = 0x10,
-                               .last = 0x15,
-                       },
-                       {
-                               .first = 0x20,
-                               .last = 0x25,
-                       },
-                       {
-                               .first = 0x30,
-                               .last = 0x35,
-                       },
-                       {
-                               .first = 0x40,
-                               .last = 0x45,
-                       },
-                       {
-                               .first = 0x50,
-                               .last = 0x50,
-                       },
-                       {
-                               .first = 0x60,
-                               .last = 0x67,
-                       },
-                       {
-                               .first = 0x80,
-                               .last = 0x80,
-                       },
-               },
-       },
-       [0x11] = {
-               .num_ranges = 0,
-               .range = 0,
-       },
-       [0x12] = {
-               .num_ranges = 0,
-               .range = 0,
-       },
-       [0x13] = {
-               .num_ranges = 0,
-               .range = 0,
-       },
-       [0x14] = {
-               .num_ranges = 0,
-               .range = 0,
-       },
-       [AB8500_OTP_EMUL] = {
-               .num_ranges = 1,
-               .range = (struct ab8500_reg_range[]) {
-                       {
-                               .first = 0x01,
-                               .last = 0x0F,
-                       },
-               },
-       },
+       [0x0] = {
+               .num_ranges = 0,
+               .range = 0,
+       },
+       [AB8500_SYS_CTRL1_BLOCK] = {
+               .num_ranges = 3,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x02,
+                       },
+                       {
+                               .first = 0x42,
+                               .last = 0x42,
+                       },
+                       {
+                               .first = 0x80,
+                               .last = 0x81,
+                       },
+               },
+       },
+       [AB8500_SYS_CTRL2_BLOCK] = {
+               .num_ranges = 4,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x0D,
+                       },
+                       {
+                               .first = 0x0F,
+                               .last = 0x17,
+                       },
+                       {
+                               .first = 0x30,
+                               .last = 0x30,
+                       },
+                       {
+                               .first = 0x32,
+                               .last = 0x33,
+                       },
+               },
+       },
+       [AB8500_REGU_CTRL1] = {
+               .num_ranges = 3,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x00,
+                       },
+                       {
+                               .first = 0x03,
+                               .last = 0x10,
+                       },
+                       {
+                               .first = 0x80,
+                               .last = 0x84,
+                       },
+               },
+       },
+       [AB8500_REGU_CTRL2] = {
+               .num_ranges = 5,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x15,
+                       },
+                       {
+                               .first = 0x17,
+                               .last = 0x19,
+                       },
+                       {
+                               .first = 0x1B,
+                               .last = 0x1D,
+                       },
+                       {
+                               .first = 0x1F,
+                               .last = 0x22,
+                       },
+                       {
+                               .first = 0x40,
+                               .last = 0x44,
+                       },
+                       /* 0x80-0x8B is SIM registers and should
+                        * not be accessed from here */
+               },
+       },
+       [AB8500_USB] = {
+               .num_ranges = 2,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x80,
+                               .last = 0x83,
+                       },
+                       {
+                               .first = 0x87,
+                               .last = 0x8A,
+                       },
+               },
+       },
+       [AB8500_TVOUT] = {
+               .num_ranges = 9,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x12,
+                       },
+                       {
+                               .first = 0x15,
+                               .last = 0x17,
+                       },
+                       {
+                               .first = 0x19,
+                               .last = 0x21,
+                       },
+                       {
+                               .first = 0x27,
+                               .last = 0x2C,
+                       },
+                       {
+                               .first = 0x41,
+                               .last = 0x41,
+                       },
+                       {
+                               .first = 0x45,
+                               .last = 0x5B,
+                       },
+                       {
+                               .first = 0x5D,
+                               .last = 0x5D,
+                       },
+                       {
+                               .first = 0x69,
+                               .last = 0x69,
+                       },
+                       {
+                               .first = 0x80,
+                               .last = 0x81,
+                       },
+               },
+       },
+       [AB8500_DBI] = {
+               .num_ranges = 0,
+               .range = NULL,
+       },
+       [AB8500_ECI_AV_ACC] = {
+               .num_ranges = 1,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x80,
+                               .last = 0x82,
+                       },
+               },
+       },
+       [0x9] = {
+               .num_ranges = 0,
+               .range = NULL,
+       },
+       [AB8500_GPADC] = {
+               .num_ranges = 1,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x08,
+                       },
+               },
+       },
+       [AB8500_CHARGER] = {
+               .num_ranges = 8,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x03,
+                       },
+                       {
+                               .first = 0x05,
+                               .last = 0x05,
+                       },
+                       {
+                               .first = 0x40,
+                               .last = 0x40,
+                       },
+                       {
+                               .first = 0x42,
+                               .last = 0x42,
+                       },
+                       {
+                               .first = 0x44,
+                               .last = 0x44,
+                       },
+                       {
+                               .first = 0x50,
+                               .last = 0x55,
+                       },
+                       {
+                               .first = 0x80,
+                               .last = 0x82,
+                       },
+                       {
+                               .first = 0xC0,
+                               .last = 0xC2,
+                       },
+               },
+       },
+       [AB8500_GAS_GAUGE] = {
+               .num_ranges = 3,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x00,
+                       },
+                       {
+                               .first = 0x07,
+                               .last = 0x0A,
+                       },
+                       {
+                               .first = 0x10,
+                               .last = 0x14,
+                       },
+               },
+       },
+       [AB8500_AUDIO] = {
+               .num_ranges = 1,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x6F,
+                       },
+               },
+       },
+       [AB8500_INTERRUPT] = {
+               .num_ranges = 0,
+               .range = NULL,
+       },
+       [AB8500_RTC] = {
+               .num_ranges = 1,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x0F,
+                       },
+               },
+       },
+       [AB8500_MISC] = {
+               .num_ranges = 8,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x00,
+                               .last = 0x05,
+                       },
+                       {
+                               .first = 0x10,
+                               .last = 0x15,
+                       },
+                       {
+                               .first = 0x20,
+                               .last = 0x25,
+                       },
+                       {
+                               .first = 0x30,
+                               .last = 0x35,
+                       },
+                       {
+                               .first = 0x40,
+                               .last = 0x45,
+                       },
+                       {
+                               .first = 0x50,
+                               .last = 0x50,
+                       },
+                       {
+                               .first = 0x60,
+                               .last = 0x67,
+                       },
+                       {
+                               .first = 0x80,
+                               .last = 0x80,
+                       },
+               },
+       },
+       [0x11] = {
+               .num_ranges = 0,
+               .range = NULL,
+       },
+       [0x12] = {
+               .num_ranges = 0,
+               .range = NULL,
+       },
+       [0x13] = {
+               .num_ranges = 0,
+               .range = NULL,
+       },
+       [0x14] = {
+               .num_ranges = 0,
+               .range = NULL,
+       },
+       [AB8500_OTP_EMUL] = {
+               .num_ranges = 1,
+               .range = (struct ab8500_reg_range[]) {
+                       {
+                               .first = 0x01,
+                               .last = 0x0F,
+                       },
+               },
+       },
 };
 
 static int ab8500_registers_print(struct seq_file *s, void *p)
 {
-       struct device *dev = s->private;
-       unsigned int i;
-       u32 bank = debug_bank;
-
-       seq_printf(s, AB8500_NAME_STRING " register values:\n");
-
-       seq_printf(s, " bank %u:\n", bank);
-       for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
-               u32 reg;
-
-               for (reg = debug_ranges[bank].range[i].first;
-                       reg <= debug_ranges[bank].range[i].last;
-                       reg++) {
-                       u8 value;
-                       int err;
-
-                       err = abx500_get_register_interruptible(dev,
-                               (u8)bank, (u8)reg, &value);
-                       if (err < 0) {
-                               dev_err(dev, "ab->read fail %d\n", err);
-                               return err;
-                       }
-
-                       err = seq_printf(s, "  [%u/0x%02X]: 0x%02X\n", bank,
-                               reg, value);
-                       if (err < 0) {
-                               dev_err(dev, "seq_printf overflow\n");
-                               /* Error is not returned here since
-                                * the output is wanted in any case */
-                               return 0;
-                       }
-               }
-       }
-       return 0;
+       struct device *dev = s->private;
+       unsigned int i;
+       u32 bank = debug_bank;
+
+       seq_printf(s, AB8500_NAME_STRING " register values:\n");
+
+       seq_printf(s, " bank %u:\n", bank);
+       for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
+               u32 reg;
+
+               for (reg = debug_ranges[bank].range[i].first;
+                       reg <= debug_ranges[bank].range[i].last;
+                       reg++) {
+                       u8 value;
+                       int err;
+
+                       err = abx500_get_register_interruptible(dev,
+                               (u8)bank, (u8)reg, &value);
+                       if (err < 0) {
+                               dev_err(dev, "ab->read fail %d\n", err);
+                               return err;
+                       }
+
+                       err = seq_printf(s, "  [%u/0x%02X]: 0x%02X\n", bank,
+                               reg, value);
+                       if (err < 0) {
+                               dev_err(dev, "seq_printf overflow\n");
+                               /* Error is not returned here since
+                                * the output is wanted in any case */
+                               return 0;
+                       }
+               }
+       }
+       return 0;
 }
 
 static int ab8500_registers_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, ab8500_registers_print, inode->i_private);
+       return single_open(file, ab8500_registers_print, inode->i_private);
 }
 
 static const struct file_operations ab8500_registers_fops = {
-       .open = ab8500_registers_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
+       .open = ab8500_registers_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
 };
 
 static int ab8500_bank_print(struct seq_file *s, void *p)
 {
-       return seq_printf(s, "%d\n", debug_bank);
+       return seq_printf(s, "%d\n", debug_bank);
 }
 
 static int ab8500_bank_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, ab8500_bank_print, inode->i_private);
+       return single_open(file, ab8500_bank_print, inode->i_private);
 }
 
 static ssize_t ab8500_bank_write(struct file *file,
-       const char __user *user_buf,
-       size_t count, loff_t *ppos)
+       const char __user *user_buf,
+       size_t count, loff_t *ppos)
 {
-       struct device *dev = ((struct seq_file *)(file->private_data))->private;
-       char buf[32];
-       int buf_size;
-       unsigned long user_bank;
-       int err;
-
-       /* Get userspace string and assure termination */
-       buf_size = min(count, (sizeof(buf) - 1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       buf[buf_size] = 0;
-
-       err = strict_strtoul(buf, 0, &user_bank);
-       if (err)
-               return -EINVAL;
-
-       if (user_bank >= AB8500_NUM_BANKS) {
-               dev_err(dev, "debugfs error input > number of banks\n");
-               return -EINVAL;
-       }
-
-       debug_bank = user_bank;
-
-       return buf_size;
+       struct device *dev = ((struct seq_file *)(file->private_data))->private;
+       char buf[32];
+       int buf_size;
+       unsigned long user_bank;
+       int err;
+
+       /* Get userspace string and assure termination */
+       buf_size = min(count, (sizeof(buf) - 1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       err = strict_strtoul(buf, 0, &user_bank);
+       if (err)
+               return -EINVAL;
+
+       if (user_bank >= AB8500_NUM_BANKS) {
+               dev_err(dev, "debugfs error input > number of banks\n");
+               return -EINVAL;
+       }
+
+       debug_bank = user_bank;
+
+       return buf_size;
 }
 
 static int ab8500_address_print(struct seq_file *s, void *p)
 {
-       return seq_printf(s, "0x%02X\n", debug_address);
+       return seq_printf(s, "0x%02X\n", debug_address);
 }
 
 static int ab8500_address_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, ab8500_address_print, inode->i_private);
+       return single_open(file, ab8500_address_print, inode->i_private);
 }
 
 static ssize_t ab8500_address_write(struct file *file,
-       const char __user *user_buf,
-       size_t count, loff_t *ppos)
+       const char __user *user_buf,
+       size_t count, loff_t *ppos)
 {
-       struct device *dev = ((struct seq_file *)(file->private_data))->private;
-       char buf[32];
-       int buf_size;
-       unsigned long user_address;
-       int err;
-
-       /* Get userspace string and assure termination */
-       buf_size = min(count, (sizeof(buf) - 1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       buf[buf_size] = 0;
-
-       err = strict_strtoul(buf, 0, &user_address);
-       if (err)
-               return -EINVAL;
-       if (user_address > 0xff) {
-               dev_err(dev, "debugfs error input > 0xff\n");
-               return -EINVAL;
-       }
-       debug_address = user_address;
-       return buf_size;
+       struct device *dev = ((struct seq_file *)(file->private_data))->private;
+       char buf[32];
+       int buf_size;
+       unsigned long user_address;
+       int err;
+
+       /* Get userspace string and assure termination */
+       buf_size = min(count, (sizeof(buf) - 1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       err = strict_strtoul(buf, 0, &user_address);
+       if (err)
+               return -EINVAL;
+       if (user_address > 0xff) {
+               dev_err(dev, "debugfs error input > 0xff\n");
+               return -EINVAL;
+       }
+       debug_address = user_address;
+       return buf_size;
 }
 
 static int ab8500_val_print(struct seq_file *s, void *p)
 {
-       struct device *dev = s->private;
-       int ret;
-       u8 regvalue;
-
-       ret = abx500_get_register_interruptible(dev,
-               (u8)debug_bank, (u8)debug_address, &regvalue);
-       if (ret < 0) {
-               dev_err(dev, "abx500_get_reg fail %d, %d\n",
-                       ret, __LINE__);
-               return -EINVAL;
-       }
-       seq_printf(s, "0x%02X\n", regvalue);
-
-       return 0;
+       struct device *dev = s->private;
+       int ret;
+       u8 regvalue;
+
+       ret = abx500_get_register_interruptible(dev,
+               (u8)debug_bank, (u8)debug_address, &regvalue);
+       if (ret < 0) {
+               dev_err(dev, "abx500_get_reg fail %d, %d\n",
+                       ret, __LINE__);
+               return -EINVAL;
+       }
+       seq_printf(s, "0x%02X\n", regvalue);
+
+       return 0;
 }
 
 static int ab8500_val_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, ab8500_val_print, inode->i_private);
+       return single_open(file, ab8500_val_print, inode->i_private);
 }
 
 static ssize_t ab8500_val_write(struct file *file,
-       const char __user *user_buf,
-       size_t count, loff_t *ppos)
+       const char __user *user_buf,
+       size_t count, loff_t *ppos)
 {
-       struct device *dev = ((struct seq_file *)(file->private_data))->private;
-       char buf[32];
-       int buf_size;
-       unsigned long user_val;
-       int err;
-
-       /* Get userspace string and assure termination */
-       buf_size = min(count, (sizeof(buf)-1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       buf[buf_size] = 0;
-
-       err = strict_strtoul(buf, 0, &user_val);
-       if (err)
-               return -EINVAL;
-       if (user_val > 0xff) {
-               dev_err(dev, "debugfs error input > 0xff\n");
-               return -EINVAL;
-       }
-       err = abx500_set_register_interruptible(dev,
-               (u8)debug_bank, debug_address, (u8)user_val);
-       if (err < 0) {
-               printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
-               return -EINVAL;
-       }
-
-       return buf_size;
+       struct device *dev = ((struct seq_file *)(file->private_data))->private;
+       char buf[32];
+       int buf_size;
+       unsigned long user_val;
+       int err;
+
+       /* Get userspace string and assure termination */
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       err = strict_strtoul(buf, 0, &user_val);
+       if (err)
+               return -EINVAL;
+       if (user_val > 0xff) {
+               dev_err(dev, "debugfs error input > 0xff\n");
+               return -EINVAL;
+       }
+       err = abx500_set_register_interruptible(dev,
+               (u8)debug_bank, debug_address, (u8)user_val);
+       if (err < 0) {
+               printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
+               return -EINVAL;
+       }
+
+       return buf_size;
 }
 
 static const struct file_operations ab8500_bank_fops = {
-       .open = ab8500_bank_open,
-       .write = ab8500_bank_write,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
+       .open = ab8500_bank_open,
+       .write = ab8500_bank_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
 };
 
 static const struct file_operations ab8500_address_fops = {
-       .open = ab8500_address_open,
-       .write = ab8500_address_write,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
+       .open = ab8500_address_open,
+       .write = ab8500_address_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
 };
 
 static const struct file_operations ab8500_val_fops = {
-       .open = ab8500_val_open,
-       .write = ab8500_val_write,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
+       .open = ab8500_val_open,
+       .write = ab8500_val_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
 };
 
 static struct dentry *ab8500_dir;
@@ -572,77 +572,77 @@ static struct dentry *ab8500_val_file;
 
 static int __devinit ab8500_debug_probe(struct platform_device *plf)
 {
-       debug_bank = AB8500_MISC;
-       debug_address = AB8500_REV_REG & 0x00FF;
+       debug_bank = AB8500_MISC;
+       debug_address = AB8500_REV_REG & 0x00FF;
 
-       ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
-       if (!ab8500_dir)
-               goto exit_no_debugfs;
+       ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
+       if (!ab8500_dir)
+               goto exit_no_debugfs;
 
-       ab8500_reg_file = debugfs_create_file("all-bank-registers",
-               S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
-       if (!ab8500_reg_file)
-               goto exit_destroy_dir;
+       ab8500_reg_file = debugfs_create_file("all-bank-registers",
+               S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
+       if (!ab8500_reg_file)
+               goto exit_destroy_dir;
 
-       ab8500_bank_file = debugfs_create_file("register-bank",
-               (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops);
-       if (!ab8500_bank_file)
-               goto exit_destroy_reg;
+       ab8500_bank_file = debugfs_create_file("register-bank",
+               (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops);
+       if (!ab8500_bank_file)
+               goto exit_destroy_reg;
 
-       ab8500_address_file = debugfs_create_file("register-address",
-               (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
-               &ab8500_address_fops);
-       if (!ab8500_address_file)
-               goto exit_destroy_bank;
+       ab8500_address_file = debugfs_create_file("register-address",
+               (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
+               &ab8500_address_fops);
+       if (!ab8500_address_file)
+               goto exit_destroy_bank;
 
-       ab8500_val_file = debugfs_create_file("register-value",
-               (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops);
-       if (!ab8500_val_file)
-               goto exit_destroy_address;
+       ab8500_val_file = debugfs_create_file("register-value",
+               (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops);
+       if (!ab8500_val_file)
+               goto exit_destroy_address;
 
-       return 0;
+       return 0;
 
 exit_destroy_address:
-       debugfs_remove(ab8500_address_file);
+       debugfs_remove(ab8500_address_file);
 exit_destroy_bank:
-       debugfs_remove(ab8500_bank_file);
+       debugfs_remove(ab8500_bank_file);
 exit_destroy_reg:
-       debugfs_remove(ab8500_reg_file);
+       debugfs_remove(ab8500_reg_file);
 exit_destroy_dir:
-       debugfs_remove(ab8500_dir);
+       debugfs_remove(ab8500_dir);
 exit_no_debugfs:
-       dev_err(&plf->dev, "failed to create debugfs entries.\n");
-       return -ENOMEM;
+       dev_err(&plf->dev, "failed to create debugfs entries.\n");
+       return -ENOMEM;
 }
 
 static int __devexit ab8500_debug_remove(struct platform_device *plf)
 {
-       debugfs_remove(ab8500_val_file);
-       debugfs_remove(ab8500_address_file);
-       debugfs_remove(ab8500_bank_file);
-       debugfs_remove(ab8500_reg_file);
-       debugfs_remove(ab8500_dir);
+       debugfs_remove(ab8500_val_file);
+       debugfs_remove(ab8500_address_file);
+       debugfs_remove(ab8500_bank_file);
+       debugfs_remove(ab8500_reg_file);
+       debugfs_remove(ab8500_dir);
 
-       return 0;
+       return 0;
 }
 
 static struct platform_driver ab8500_debug_driver = {
-       .driver = {
-               .name = "ab8500-debug",
-               .owner = THIS_MODULE,
-       },
-       .probe  = ab8500_debug_probe,
-       .remove = __devexit_p(ab8500_debug_remove)
+       .driver = {
+               .name = "ab8500-debug",
+               .owner = THIS_MODULE,
+       },
+       .probe  = ab8500_debug_probe,
+       .remove = __devexit_p(ab8500_debug_remove)
 };
 
 static int __init ab8500_debug_init(void)
 {
-       return platform_driver_register(&ab8500_debug_driver);
+       return platform_driver_register(&ab8500_debug_driver);
 }
 
 static void __exit ab8500_debug_exit(void)
 {
-       platform_driver_unregister(&ab8500_debug_driver);
+       platform_driver_unregister(&ab8500_debug_driver);
 }
 subsys_initcall(ab8500_debug_init);
 module_exit(ab8500_debug_exit);
diff --git a/drivers/mfd/ab8500-spi.c b/drivers/mfd/ab8500-spi.c
deleted file mode 100644 (file)
index b165342..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mfd/ab8500.h>
-
-/*
- * This funtion writes to any AB8500 registers using
- * SPI protocol &  before it writes it packs the data
- * in the below 24 bit frame format
- *
- *      *|------------------------------------|
- *      *| 23|22...18|17.......10|9|8|7......0|
- *      *| r/w  bank       adr          data  |
- *      * ------------------------------------
- *
- * This function shouldn't be called from interrupt
- * context
- */
-static int ab8500_spi_write(struct ab8500 *ab8500, u16 addr, u8 data)
-{
-       struct spi_device *spi = container_of(ab8500->dev, struct spi_device,
-                                             dev);
-       unsigned long spi_data = addr << 10 | data;
-       struct spi_transfer xfer;
-       struct spi_message msg;
-
-       ab8500->tx_buf[0] = spi_data;
-       ab8500->rx_buf[0] = 0;
-
-       xfer.tx_buf     = ab8500->tx_buf;
-       xfer.rx_buf     = NULL;
-       xfer.len        = sizeof(unsigned long);
-
-       spi_message_init(&msg);
-       spi_message_add_tail(&xfer, &msg);
-
-       return spi_sync(spi, &msg);
-}
-
-static int ab8500_spi_read(struct ab8500 *ab8500, u16 addr)
-{
-       struct spi_device *spi = container_of(ab8500->dev, struct spi_device,
-                                             dev);
-       unsigned long spi_data = 1 << 23 | addr << 10;
-       struct spi_transfer xfer;
-       struct spi_message msg;
-       int ret;
-
-       ab8500->tx_buf[0] = spi_data;
-       ab8500->rx_buf[0] = 0;
-
-       xfer.tx_buf     = ab8500->tx_buf;
-       xfer.rx_buf     = ab8500->rx_buf;
-       xfer.len        = sizeof(unsigned long);
-
-       spi_message_init(&msg);
-       spi_message_add_tail(&xfer, &msg);
-
-       ret = spi_sync(spi, &msg);
-       if (!ret)
-               /*
-                * Only the 8 lowermost bytes are
-                * defined with value, the rest may
-                * vary depending on chip/board noise.
-                */
-               ret = ab8500->rx_buf[0] & 0xFFU;
-
-       return ret;
-}
-
-static int __devinit ab8500_spi_probe(struct spi_device *spi)
-{
-       struct ab8500 *ab8500;
-       int ret;
-
-       spi->bits_per_word = 24;
-       ret = spi_setup(spi);
-       if (ret < 0)
-               return ret;
-
-       ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
-       if (!ab8500)
-               return -ENOMEM;
-
-       ab8500->dev = &spi->dev;
-       ab8500->irq = spi->irq;
-
-       ab8500->read = ab8500_spi_read;
-       ab8500->write = ab8500_spi_write;
-
-       spi_set_drvdata(spi, ab8500);
-
-       ret = ab8500_init(ab8500);
-       if (ret)
-               kfree(ab8500);
-
-       return ret;
-}
-
-static int __devexit ab8500_spi_remove(struct spi_device *spi)
-{
-       struct ab8500 *ab8500 = spi_get_drvdata(spi);
-
-       ab8500_exit(ab8500);
-       kfree(ab8500);
-
-       return 0;
-}
-
-static struct spi_driver ab8500_spi_driver = {
-       .driver = {
-               .name = "ab8500-spi",
-               .owner = THIS_MODULE,
-       },
-       .probe  = ab8500_spi_probe,
-       .remove = __devexit_p(ab8500_spi_remove)
-};
-
-static int __init ab8500_spi_init(void)
-{
-       return spi_register_driver(&ab8500_spi_driver);
-}
-subsys_initcall(ab8500_spi_init);
-
-static void __exit ab8500_spi_exit(void)
-{
-       spi_unregister_driver(&ab8500_spi_driver);
-}
-module_exit(ab8500_spi_exit);
-
-MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com");
-MODULE_DESCRIPTION("AB8500 SPI");
-MODULE_LICENSE("GPL v2");
index 7de708d15d7251e62f490ca1f6eed1b75e8ff098..6a1f9404261277991099dbf446cd949b83ce5dcc 100644 (file)
@@ -57,7 +57,7 @@ struct asic3_clk {
                .rate = _rate,                  \
        }
 
-struct asic3_clk asic3_clk_init[] __initdata = {
+static struct asic3_clk asic3_clk_init[] __initdata = {
        INIT_CDEX(SPI, 0),
        INIT_CDEX(OWM, 5000000),
        INIT_CDEX(PWM0, 0),
@@ -102,7 +102,7 @@ static inline u32 asic3_read_register(struct asic3 *asic,
                        (reg >> asic->bus_shift));
 }
 
-void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
+static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
 {
        unsigned long flags;
        u32 val;
@@ -226,14 +226,14 @@ static inline int asic3_irq_to_index(struct asic3 *asic, int irq)
        return (irq - asic->irq_base) & 0xf;
 }
 
-static void asic3_mask_gpio_irq(unsigned int irq)
+static void asic3_mask_gpio_irq(struct irq_data *data)
 {
-       struct asic3 *asic = get_irq_chip_data(irq);
+       struct asic3 *asic = irq_data_get_irq_chip_data(data);
        u32 val, bank, index;
        unsigned long flags;
 
-       bank = asic3_irq_to_bank(asic, irq);
-       index = asic3_irq_to_index(asic, irq);
+       bank = asic3_irq_to_bank(asic, data->irq);
+       index = asic3_irq_to_index(asic, data->irq);
 
        spin_lock_irqsave(&asic->lock, flags);
        val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
@@ -242,9 +242,9 @@ static void asic3_mask_gpio_irq(unsigned int irq)
        spin_unlock_irqrestore(&asic->lock, flags);
 }
 
-static void asic3_mask_irq(unsigned int irq)
+static void asic3_mask_irq(struct irq_data *data)
 {
-       struct asic3 *asic = get_irq_chip_data(irq);
+       struct asic3 *asic = irq_data_get_irq_chip_data(data);
        int regval;
        unsigned long flags;
 
@@ -254,7 +254,7 @@ static void asic3_mask_irq(unsigned int irq)
                                     ASIC3_INTR_INT_MASK);
 
        regval &= ~(ASIC3_INTMASK_MASK0 <<
-                   (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
+                   (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
 
        asic3_write_register(asic,
                             ASIC3_INTR_BASE +
@@ -263,14 +263,14 @@ static void asic3_mask_irq(unsigned int irq)
        spin_unlock_irqrestore(&asic->lock, flags);
 }
 
-static void asic3_unmask_gpio_irq(unsigned int irq)
+static void asic3_unmask_gpio_irq(struct irq_data *data)
 {
-       struct asic3 *asic = get_irq_chip_data(irq);
+       struct asic3 *asic = irq_data_get_irq_chip_data(data);
        u32 val, bank, index;
        unsigned long flags;
 
-       bank = asic3_irq_to_bank(asic, irq);
-       index = asic3_irq_to_index(asic, irq);
+       bank = asic3_irq_to_bank(asic, data->irq);
+       index = asic3_irq_to_index(asic, data->irq);
 
        spin_lock_irqsave(&asic->lock, flags);
        val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
@@ -279,9 +279,9 @@ static void asic3_unmask_gpio_irq(unsigned int irq)
        spin_unlock_irqrestore(&asic->lock, flags);
 }
 
-static void asic3_unmask_irq(unsigned int irq)
+static void asic3_unmask_irq(struct irq_data *data)
 {
-       struct asic3 *asic = get_irq_chip_data(irq);
+       struct asic3 *asic = irq_data_get_irq_chip_data(data);
        int regval;
        unsigned long flags;
 
@@ -291,7 +291,7 @@ static void asic3_unmask_irq(unsigned int irq)
                                     ASIC3_INTR_INT_MASK);
 
        regval |= (ASIC3_INTMASK_MASK0 <<
-                  (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
+                  (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
 
        asic3_write_register(asic,
                             ASIC3_INTR_BASE +
@@ -300,15 +300,15 @@ static void asic3_unmask_irq(unsigned int irq)
        spin_unlock_irqrestore(&asic->lock, flags);
 }
 
-static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
+static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
 {
-       struct asic3 *asic = get_irq_chip_data(irq);
+       struct asic3 *asic = irq_data_get_irq_chip_data(data);
        u32 bank, index;
        u16 trigger, level, edge, bit;
        unsigned long flags;
 
-       bank = asic3_irq_to_bank(asic, irq);
-       index = asic3_irq_to_index(asic, irq);
+       bank = asic3_irq_to_bank(asic, data->irq);
+       index = asic3_irq_to_index(asic, data->irq);
        bit = 1<<index;
 
        spin_lock_irqsave(&asic->lock, flags);
@@ -318,7 +318,7 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
                                   bank + ASIC3_GPIO_EDGE_TRIGGER);
        trigger = asic3_read_register(asic,
                                      bank + ASIC3_GPIO_TRIGGER_TYPE);
-       asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit;
+       asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] &= ~bit;
 
        if (type == IRQ_TYPE_EDGE_RISING) {
                trigger |= bit;
@@ -328,11 +328,11 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
                edge &= ~bit;
        } else if (type == IRQ_TYPE_EDGE_BOTH) {
                trigger |= bit;
-               if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base))
+               if (asic3_gpio_get(&asic->gpio, data->irq - asic->irq_base))
                        edge &= ~bit;
                else
                        edge |= bit;
-               asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit;
+               asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] |= bit;
        } else if (type == IRQ_TYPE_LEVEL_LOW) {
                trigger &= ~bit;
                level &= ~bit;
@@ -359,17 +359,17 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
 
 static struct irq_chip asic3_gpio_irq_chip = {
        .name           = "ASIC3-GPIO",
-       .ack            = asic3_mask_gpio_irq,
-       .mask           = asic3_mask_gpio_irq,
-       .unmask         = asic3_unmask_gpio_irq,
-       .set_type       = asic3_gpio_irq_type,
+       .irq_ack        = asic3_mask_gpio_irq,
+       .irq_mask       = asic3_mask_gpio_irq,
+       .irq_unmask     = asic3_unmask_gpio_irq,
+       .irq_set_type   = asic3_gpio_irq_type,
 };
 
 static struct irq_chip asic3_irq_chip = {
        .name           = "ASIC3",
-       .ack            = asic3_mask_irq,
-       .mask           = asic3_mask_irq,
-       .unmask         = asic3_unmask_irq,
+       .irq_ack        = asic3_mask_irq,
+       .irq_mask       = asic3_mask_irq,
+       .irq_unmask     = asic3_unmask_irq,
 };
 
 static int __init asic3_irq_probe(struct platform_device *pdev)
@@ -635,7 +635,7 @@ static struct resource ds1wm_resources[] = {
        },
        {
                .start = ASIC3_IRQ_OWM,
-               .start = ASIC3_IRQ_OWM,
+               .end   = ASIC3_IRQ_OWM,
                .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
        },
 };
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c
new file mode 100644 (file)
index 0000000..59ca6f1
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * cs5535-mfd.c - core MFD driver for CS5535/CS5536 southbridges
+ *
+ * The CS5535 and CS5536 has an ISA bridge on the PCI bus that is
+ * used for accessing GPIOs, MFGPTs, ACPI, etc.  Each subdevice has
+ * an IO range that's specified in a single BAR.  The BAR order is
+ * hardcoded in the CS553x specifications.
+ *
+ * Copyright (c) 2010  Andres Salomon <dilinger@queued.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#define DRV_NAME "cs5535-mfd"
+
+enum cs5535_mfd_bars {
+       SMB_BAR = 0,
+       GPIO_BAR = 1,
+       MFGPT_BAR = 2,
+       PMS_BAR = 4,
+       ACPI_BAR = 5,
+       NR_BARS,
+};
+
+static __devinitdata struct resource cs5535_mfd_resources[NR_BARS];
+
+static __devinitdata struct mfd_cell cs5535_mfd_cells[] = {
+       {
+               .id = SMB_BAR,
+               .name = "cs5535-smb",
+               .num_resources = 1,
+               .resources = &cs5535_mfd_resources[SMB_BAR],
+       },
+       {
+               .id = GPIO_BAR,
+               .name = "cs5535-gpio",
+               .num_resources = 1,
+               .resources = &cs5535_mfd_resources[GPIO_BAR],
+       },
+       {
+               .id = MFGPT_BAR,
+               .name = "cs5535-mfgpt",
+               .num_resources = 1,
+               .resources = &cs5535_mfd_resources[MFGPT_BAR],
+       },
+       {
+               .id = PMS_BAR,
+               .name = "cs5535-pms",
+               .num_resources = 1,
+               .resources = &cs5535_mfd_resources[PMS_BAR],
+       },
+       {
+               .id = ACPI_BAR,
+               .name = "cs5535-acpi",
+               .num_resources = 1,
+               .resources = &cs5535_mfd_resources[ACPI_BAR],
+       },
+};
+
+static int __devinit cs5535_mfd_probe(struct pci_dev *pdev,
+               const struct pci_device_id *id)
+{
+       int err, i;
+
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
+
+       /* fill in IO range for each cell; subdrivers handle the region */
+       for (i = 0; i < ARRAY_SIZE(cs5535_mfd_cells); i++) {
+               int bar = cs5535_mfd_cells[i].id;
+               struct resource *r = &cs5535_mfd_resources[bar];
+
+               r->flags = IORESOURCE_IO;
+               r->start = pci_resource_start(pdev, bar);
+               r->end = pci_resource_end(pdev, bar);
+
+               /* id is used for temporarily storing BAR; unset it now */
+               cs5535_mfd_cells[i].id = 0;
+       }
+
+       err = mfd_add_devices(&pdev->dev, -1, cs5535_mfd_cells,
+                       ARRAY_SIZE(cs5535_mfd_cells), NULL, 0);
+       if (err) {
+               dev_err(&pdev->dev, "MFD add devices failed: %d\n", err);
+               goto err_disable;
+       }
+
+       dev_info(&pdev->dev, "%zu devices registered.\n",
+                       ARRAY_SIZE(cs5535_mfd_cells));
+
+       return 0;
+
+err_disable:
+       pci_disable_device(pdev);
+       return err;
+}
+
+static void __devexit cs5535_mfd_remove(struct pci_dev *pdev)
+{
+       mfd_remove_devices(&pdev->dev);
+       pci_disable_device(pdev);
+}
+
+static struct pci_device_id cs5535_mfd_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl);
+
+static struct pci_driver cs5535_mfd_drv = {
+       .name = DRV_NAME,
+       .id_table = cs5535_mfd_pci_tbl,
+       .probe = cs5535_mfd_probe,
+       .remove = __devexit_p(cs5535_mfd_remove),
+};
+
+static int __init cs5535_mfd_init(void)
+{
+       return pci_register_driver(&cs5535_mfd_drv);
+}
+
+static void __exit cs5535_mfd_exit(void)
+{
+       pci_unregister_driver(&cs5535_mfd_drv);
+}
+
+module_init(cs5535_mfd_init);
+module_exit(cs5535_mfd_exit);
+
+MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
+MODULE_DESCRIPTION("MFD driver for CS5535/CS5536 southbridge's ISA PCI device");
+MODULE_LICENSE("GPL");
index c2b698d69a93862937efa7efb4e1bf3d48c96f32..9e2d8dd5f9e53d1d57d0ebbbee5bfedb992068e1 100644 (file)
@@ -144,26 +144,26 @@ int pcap_to_irq(struct pcap_chip *pcap, int irq)
 }
 EXPORT_SYMBOL_GPL(pcap_to_irq);
 
-static void pcap_mask_irq(unsigned int irq)
+static void pcap_mask_irq(struct irq_data *d)
 {
-       struct pcap_chip *pcap = get_irq_chip_data(irq);
+       struct pcap_chip *pcap = irq_data_get_irq_chip_data(d);
 
-       pcap->msr |= 1 << irq_to_pcap(pcap, irq);
+       pcap->msr |= 1 << irq_to_pcap(pcap, d->irq);
        queue_work(pcap->workqueue, &pcap->msr_work);
 }
 
-static void pcap_unmask_irq(unsigned int irq)
+static void pcap_unmask_irq(struct irq_data *d)
 {
-       struct pcap_chip *pcap = get_irq_chip_data(irq);
+       struct pcap_chip *pcap = irq_data_get_irq_chip_data(d);
 
-       pcap->msr &= ~(1 << irq_to_pcap(pcap, irq));
+       pcap->msr &= ~(1 << irq_to_pcap(pcap, d->irq));
        queue_work(pcap->workqueue, &pcap->msr_work);
 }
 
 static struct irq_chip pcap_irq_chip = {
-       .name   = "pcap",
-       .mask   = pcap_mask_irq,
-       .unmask = pcap_unmask_irq,
+       .name           = "pcap",
+       .irq_mask       = pcap_mask_irq,
+       .irq_unmask     = pcap_unmask_irq,
 };
 
 static void pcap_msr_work(struct work_struct *work)
@@ -199,8 +199,7 @@ static void pcap_isr_work(struct work_struct *work)
                        if (service & 1) {
                                struct irq_desc *desc = irq_to_desc(irq);
 
-                               if (WARN(!desc, KERN_WARNING
-                                               "Invalid PCAP IRQ %d\n", irq))
+                               if (WARN(!desc, "Invalid PCAP IRQ %d\n", irq))
                                        break;
 
                                if (desc->status & IRQ_DISABLED)
@@ -218,7 +217,7 @@ static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
        struct pcap_chip *pcap = get_irq_data(irq);
 
-       desc->chip->ack(irq);
+       desc->irq_data.chip->irq_ack(&desc->irq_data);
        queue_work(pcap->workqueue, &pcap->isr_work);
        return;
 }
@@ -282,7 +281,7 @@ static irqreturn_t pcap_adc_irq(int irq, void *_pcap)
        mutex_lock(&pcap->adc_mutex);
        req = pcap->adc_queue[pcap->adc_head];
 
-       if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) {
+       if (WARN(!req, "adc irq without pending request\n")) {
                mutex_unlock(&pcap->adc_mutex);
                return IRQ_HANDLED;
        }
index d3e74f8585e0b087507c47618bc344d751c8800c..d00b6d1a69e531daedb85a479fad72849a1e30c9 100644 (file)
@@ -70,31 +70,32 @@ static inline void ack_irqs(struct egpio_info *ei)
                        ei->ack_write, ei->ack_register << ei->bus_shift);
 }
 
-static void egpio_ack(unsigned int irq)
+static void egpio_ack(struct irq_data *data)
 {
 }
 
 /* There does not appear to be a way to proactively mask interrupts
  * on the egpio chip itself.  So, we simply ignore interrupts that
  * aren't desired. */
-static void egpio_mask(unsigned int irq)
+static void egpio_mask(struct irq_data *data)
 {
-       struct egpio_info *ei = get_irq_chip_data(irq);
-       ei->irqs_enabled &= ~(1 << (irq - ei->irq_start));
-       pr_debug("EGPIO mask %d %04x\n", irq, ei->irqs_enabled);
+       struct egpio_info *ei = irq_data_get_irq_chip_data(data);
+       ei->irqs_enabled &= ~(1 << (data->irq - ei->irq_start));
+       pr_debug("EGPIO mask %d %04x\n", data->irq, ei->irqs_enabled);
 }
-static void egpio_unmask(unsigned int irq)
+
+static void egpio_unmask(struct irq_data *data)
 {
-       struct egpio_info *ei = get_irq_chip_data(irq);
-       ei->irqs_enabled |= 1 << (irq - ei->irq_start);
-       pr_debug("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled);
+       struct egpio_info *ei = irq_data_get_irq_chip_data(data);
+       ei->irqs_enabled |= 1 << (data->irq - ei->irq_start);
+       pr_debug("EGPIO unmask %d %04x\n", data->irq, ei->irqs_enabled);
 }
 
 static struct irq_chip egpio_muxed_chip = {
-       .name   = "htc-egpio",
-       .ack    = egpio_ack,
-       .mask   = egpio_mask,
-       .unmask = egpio_unmask,
+       .name           = "htc-egpio",
+       .irq_ack        = egpio_ack,
+       .irq_mask       = egpio_mask,
+       .irq_unmask     = egpio_unmask,
 };
 
 static void egpio_handler(unsigned int irq, struct irq_desc *desc)
index 594c9a8e25e160b43a90bf8eceea7c5661b2709d..296ad1562f69a76d0c9b13101eb2821cdf8fcc31 100644 (file)
@@ -82,25 +82,25 @@ struct htcpld_data {
 /* There does not appear to be a way to proactively mask interrupts
  * on the htcpld chip itself.  So, we simply ignore interrupts that
  * aren't desired. */
-static void htcpld_mask(unsigned int irq)
+static void htcpld_mask(struct irq_data *data)
 {
-       struct htcpld_chip *chip = get_irq_chip_data(irq);
-       chip->irqs_enabled &= ~(1 << (irq - chip->irq_start));
-       pr_debug("HTCPLD mask %d %04x\n", irq, chip->irqs_enabled);
+       struct htcpld_chip *chip = irq_data_get_irq_chip_data(data);
+       chip->irqs_enabled &= ~(1 << (data->irq - chip->irq_start));
+       pr_debug("HTCPLD mask %d %04x\n", data->irq, chip->irqs_enabled);
 }
-static void htcpld_unmask(unsigned int irq)
+static void htcpld_unmask(struct irq_data *data)
 {
-       struct htcpld_chip *chip = get_irq_chip_data(irq);
-       chip->irqs_enabled |= 1 << (irq - chip->irq_start);
-       pr_debug("HTCPLD unmask %d %04x\n", irq, chip->irqs_enabled);
+       struct htcpld_chip *chip = irq_data_get_irq_chip_data(data);
+       chip->irqs_enabled |= 1 << (data->irq - chip->irq_start);
+       pr_debug("HTCPLD unmask %d %04x\n", data->irq, chip->irqs_enabled);
 }
 
-static int htcpld_set_type(unsigned int irq, unsigned int flags)
+static int htcpld_set_type(struct irq_data *data, unsigned int flags)
 {
-       struct irq_desc *d = irq_to_desc(irq);
+       struct irq_desc *d = irq_to_desc(data->irq);
 
        if (!d) {
-               pr_err("HTCPLD invalid IRQ: %d\n", irq);
+               pr_err("HTCPLD invalid IRQ: %d\n", data->irq);
                return -EINVAL;
        }
 
@@ -118,10 +118,10 @@ static int htcpld_set_type(unsigned int irq, unsigned int flags)
 }
 
 static struct irq_chip htcpld_muxed_chip = {
-       .name     = "htcpld",
-       .mask     = htcpld_mask,
-       .unmask   = htcpld_unmask,
-       .set_type = htcpld_set_type,
+       .name         = "htcpld",
+       .irq_mask     = htcpld_mask,
+       .irq_unmask   = htcpld_unmask,
+       .irq_set_type = htcpld_set_type,
 };
 
 /* To properly dispatch IRQ events, we need to read from the
@@ -235,7 +235,7 @@ static irqreturn_t htcpld_handler(int irq, void *dev)
  * and that work is scheduled in the set routine.  The kernel can then run
  * the I2C functions, which will sleep, in process context.
  */
-void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
+static void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
 {
        struct i2c_client *client;
        struct htcpld_chip *chip_data;
@@ -259,7 +259,7 @@ void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
        schedule_work(&(chip_data->set_val_work));
 }
 
-void htcpld_chip_set_ni(struct work_struct *work)
+static void htcpld_chip_set_ni(struct work_struct *work)
 {
        struct htcpld_chip *chip_data;
        struct i2c_client *client;
@@ -269,7 +269,7 @@ void htcpld_chip_set_ni(struct work_struct *work)
        i2c_smbus_read_byte_data(client, chip_data->cache_out);
 }
 
-int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
+static int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
 {
        struct htcpld_chip *chip_data;
        int val = 0;
@@ -316,7 +316,7 @@ static int htcpld_direction_input(struct gpio_chip *chip,
        return (offset < chip->ngpio) ? 0 : -EINVAL;
 }
 
-int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
+static int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
 {
        struct htcpld_chip *chip_data;
 
@@ -328,7 +328,7 @@ int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
                return -EINVAL;
 }
 
-void htcpld_chip_reset(struct i2c_client *client)
+static void htcpld_chip_reset(struct i2c_client *client)
 {
        struct htcpld_chip *chip_data = i2c_get_clientdata(client);
        if (!chip_data)
index 9dd1b33f227512ffc6cb2e833a2d721cf5a1bf6e..0cc59795f6004df02380608d28f300f85e07435a 100644 (file)
@@ -84,31 +84,30 @@ static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq,
        spin_unlock_irqrestore(&adc->lock, flags);
 }
 
-static void jz4740_adc_irq_mask(unsigned int irq)
+static void jz4740_adc_irq_mask(struct irq_data *data)
 {
-       struct jz4740_adc *adc = get_irq_chip_data(irq);
-       jz4740_adc_irq_set_masked(adc, irq, true);
+       struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
+       jz4740_adc_irq_set_masked(adc, data->irq, true);
 }
 
-static void jz4740_adc_irq_unmask(unsigned int irq)
+static void jz4740_adc_irq_unmask(struct irq_data *data)
 {
-       struct jz4740_adc *adc = get_irq_chip_data(irq);
-       jz4740_adc_irq_set_masked(adc, irq, false);
+       struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
+       jz4740_adc_irq_set_masked(adc, data->irq, false);
 }
 
-static void jz4740_adc_irq_ack(unsigned int irq)
+static void jz4740_adc_irq_ack(struct irq_data *data)
 {
-       struct jz4740_adc *adc = get_irq_chip_data(irq);
-
-       irq -= adc->irq_base;
+       struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
+       unsigned int irq = data->irq - adc->irq_base;
        writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS);
 }
 
 static struct irq_chip jz4740_adc_irq_chip = {
        .name = "jz4740-adc",
-       .mask = jz4740_adc_irq_mask,
-       .unmask = jz4740_adc_irq_unmask,
-       .ack = jz4740_adc_irq_ack,
+       .irq_mask = jz4740_adc_irq_mask,
+       .irq_unmask = jz4740_adc_irq_unmask,
+       .irq_ack = jz4740_adc_irq_ack,
 };
 
 static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
index 44695f5a180042887c7e6e93e925bdf582343721..0e998dc4e7d8cb0c9407a90cb615e9559d6d1b21 100644 (file)
@@ -407,16 +407,16 @@ static irqreturn_t max8925_tsc_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static void max8925_irq_lock(unsigned int irq)
+static void max8925_irq_lock(struct irq_data *data)
 {
-       struct max8925_chip *chip = get_irq_chip_data(irq);
+       struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
 
        mutex_lock(&chip->irq_lock);
 }
 
-static void max8925_irq_sync_unlock(unsigned int irq)
+static void max8925_irq_sync_unlock(struct irq_data *data)
 {
-       struct max8925_chip *chip = get_irq_chip_data(irq);
+       struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
        struct max8925_irq_data *irq_data;
        static unsigned char cache_chg[2] = {0xff, 0xff};
        static unsigned char cache_on[2] = {0xff, 0xff};
@@ -492,25 +492,25 @@ static void max8925_irq_sync_unlock(unsigned int irq)
        mutex_unlock(&chip->irq_lock);
 }
 
-static void max8925_irq_enable(unsigned int irq)
+static void max8925_irq_enable(struct irq_data *data)
 {
-       struct max8925_chip *chip = get_irq_chip_data(irq);
-       max8925_irqs[irq - chip->irq_base].enable
-               = max8925_irqs[irq - chip->irq_base].offs;
+       struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
+       max8925_irqs[data->irq - chip->irq_base].enable
+               = max8925_irqs[data->irq - chip->irq_base].offs;
 }
 
-static void max8925_irq_disable(unsigned int irq)
+static void max8925_irq_disable(struct irq_data *data)
 {
-       struct max8925_chip *chip = get_irq_chip_data(irq);
-       max8925_irqs[irq - chip->irq_base].enable = 0;
+       struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
+       max8925_irqs[data->irq - chip->irq_base].enable = 0;
 }
 
 static struct irq_chip max8925_irq_chip = {
        .name           = "max8925",
-       .bus_lock       = max8925_irq_lock,
-       .bus_sync_unlock = max8925_irq_sync_unlock,
-       .enable         = max8925_irq_enable,
-       .disable        = max8925_irq_disable,
+       .irq_bus_lock   = max8925_irq_lock,
+       .irq_bus_sync_unlock = max8925_irq_sync_unlock,
+       .irq_enable     = max8925_irq_enable,
+       .irq_disable    = max8925_irq_disable,
 };
 
 static int max8925_irq_init(struct max8925_chip *chip, int irq,
index 45bfe77b639baac66e94615ac43977e3be9eae4e..3903e1fbb3347b0792dc83a651b125163ad52c3c 100644 (file)
@@ -102,16 +102,16 @@ irq_to_max8998_irq(struct max8998_dev *max8998, int irq)
        return &max8998_irqs[irq - max8998->irq_base];
 }
 
-static void max8998_irq_lock(unsigned int irq)
+static void max8998_irq_lock(struct irq_data *data)
 {
-       struct max8998_dev *max8998 = get_irq_chip_data(irq);
+       struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
 
        mutex_lock(&max8998->irqlock);
 }
 
-static void max8998_irq_sync_unlock(unsigned int irq)
+static void max8998_irq_sync_unlock(struct irq_data *data)
 {
-       struct max8998_dev *max8998 = get_irq_chip_data(irq);
+       struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(max8998->irq_masks_cur); i++) {
@@ -129,28 +129,30 @@ static void max8998_irq_sync_unlock(unsigned int irq)
        mutex_unlock(&max8998->irqlock);
 }
 
-static void max8998_irq_unmask(unsigned int irq)
+static void max8998_irq_unmask(struct irq_data *data)
 {
-       struct max8998_dev *max8998 = get_irq_chip_data(irq);
-       struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq);
+       struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
+       struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
+                                                              data->irq);
 
        max8998->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
 }
 
-static void max8998_irq_mask(unsigned int irq)
+static void max8998_irq_mask(struct irq_data *data)
 {
-       struct max8998_dev *max8998 = get_irq_chip_data(irq);
-       struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq);
+       struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
+       struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
+                                                              data->irq);
 
        max8998->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
 }
 
 static struct irq_chip max8998_irq_chip = {
        .name = "max8998",
-       .bus_lock = max8998_irq_lock,
-       .bus_sync_unlock = max8998_irq_sync_unlock,
-       .mask = max8998_irq_mask,
-       .unmask = max8998_irq_unmask,
+       .irq_bus_lock = max8998_irq_lock,
+       .irq_bus_sync_unlock = max8998_irq_sync_unlock,
+       .irq_mask = max8998_irq_mask,
+       .irq_unmask = max8998_irq_unmask,
 };
 
 static irqreturn_t max8998_irq_thread(int irq, void *data)
@@ -181,6 +183,13 @@ static irqreturn_t max8998_irq_thread(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+int max8998_irq_resume(struct max8998_dev *max8998)
+{
+       if (max8998->irq && max8998->irq_base)
+               max8998_irq_thread(max8998->irq_base, max8998);
+       return 0;
+}
+
 int max8998_irq_init(struct max8998_dev *max8998)
 {
        int i;
index bb9977bebe782d10103a9235bd9e513bb7201f66..bbfe867326027f514b00645da907f5e31e96fabc 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
 #include <linux/mutex.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/max8998.h>
@@ -40,6 +42,14 @@ static struct mfd_cell max8998_devs[] = {
        },
 };
 
+static struct mfd_cell lp3974_devs[] = {
+       {
+               .name = "lp3974-pmic",
+       }, {
+               .name = "lp3974-rtc",
+       },
+};
+
 int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
 {
        struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
@@ -135,6 +145,7 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
        if (pdata) {
                max8998->ono = pdata->ono;
                max8998->irq_base = pdata->irq_base;
+               max8998->wakeup = pdata->wakeup;
        }
        mutex_init(&max8998->iolock);
 
@@ -143,9 +154,23 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
 
        max8998_irq_init(max8998);
 
-       ret = mfd_add_devices(max8998->dev, -1,
-                             max8998_devs, ARRAY_SIZE(max8998_devs),
-                             NULL, 0);
+       pm_runtime_set_active(max8998->dev);
+
+       switch (id->driver_data) {
+       case TYPE_LP3974:
+               ret = mfd_add_devices(max8998->dev, -1,
+                               lp3974_devs, ARRAY_SIZE(lp3974_devs),
+                               NULL, 0);
+               break;
+       case TYPE_MAX8998:
+               ret = mfd_add_devices(max8998->dev, -1,
+                               max8998_devs, ARRAY_SIZE(max8998_devs),
+                               NULL, 0);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
        if (ret < 0)
                goto err;
 
@@ -178,10 +203,113 @@ static const struct i2c_device_id max8998_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
 
+static int max8998_suspend(struct device *dev)
+{
+       struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+       struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
+
+       if (max8998->wakeup)
+               set_irq_wake(max8998->irq, 1);
+       return 0;
+}
+
+static int max8998_resume(struct device *dev)
+{
+       struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+       struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
+
+       if (max8998->wakeup)
+               set_irq_wake(max8998->irq, 0);
+       /*
+        * In LP3974, if IRQ registers are not "read & clear"
+        * when it's set during sleep, the interrupt becomes
+        * disabled.
+        */
+       return max8998_irq_resume(i2c_get_clientdata(i2c));
+}
+
+struct max8998_reg_dump {
+       u8      addr;
+       u8      val;
+};
+#define SAVE_ITEM(x)   { .addr = (x), .val = 0x0, }
+struct max8998_reg_dump max8998_dump[] = {
+       SAVE_ITEM(MAX8998_REG_IRQM1),
+       SAVE_ITEM(MAX8998_REG_IRQM2),
+       SAVE_ITEM(MAX8998_REG_IRQM3),
+       SAVE_ITEM(MAX8998_REG_IRQM4),
+       SAVE_ITEM(MAX8998_REG_STATUSM1),
+       SAVE_ITEM(MAX8998_REG_STATUSM2),
+       SAVE_ITEM(MAX8998_REG_CHGR1),
+       SAVE_ITEM(MAX8998_REG_CHGR2),
+       SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1),
+       SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1),
+       SAVE_ITEM(MAX8998_REG_BUCK_ACTIVE_DISCHARGE3),
+       SAVE_ITEM(MAX8998_REG_ONOFF1),
+       SAVE_ITEM(MAX8998_REG_ONOFF2),
+       SAVE_ITEM(MAX8998_REG_ONOFF3),
+       SAVE_ITEM(MAX8998_REG_ONOFF4),
+       SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE1),
+       SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE2),
+       SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE3),
+       SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE4),
+       SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE1),
+       SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE2),
+       SAVE_ITEM(MAX8998_REG_LDO2_LDO3),
+       SAVE_ITEM(MAX8998_REG_LDO4),
+       SAVE_ITEM(MAX8998_REG_LDO5),
+       SAVE_ITEM(MAX8998_REG_LDO6),
+       SAVE_ITEM(MAX8998_REG_LDO7),
+       SAVE_ITEM(MAX8998_REG_LDO8_LDO9),
+       SAVE_ITEM(MAX8998_REG_LDO10_LDO11),
+       SAVE_ITEM(MAX8998_REG_LDO12),
+       SAVE_ITEM(MAX8998_REG_LDO13),
+       SAVE_ITEM(MAX8998_REG_LDO14),
+       SAVE_ITEM(MAX8998_REG_LDO15),
+       SAVE_ITEM(MAX8998_REG_LDO16),
+       SAVE_ITEM(MAX8998_REG_LDO17),
+       SAVE_ITEM(MAX8998_REG_BKCHR),
+       SAVE_ITEM(MAX8998_REG_LBCNFG1),
+       SAVE_ITEM(MAX8998_REG_LBCNFG2),
+};
+/* Save registers before hibernation */
+static int max8998_freeze(struct device *dev)
+{
+       struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
+               max8998_read_reg(i2c, max8998_dump[i].addr,
+                               &max8998_dump[i].val);
+
+       return 0;
+}
+
+/* Restore registers after hibernation */
+static int max8998_restore(struct device *dev)
+{
+       struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
+               max8998_write_reg(i2c, max8998_dump[i].addr,
+                               max8998_dump[i].val);
+
+       return 0;
+}
+
+const struct dev_pm_ops max8998_pm = {
+       .suspend = max8998_suspend,
+       .resume = max8998_resume,
+       .freeze = max8998_freeze,
+       .restore = max8998_restore,
+};
+
 static struct i2c_driver max8998_i2c_driver = {
        .driver = {
                   .name = "max8998",
                   .owner = THIS_MODULE,
+                  .pm = &max8998_pm,
        },
        .probe = max8998_i2c_probe,
        .remove = max8998_i2c_remove,
index a2ac2ed6d64c64467e12ad6822f543cfe609a853..b9fcaf0004da79142414ef54d53f866122df1a1e 100644 (file)
@@ -749,7 +749,7 @@ static int mc13xxx_probe(struct spi_device *spi)
        if (ret) {
 err_mask:
 err_revision:
-               mutex_unlock(&mc13xxx->lock);
+               mc13xxx_unlock(mc13xxx);
                dev_set_drvdata(&spi->dev, NULL);
                kfree(mc13xxx);
                return ret;
index ec99f681e77368b33bfa23718663c520508e0f6b..d83ad0f141af3ef7bc26d8322e508a46351d8cf9 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 #include <linux/mfd/core.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
 static int mfd_add_device(struct device *parent, int id,
@@ -82,6 +83,9 @@ static int mfd_add_device(struct device *parent, int id,
        if (ret)
                goto fail_res;
 
+       if (cell->pm_runtime_no_callbacks)
+               pm_runtime_no_callbacks(&pdev->dev);
+
        kfree(res);
 
        return 0;
index bc9275c12133f2817c54dafb04fd1856a54870c1..5de3a760ea1ef946075c1de485a645bb8121ae0d 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/sm501-regs.h>
 #include <linux/serial_8250.h>
 
-#include <asm/io.h>
+#include <linux/io.h>
 
 struct sm501_device {
        struct list_head                list;
@@ -745,11 +745,8 @@ static int sm501_register_device(struct sm501_devdata *sm,
        int ret;
 
        for (ptr = 0; ptr < pdev->num_resources; ptr++) {
-               printk(KERN_DEBUG "%s[%d] flags %08lx: %08llx..%08llx\n",
-                      pdev->name, ptr,
-                      pdev->resource[ptr].flags,
-                      (unsigned long long)pdev->resource[ptr].start,
-                      (unsigned long long)pdev->resource[ptr].end);
+               printk(KERN_DEBUG "%s[%d] %pR\n",
+                      pdev->name, ptr, &pdev->resource[ptr]);
        }
 
        ret = platform_device_register(pdev);
index b11487f1e1cb68de4dcabcf3ba584426988eda18..3e5732b58c49900efd5da19ad14a72f659df92f5 100644 (file)
@@ -699,16 +699,16 @@ static irqreturn_t stmpe_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static void stmpe_irq_lock(unsigned int irq)
+static void stmpe_irq_lock(struct irq_data *data)
 {
-       struct stmpe *stmpe = get_irq_chip_data(irq);
+       struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
 
        mutex_lock(&stmpe->irq_lock);
 }
 
-static void stmpe_irq_sync_unlock(unsigned int irq)
+static void stmpe_irq_sync_unlock(struct irq_data *data)
 {
-       struct stmpe *stmpe = get_irq_chip_data(irq);
+       struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
        struct stmpe_variant_info *variant = stmpe->variant;
        int num = DIV_ROUND_UP(variant->num_irqs, 8);
        int i;
@@ -727,20 +727,20 @@ static void stmpe_irq_sync_unlock(unsigned int irq)
        mutex_unlock(&stmpe->irq_lock);
 }
 
-static void stmpe_irq_mask(unsigned int irq)
+static void stmpe_irq_mask(struct irq_data *data)
 {
-       struct stmpe *stmpe = get_irq_chip_data(irq);
-       int offset = irq - stmpe->irq_base;
+       struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
+       int offset = data->irq - stmpe->irq_base;
        int regoffset = offset / 8;
        int mask = 1 << (offset % 8);
 
        stmpe->ier[regoffset] &= ~mask;
 }
 
-static void stmpe_irq_unmask(unsigned int irq)
+static void stmpe_irq_unmask(struct irq_data *data)
 {
-       struct stmpe *stmpe = get_irq_chip_data(irq);
-       int offset = irq - stmpe->irq_base;
+       struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
+       int offset = data->irq - stmpe->irq_base;
        int regoffset = offset / 8;
        int mask = 1 << (offset % 8);
 
@@ -749,10 +749,10 @@ static void stmpe_irq_unmask(unsigned int irq)
 
 static struct irq_chip stmpe_irq_chip = {
        .name                   = "stmpe",
-       .bus_lock               = stmpe_irq_lock,
-       .bus_sync_unlock        = stmpe_irq_sync_unlock,
-       .mask                   = stmpe_irq_mask,
-       .unmask                 = stmpe_irq_unmask,
+       .irq_bus_lock           = stmpe_irq_lock,
+       .irq_bus_sync_unlock    = stmpe_irq_sync_unlock,
+       .irq_mask               = stmpe_irq_mask,
+       .irq_unmask             = stmpe_irq_unmask,
 };
 
 static int __devinit stmpe_irq_init(struct stmpe *stmpe)
index 006c121f3f0d2f2bca2a87f05f6c65ca3a063987..9caeb4ac6ea6c2b1fa72eb63a8c678fefef28b14 100644 (file)
@@ -199,37 +199,37 @@ static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc)
                                generic_handle_irq(irq_base + i);
 }
 
-static void t7l66xb_irq_mask(unsigned int irq)
+static void t7l66xb_irq_mask(struct irq_data *data)
 {
-       struct t7l66xb *t7l66xb = get_irq_chip_data(irq);
+       struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
        unsigned long                   flags;
        u8 imr;
 
        spin_lock_irqsave(&t7l66xb->lock, flags);
        imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
-       imr |= 1 << (irq - t7l66xb->irq_base);
+       imr |= 1 << (data->irq - t7l66xb->irq_base);
        tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
        spin_unlock_irqrestore(&t7l66xb->lock, flags);
 }
 
-static void t7l66xb_irq_unmask(unsigned int irq)
+static void t7l66xb_irq_unmask(struct irq_data *data)
 {
-       struct t7l66xb *t7l66xb = get_irq_chip_data(irq);
+       struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
        unsigned long flags;
        u8 imr;
 
        spin_lock_irqsave(&t7l66xb->lock, flags);
        imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
-       imr &= ~(1 << (irq - t7l66xb->irq_base));
+       imr &= ~(1 << (data->irq - t7l66xb->irq_base));
        tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
        spin_unlock_irqrestore(&t7l66xb->lock, flags);
 }
 
 static struct irq_chip t7l66xb_chip = {
-       .name   = "t7l66xb",
-       .ack    = t7l66xb_irq_mask,
-       .mask   = t7l66xb_irq_mask,
-       .unmask = t7l66xb_irq_unmask,
+       .name           = "t7l66xb",
+       .irq_ack        = t7l66xb_irq_mask,
+       .irq_mask       = t7l66xb_irq_mask,
+       .irq_unmask     = t7l66xb_irq_unmask,
 };
 
 /*--------------------------------------------------------------------------*/
index 1ea80d8ad915c4487ab42762204755d1b6ec983c..9a238633a54d4b7e0c594e04a5b6c35738b03e3b 100644 (file)
@@ -527,41 +527,41 @@ tc6393xb_irq(unsigned int irq, struct irq_desc *desc)
                }
 }
 
-static void tc6393xb_irq_ack(unsigned int irq)
+static void tc6393xb_irq_ack(struct irq_data *data)
 {
 }
 
-static void tc6393xb_irq_mask(unsigned int irq)
+static void tc6393xb_irq_mask(struct irq_data *data)
 {
-       struct tc6393xb *tc6393xb = get_irq_chip_data(irq);
+       struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data);
        unsigned long flags;
        u8 imr;
 
        spin_lock_irqsave(&tc6393xb->lock, flags);
        imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
-       imr |= 1 << (irq - tc6393xb->irq_base);
+       imr |= 1 << (data->irq - tc6393xb->irq_base);
        tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
        spin_unlock_irqrestore(&tc6393xb->lock, flags);
 }
 
-static void tc6393xb_irq_unmask(unsigned int irq)
+static void tc6393xb_irq_unmask(struct irq_data *data)
 {
-       struct tc6393xb *tc6393xb = get_irq_chip_data(irq);
+       struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data);
        unsigned long flags;
        u8 imr;
 
        spin_lock_irqsave(&tc6393xb->lock, flags);
        imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
-       imr &= ~(1 << (irq - tc6393xb->irq_base));
+       imr &= ~(1 << (data->irq - tc6393xb->irq_base));
        tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
        spin_unlock_irqrestore(&tc6393xb->lock, flags);
 }
 
 static struct irq_chip tc6393xb_chip = {
-       .name   = "tc6393xb",
-       .ack    = tc6393xb_irq_ack,
-       .mask   = tc6393xb_irq_mask,
-       .unmask = tc6393xb_irq_unmask,
+       .name           = "tc6393xb",
+       .irq_ack        = tc6393xb_irq_ack,
+       .irq_mask       = tc6393xb_irq_mask,
+       .irq_unmask     = tc6393xb_irq_unmask,
 };
 
 static void tc6393xb_attach_irq(struct platform_device *dev)
index 90187fe33e0449d15b569482bd843f104735030a..93d5fdf020c7eaa90dbf4d1eee41de216873d78e 100644 (file)
@@ -34,7 +34,7 @@
 
 #include <linux/i2c/tps65010.h>
 
-#include <asm/gpio.h>
+#include <linux/gpio.h>
 
 
 /*-------------------------------------------------------------------------*/
index b4931ab349299e1205ebd70c9023a9bba344f366..627cf577b16d2ea2f696a7806de74ad950494618 100644 (file)
@@ -46,8 +46,6 @@
 
 /* device id */
 #define TPS6586X_VERSIONCRC    0xcd
-#define TPS658621A_VERSIONCRC  0x15
-#define TPS658621C_VERSIONCRC  0x2c
 
 struct tps6586x_irq_data {
        u8      mask_reg;
@@ -325,37 +323,37 @@ static int tps6586x_remove_subdevs(struct tps6586x *tps6586x)
        return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
 }
 
-static void tps6586x_irq_lock(unsigned int irq)
+static void tps6586x_irq_lock(struct irq_data *data)
 {
-       struct tps6586x *tps6586x = get_irq_chip_data(irq);
+       struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data);
 
        mutex_lock(&tps6586x->irq_lock);
 }
 
-static void tps6586x_irq_enable(unsigned int irq)
+static void tps6586x_irq_enable(struct irq_data *irq_data)
 {
-       struct tps6586x *tps6586x = get_irq_chip_data(irq);
-       unsigned int __irq = irq - tps6586x->irq_base;
+       struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->irq - tps6586x->irq_base;
        const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
 
        tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask;
        tps6586x->irq_en |= (1 << __irq);
 }
 
-static void tps6586x_irq_disable(unsigned int irq)
+static void tps6586x_irq_disable(struct irq_data *irq_data)
 {
-       struct tps6586x *tps6586x = get_irq_chip_data(irq);
+       struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
 
-       unsigned int __irq = irq - tps6586x->irq_base;
+       unsigned int __irq = irq_data->irq - tps6586x->irq_base;
        const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
 
        tps6586x->mask_reg[data->mask_reg] |= data->mask_mask;
        tps6586x->irq_en &= ~(1 << __irq);
 }
 
-static void tps6586x_irq_sync_unlock(unsigned int irq)
+static void tps6586x_irq_sync_unlock(struct irq_data *data)
 {
-       struct tps6586x *tps6586x = get_irq_chip_data(irq);
+       struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) {
@@ -421,10 +419,10 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq,
        tps6586x->irq_base = irq_base;
 
        tps6586x->irq_chip.name = "tps6586x";
-       tps6586x->irq_chip.enable = tps6586x_irq_enable;
-       tps6586x->irq_chip.disable = tps6586x_irq_disable;
-       tps6586x->irq_chip.bus_lock = tps6586x_irq_lock;
-       tps6586x->irq_chip.bus_sync_unlock = tps6586x_irq_sync_unlock;
+       tps6586x->irq_chip.irq_enable = tps6586x_irq_enable;
+       tps6586x->irq_chip.irq_disable = tps6586x_irq_disable;
+       tps6586x->irq_chip.irq_bus_lock = tps6586x_irq_lock;
+       tps6586x->irq_chip.irq_bus_sync_unlock = tps6586x_irq_sync_unlock;
 
        for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) {
                int __irq = i + tps6586x->irq_base;
@@ -498,11 +496,7 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
                return -EIO;
        }
 
-       if ((ret != TPS658621A_VERSIONCRC) &&
-           (ret != TPS658621C_VERSIONCRC)) {
-               dev_err(&client->dev, "Unsupported chip ID: %x\n", ret);
-               return -ENODEV;
-       }
+       dev_info(&client->dev, "VERSIONCRC is %02x\n", ret);
 
        tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL);
        if (tps6586x == NULL)
index 12abd5b924b3a8729c938029abaf7600a63b3f6b..a35fa7dcbf53b6778696aa81d5a82a3d145ab148 100644 (file)
@@ -1003,7 +1003,7 @@ static int twl_remove(struct i2c_client *client)
 }
 
 /* NOTE:  this driver only handles a single twl4030/tps659x0 chip */
-static int __init
+static int __devinit
 twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        int                             status;
index 5d3a1478004b8a4448ccbf2c4a47030609951872..63a30e88908f8e903df95883c3f571e91fccff9e 100644 (file)
@@ -599,38 +599,38 @@ static void twl4030_sih_do_edge(struct work_struct *work)
  * completion, potentially including some re-ordering, of these requests.
  */
 
-static void twl4030_sih_mask(unsigned irq)
+static void twl4030_sih_mask(struct irq_data *data)
 {
-       struct sih_agent *sih = get_irq_chip_data(irq);
+       struct sih_agent *sih = irq_data_get_irq_chip_data(data);
        unsigned long flags;
 
        spin_lock_irqsave(&sih_agent_lock, flags);
-       sih->imr |= BIT(irq - sih->irq_base);
+       sih->imr |= BIT(data->irq - sih->irq_base);
        sih->imr_change_pending = true;
        queue_work(wq, &sih->mask_work);
        spin_unlock_irqrestore(&sih_agent_lock, flags);
 }
 
-static void twl4030_sih_unmask(unsigned irq)
+static void twl4030_sih_unmask(struct irq_data *data)
 {
-       struct sih_agent *sih = get_irq_chip_data(irq);
+       struct sih_agent *sih = irq_data_get_irq_chip_data(data);
        unsigned long flags;
 
        spin_lock_irqsave(&sih_agent_lock, flags);
-       sih->imr &= ~BIT(irq - sih->irq_base);
+       sih->imr &= ~BIT(data->irq - sih->irq_base);
        sih->imr_change_pending = true;
        queue_work(wq, &sih->mask_work);
        spin_unlock_irqrestore(&sih_agent_lock, flags);
 }
 
-static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
+static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger)
 {
-       struct sih_agent *sih = get_irq_chip_data(irq);
-       struct irq_desc *desc = irq_to_desc(irq);
+       struct sih_agent *sih = irq_data_get_irq_chip_data(data);
+       struct irq_desc *desc = irq_to_desc(data->irq);
        unsigned long flags;
 
        if (!desc) {
-               pr_err("twl4030: Invalid IRQ: %d\n", irq);
+               pr_err("twl4030: Invalid IRQ: %d\n", data->irq);
                return -EINVAL;
        }
 
@@ -641,7 +641,7 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
        if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) {
                desc->status &= ~IRQ_TYPE_SENSE_MASK;
                desc->status |= trigger;
-               sih->edge_change |= BIT(irq - sih->irq_base);
+               sih->edge_change |= BIT(data->irq - sih->irq_base);
                queue_work(wq, &sih->edge_work);
        }
        spin_unlock_irqrestore(&sih_agent_lock, flags);
@@ -650,9 +650,9 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
 
 static struct irq_chip twl4030_sih_irq_chip = {
        .name           = "twl4030",
-       .mask           = twl4030_sih_mask,
-       .unmask         = twl4030_sih_unmask,
-       .set_type       = twl4030_sih_set_type,
+       .irq_mask       = twl4030_sih_mask,
+       .irq_unmask     = twl4030_sih_unmask,
+       .irq_set_type   = twl4030_sih_set_type,
 };
 
 /*----------------------------------------------------------------------*/
index 06c8955907e9de84876aa9df73107288244482e5..4082ed73613f98a6abd0fb0a1b8463f0d45a788e 100644 (file)
@@ -332,7 +332,7 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
         */
        twl6030_irq_chip = dummy_irq_chip;
        twl6030_irq_chip.name = "twl6030";
-       twl6030_irq_chip.set_type = NULL;
+       twl6030_irq_chip.irq_set_type = NULL;
 
        for (i = irq_base; i < irq_end; i++) {
                set_irq_chip_and_handler(i, &twl6030_irq_chip,
index ebb059765eddfd6e2e6afee4c81b84a65cfcc8b7..348052aa5dbfac31b3bb8496d6d2f35ac164c454 100644 (file)
@@ -112,7 +112,7 @@ out:
        return ret;
 }
 
-static void vx855_remove(struct pci_dev *pdev)
+static void __devexit vx855_remove(struct pci_dev *pdev)
 {
        mfd_remove_devices(&pdev->dev);
        pci_disable_device(pdev);
index 76cadcf3b1fee2ccf996d318c01137c53ba852a7..3fe9a58fe6c76a304a2eb61e93c375840d4b3d2d 100644 (file)
@@ -1541,6 +1541,12 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
                dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev);
                break;
 
+       case WM8326:
+               parent = WM8326;
+               wm831x->num_gpio = 12;
+               dev_info(wm831x->dev, "WM8326 revision %c\n", 'A' + rev);
+               break;
+
        default:
                dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
                ret = -EINVAL;
@@ -1610,18 +1616,9 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
                break;
 
        case WM8320:
-               ret = mfd_add_devices(wm831x->dev, -1,
-                                     wm8320_devs, ARRAY_SIZE(wm8320_devs),
-                                     NULL, 0);
-               break;
-
        case WM8321:
-               ret = mfd_add_devices(wm831x->dev, -1,
-                                     wm8320_devs, ARRAY_SIZE(wm8320_devs),
-                                     NULL, 0);
-               break;
-
        case WM8325:
+       case WM8326:
                ret = mfd_add_devices(wm831x->dev, -1,
                                      wm8320_devs, ARRAY_SIZE(wm8320_devs),
                                      NULL, wm831x->irq_base);
index 156b19859e81701d57090f2f522f43238c987604..3853fa8e7cc267dd4496a1e9101c79fc6f2c9082 100644 (file)
@@ -94,9 +94,9 @@ static int wm831x_i2c_remove(struct i2c_client *i2c)
        return 0;
 }
 
-static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
+static int wm831x_i2c_suspend(struct device *dev)
 {
-       struct wm831x *wm831x = i2c_get_clientdata(i2c);
+       struct wm831x *wm831x = dev_get_drvdata(dev);
 
        return wm831x_device_suspend(wm831x);
 }
@@ -108,19 +108,23 @@ static const struct i2c_device_id wm831x_i2c_id[] = {
        { "wm8320", WM8320 },
        { "wm8321", WM8321 },
        { "wm8325", WM8325 },
+       { "wm8326", WM8326 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
 
+static const struct dev_pm_ops wm831x_pm_ops = {
+       .suspend = wm831x_i2c_suspend,
+};
 
 static struct i2c_driver wm831x_i2c_driver = {
        .driver = {
-                  .name = "wm831x",
-                  .owner = THIS_MODULE,
+               .name = "wm831x",
+               .owner = THIS_MODULE,
+               .pm = &wm831x_pm_ops,
        },
        .probe = wm831x_i2c_probe,
        .remove = wm831x_i2c_remove,
-       .suspend = wm831x_i2c_suspend,
        .id_table = wm831x_i2c_id,
 };
 
index 294183b6260b1facff3d26764eb3cea8c6d4b011..f7192d438aabf17f209ec9959aaa7f7db98078d4 100644 (file)
@@ -345,16 +345,16 @@ static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
        return &wm831x_irqs[irq - wm831x->irq_base];
 }
 
-static void wm831x_irq_lock(unsigned int irq)
+static void wm831x_irq_lock(struct irq_data *data)
 {
-       struct wm831x *wm831x = get_irq_chip_data(irq);
+       struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
 
        mutex_lock(&wm831x->irq_lock);
 }
 
-static void wm831x_irq_sync_unlock(unsigned int irq)
+static void wm831x_irq_sync_unlock(struct irq_data *data)
 {
-       struct wm831x *wm831x = get_irq_chip_data(irq);
+       struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
@@ -371,28 +371,30 @@ static void wm831x_irq_sync_unlock(unsigned int irq)
        mutex_unlock(&wm831x->irq_lock);
 }
 
-static void wm831x_irq_unmask(unsigned int irq)
+static void wm831x_irq_unmask(struct irq_data *data)
 {
-       struct wm831x *wm831x = get_irq_chip_data(irq);
-       struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
+       struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+       struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
+                                                            data->irq);
 
        wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
 }
 
-static void wm831x_irq_mask(unsigned int irq)
+static void wm831x_irq_mask(struct irq_data *data)
 {
-       struct wm831x *wm831x = get_irq_chip_data(irq);
-       struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
+       struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+       struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
+                                                            data->irq);
 
        wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
 }
 
-static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
+static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
 {
-       struct wm831x *wm831x = get_irq_chip_data(irq);
-       int val;
+       struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+       int val, irq;
 
-       irq = irq - wm831x->irq_base;
+       irq = data->irq - wm831x->irq_base;
 
        if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) {
                /* Ignore internal-only IRQs */
@@ -421,12 +423,12 @@ static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
 }
 
 static struct irq_chip wm831x_irq_chip = {
-       .name = "wm831x",
-       .bus_lock = wm831x_irq_lock,
-       .bus_sync_unlock = wm831x_irq_sync_unlock,
-       .mask = wm831x_irq_mask,
-       .unmask = wm831x_irq_unmask,
-       .set_type = wm831x_irq_set_type,
+       .name                   = "wm831x",
+       .irq_bus_lock           = wm831x_irq_lock,
+       .irq_bus_sync_unlock    = wm831x_irq_sync_unlock,
+       .irq_mask               = wm831x_irq_mask,
+       .irq_unmask             = wm831x_irq_unmask,
+       .irq_set_type           = wm831x_irq_set_type,
 };
 
 /* The processing of the primary interrupt occurs in a thread so that
@@ -515,6 +517,17 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
                return 0;
        }
 
+       /* Try to flag /IRQ as a wake source; there are a number of
+        * unconditional wake sources in the PMIC so this isn't
+        * conditional but we don't actually care *too* much if it
+        * fails.
+        */
+       ret = enable_irq_wake(irq);
+       if (ret != 0) {
+               dev_warn(wm831x->dev, "Can't enable IRQ as wake source: %d\n",
+                        ret);
+       }
+
        wm831x->irq = irq;
        wm831x->irq_base = pdata->irq_base;
 
index 2789b151b0f9d9940f2eb18f570b599ded4374ad..0a8f772be88c88aff35e731a7eef5ae607eefcdb 100644 (file)
@@ -81,6 +81,8 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
                type = WM8321;
        else if (strcmp(spi->modalias, "wm8325") == 0)
                type = WM8325;
+       else if (strcmp(spi->modalias, "wm8326") == 0)
+               type = WM8326;
        else {
                dev_err(&spi->dev, "Unknown device type\n");
                return -EINVAL;
@@ -184,6 +186,17 @@ static struct spi_driver wm8325_spi_driver = {
        .suspend        = wm831x_spi_suspend,
 };
 
+static struct spi_driver wm8326_spi_driver = {
+       .driver = {
+               .name   = "wm8326",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm831x_spi_probe,
+       .remove         = __devexit_p(wm831x_spi_remove),
+       .suspend        = wm831x_spi_suspend,
+};
+
 static int __init wm831x_spi_init(void)
 {
        int ret;
@@ -212,12 +225,17 @@ static int __init wm831x_spi_init(void)
        if (ret != 0)
                pr_err("Failed to register WM8325 SPI driver: %d\n", ret);
 
+       ret = spi_register_driver(&wm8326_spi_driver);
+       if (ret != 0)
+               pr_err("Failed to register WM8326 SPI driver: %d\n", ret);
+
        return 0;
 }
 subsys_initcall(wm831x_spi_init);
 
 static void __exit wm831x_spi_exit(void)
 {
+       spi_unregister_driver(&wm8326_spi_driver);
        spi_unregister_driver(&wm8325_spi_driver);
        spi_unregister_driver(&wm8321_spi_driver);
        spi_unregister_driver(&wm8320_spi_driver);
index f56c9adf94930f65d057946d86ba4b0d471dd196..5839966ebd85bfbd73b8ee229e0ee666c4b98cd2 100644 (file)
@@ -417,16 +417,16 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data)
        return IRQ_HANDLED;
 }
 
-static void wm8350_irq_lock(unsigned int irq)
+static void wm8350_irq_lock(struct irq_data *data)
 {
-       struct wm8350 *wm8350 = get_irq_chip_data(irq);
+       struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
 
        mutex_lock(&wm8350->irq_lock);
 }
 
-static void wm8350_irq_sync_unlock(unsigned int irq)
+static void wm8350_irq_sync_unlock(struct irq_data *data)
 {
-       struct wm8350 *wm8350 = get_irq_chip_data(irq);
+       struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
@@ -442,28 +442,30 @@ static void wm8350_irq_sync_unlock(unsigned int irq)
        mutex_unlock(&wm8350->irq_lock);
 }
 
-static void wm8350_irq_enable(unsigned int irq)
+static void wm8350_irq_enable(struct irq_data *data)
 {
-       struct wm8350 *wm8350 = get_irq_chip_data(irq);
-       struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
+       struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
+       struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
+                                                            data->irq);
 
        wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask;
 }
 
-static void wm8350_irq_disable(unsigned int irq)
+static void wm8350_irq_disable(struct irq_data *data)
 {
-       struct wm8350 *wm8350 = get_irq_chip_data(irq);
-       struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
+       struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
+       struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
+                                                            data->irq);
 
        wm8350->irq_masks[irq_data->reg] |= irq_data->mask;
 }
 
 static struct irq_chip wm8350_irq_chip = {
-       .name = "wm8350",
-       .bus_lock = wm8350_irq_lock,
-       .bus_sync_unlock = wm8350_irq_sync_unlock,
-       .disable = wm8350_irq_disable,
-       .enable = wm8350_irq_enable,
+       .name                   = "wm8350",
+       .irq_bus_lock           = wm8350_irq_lock,
+       .irq_bus_sync_unlock    = wm8350_irq_sync_unlock,
+       .irq_disable            = wm8350_irq_disable,
+       .irq_enable             = wm8350_irq_enable,
 };
 
 int wm8350_irq_init(struct wm8350 *wm8350, int irq,
index 8d221ba5e38df5dd293d460bf7ff564124eb1262..41233c7fa581137fbfc0020e40022e222489b695 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/mfd/core.h>
+#include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/machine.h>
 
@@ -169,8 +170,16 @@ out:
 EXPORT_SYMBOL_GPL(wm8994_set_bits);
 
 static struct mfd_cell wm8994_regulator_devs[] = {
-       { .name = "wm8994-ldo", .id = 1 },
-       { .name = "wm8994-ldo", .id = 2 },
+       {
+               .name = "wm8994-ldo",
+               .id = 1,
+               .pm_runtime_no_callbacks = true,
+       },
+       {
+               .name = "wm8994-ldo",
+               .id = 2,
+               .pm_runtime_no_callbacks = true,
+       },
 };
 
 static struct resource wm8994_codec_resources[] = {
@@ -200,6 +209,7 @@ static struct mfd_cell wm8994_devs[] = {
                .name = "wm8994-gpio",
                .num_resources = ARRAY_SIZE(wm8994_gpio_resources),
                .resources = wm8994_gpio_resources,
+               .pm_runtime_no_callbacks = true,
        },
 };
 
@@ -231,7 +241,7 @@ static const char *wm8958_main_supplies[] = {
 };
 
 #ifdef CONFIG_PM
-static int wm8994_device_suspend(struct device *dev)
+static int wm8994_suspend(struct device *dev)
 {
        struct wm8994 *wm8994 = dev_get_drvdata(dev);
        int ret;
@@ -261,7 +271,7 @@ static int wm8994_device_suspend(struct device *dev)
        return 0;
 }
 
-static int wm8994_device_resume(struct device *dev)
+static int wm8994_resume(struct device *dev)
 {
        struct wm8994 *wm8994 = dev_get_drvdata(dev);
        int ret;
@@ -471,6 +481,9 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                goto err_irq;
        }
 
+       pm_runtime_enable(wm8994->dev);
+       pm_runtime_resume(wm8994->dev);
+
        return 0;
 
 err_irq:
@@ -490,6 +503,7 @@ err:
 
 static void wm8994_device_exit(struct wm8994 *wm8994)
 {
+       pm_runtime_disable(wm8994->dev);
        mfd_remove_devices(wm8994->dev);
        wm8994_irq_exit(wm8994);
        regulator_bulk_disable(wm8994->num_supplies,
@@ -573,21 +587,6 @@ static int wm8994_i2c_remove(struct i2c_client *i2c)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int wm8994_i2c_suspend(struct i2c_client *i2c, pm_message_t state)
-{
-       return wm8994_device_suspend(&i2c->dev);
-}
-
-static int wm8994_i2c_resume(struct i2c_client *i2c)
-{
-       return wm8994_device_resume(&i2c->dev);
-}
-#else
-#define wm8994_i2c_suspend NULL
-#define wm8994_i2c_resume NULL
-#endif
-
 static const struct i2c_device_id wm8994_i2c_id[] = {
        { "wm8994", WM8994 },
        { "wm8958", WM8958 },
@@ -595,15 +594,16 @@ static const struct i2c_device_id wm8994_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id);
 
+UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, NULL);
+
 static struct i2c_driver wm8994_i2c_driver = {
        .driver = {
-                  .name = "wm8994",
-                  .owner = THIS_MODULE,
+               .name = "wm8994",
+               .owner = THIS_MODULE,
+               .pm = &wm8994_pm_ops,
        },
        .probe = wm8994_i2c_probe,
        .remove = wm8994_i2c_remove,
-       .suspend = wm8994_i2c_suspend,
-       .resume = wm8994_i2c_resume,
        .id_table = wm8994_i2c_id,
 };
 
index 8400eb1ee5db58869f35ab814bd4c19c6a1269b9..29e8faf9c01c79f37dada4b1d0581d92f4e49e90 100644 (file)
@@ -156,16 +156,16 @@ static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994,
        return &wm8994_irqs[irq - wm8994->irq_base];
 }
 
-static void wm8994_irq_lock(unsigned int irq)
+static void wm8994_irq_lock(struct irq_data *data)
 {
-       struct wm8994 *wm8994 = get_irq_chip_data(irq);
+       struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
 
        mutex_lock(&wm8994->irq_lock);
 }
 
-static void wm8994_irq_sync_unlock(unsigned int irq)
+static void wm8994_irq_sync_unlock(struct irq_data *data)
 {
-       struct wm8994 *wm8994 = get_irq_chip_data(irq);
+       struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
@@ -182,28 +182,30 @@ static void wm8994_irq_sync_unlock(unsigned int irq)
        mutex_unlock(&wm8994->irq_lock);
 }
 
-static void wm8994_irq_unmask(unsigned int irq)
+static void wm8994_irq_unmask(struct irq_data *data)
 {
-       struct wm8994 *wm8994 = get_irq_chip_data(irq);
-       struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
+       struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
+       struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
+                                                            data->irq);
 
        wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
 }
 
-static void wm8994_irq_mask(unsigned int irq)
+static void wm8994_irq_mask(struct irq_data *data)
 {
-       struct wm8994 *wm8994 = get_irq_chip_data(irq);
-       struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
+       struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
+       struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
+                                                            data->irq);
 
        wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
 }
 
 static struct irq_chip wm8994_irq_chip = {
-       .name = "wm8994",
-       .bus_lock = wm8994_irq_lock,
-       .bus_sync_unlock = wm8994_irq_sync_unlock,
-       .mask = wm8994_irq_mask,
-       .unmask = wm8994_irq_unmask,
+       .name                   = "wm8994",
+       .irq_bus_lock           = wm8994_irq_lock,
+       .irq_bus_sync_unlock    = wm8994_irq_sync_unlock,
+       .irq_mask               = wm8994_irq_mask,
+       .irq_unmask             = wm8994_irq_unmask,
 };
 
 /* The processing of the primary interrupt occurs in a thread so that
index 1e1a4be8eb6cc11e22a5a40e509bcfd74bd45c80..cc8e49db45fee026c023272f59f59ede0a1667dc 100644 (file)
@@ -64,7 +64,7 @@ config ATMEL_PWM
 
 config AB8500_PWM
        bool "AB8500 PWM support"
-       depends on AB8500_CORE
+       depends on AB8500_CORE && ARCH_U8500
        select HAVE_PWM
        help
          This driver exports functions to enable/disble/config/free Pulse
index 6f6218061b0dfff3adc3b5cc862da3162d6b0077..d02d302ee6d57e47d14b8056838f55b2093b8d98 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
-#include <linux/pci.h>
+#include <linux/platform_device.h>
 #include <linux/cs5535.h>
 #include <linux/slab.h>
 
 #define DRV_NAME "cs5535-mfgpt"
-#define MFGPT_BAR 2
 
 static int mfgpt_reset_timers;
 module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644);
@@ -37,7 +36,7 @@ static struct cs5535_mfgpt_chip {
        DECLARE_BITMAP(avail, MFGPT_MAX_TIMERS);
        resource_size_t base;
 
-       struct pci_dev *pdev;
+       struct platform_device *pdev;
        spinlock_t lock;
        int initialized;
 } cs5535_mfgpt_chip;
@@ -290,10 +289,10 @@ static int __init scan_timers(struct cs5535_mfgpt_chip *mfgpt)
        return timers;
 }
 
-static int __init cs5535_mfgpt_probe(struct pci_dev *pdev,
-               const struct pci_device_id *pci_id)
+static int __devinit cs5535_mfgpt_probe(struct platform_device *pdev)
 {
-       int err, t;
+       struct resource *res;
+       int err = -EIO, t;
 
        /* There are two ways to get the MFGPT base address; one is by
         * fetching it from MSR_LBAR_MFGPT, the other is by reading the
@@ -302,29 +301,27 @@ static int __init cs5535_mfgpt_probe(struct pci_dev *pdev,
         * it turns out to be unreliable in the face of crappy BIOSes, we
         * can always go back to using MSRs.. */
 
-       err = pci_enable_device_io(pdev);
-       if (err) {
-               dev_err(&pdev->dev, "can't enable device IO\n");
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "can't fetch device resource info\n");
                goto done;
        }
 
-       err = pci_request_region(pdev, MFGPT_BAR, DRV_NAME);
-       if (err) {
-               dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", MFGPT_BAR);
+       if (!request_region(res->start, resource_size(res), pdev->name)) {
+               dev_err(&pdev->dev, "can't request region\n");
                goto done;
        }
 
        /* set up the driver-specific struct */
-       cs5535_mfgpt_chip.base = pci_resource_start(pdev, MFGPT_BAR);
+       cs5535_mfgpt_chip.base = res->start;
        cs5535_mfgpt_chip.pdev = pdev;
        spin_lock_init(&cs5535_mfgpt_chip.lock);
 
-       dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", MFGPT_BAR,
-                       (unsigned long long) cs5535_mfgpt_chip.base);
+       dev_info(&pdev->dev, "reserved resource region %pR\n", res);
 
        /* detect the available timers */
        t = scan_timers(&cs5535_mfgpt_chip);
-       dev_info(&pdev->dev, DRV_NAME ": %d MFGPT timers available\n", t);
+       dev_info(&pdev->dev, "%d MFGPT timers available\n", t);
        cs5535_mfgpt_chip.initialized = 1;
        return 0;
 
@@ -332,47 +329,18 @@ done:
        return err;
 }
 
-static struct pci_device_id cs5535_mfgpt_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
-       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
-       { 0, },
+static struct platform_driver cs5535_mfgpt_drv = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = cs5535_mfgpt_probe,
 };
-MODULE_DEVICE_TABLE(pci, cs5535_mfgpt_pci_tbl);
 
-/*
- * Just like with the cs5535-gpio driver, we can't use the standard PCI driver
- * registration stuff.  It only allows only one driver to bind to each PCI
- * device, and we want the GPIO and MFGPT drivers to be able to share a PCI
- * device.  Instead, we manually scan for the PCI device, request a single
- * region, and keep track of the devices that we're using.
- */
-
-static int __init cs5535_mfgpt_scan_pci(void)
-{
-       struct pci_dev *pdev;
-       int err = -ENODEV;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(cs5535_mfgpt_pci_tbl); i++) {
-               pdev = pci_get_device(cs5535_mfgpt_pci_tbl[i].vendor,
-                               cs5535_mfgpt_pci_tbl[i].device, NULL);
-               if (pdev) {
-                       err = cs5535_mfgpt_probe(pdev,
-                                       &cs5535_mfgpt_pci_tbl[i]);
-                       if (err)
-                               pci_dev_put(pdev);
-
-                       /* we only support a single CS5535/6 southbridge */
-                       break;
-               }
-       }
-
-       return err;
-}
 
 static int __init cs5535_mfgpt_init(void)
 {
-       return cs5535_mfgpt_scan_pci();
+       return platform_driver_register(&cs5535_mfgpt_drv);
 }
 
 module_init(cs5535_mfgpt_init);
@@ -380,3 +348,4 @@ module_init(cs5535_mfgpt_init);
 MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
 MODULE_DESCRIPTION("CS5535/CS5536 MFGPT timer driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index fa19d849a9202ad0a9390ee96fae6a3e9647594e..dd84124f4209314bd571a61a172cbbcf24285cf9 100644 (file)
@@ -13,6 +13,7 @@
  * your option) any later version.
  */
 
+#include <linux/err.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/mmc/host.h>
+#ifdef CONFIG_PPC
 #include <asm/machdep.h>
+#endif
 #include "sdhci-of.h"
 #include "sdhci.h"
 
@@ -112,7 +117,11 @@ static bool __devinit sdhci_of_wp_inverted(struct device_node *np)
                return true;
 
        /* Old device trees don't have the wp-inverted property. */
+#ifdef CONFIG_PPC
        return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds);
+#else
+       return false;
+#endif
 }
 
 static int __devinit sdhci_of_probe(struct platform_device *ofdev,
index 54c6d849cf25683cf4d2831c2c7b5d50605ec452..62d6f88cbab57deb4fb7141745f700ad68efceb4 100644 (file)
@@ -854,12 +854,12 @@ ks8695_set_msglevel(struct net_device *ndev, u32 value)
 }
 
 /**
- *     ks8695_get_settings - Get device-specific settings.
+ *     ks8695_wan_get_settings - Get device-specific settings.
  *     @ndev: The network device to read settings from
  *     @cmd: The ethtool structure to read into
  */
 static int
-ks8695_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+ks8695_wan_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
 {
        struct ks8695_priv *ksp = netdev_priv(ndev);
        u32 ctrl;
@@ -870,69 +870,50 @@ ks8695_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
                          SUPPORTED_TP | SUPPORTED_MII);
        cmd->transceiver = XCVR_INTERNAL;
 
-       /* Port specific extras */
-       switch (ksp->dtype) {
-       case KS8695_DTYPE_HPNA:
-               cmd->phy_address = 0;
-               /* not supported for HPNA */
-               cmd->autoneg = AUTONEG_DISABLE;
+       cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+       cmd->port = PORT_MII;
+       cmd->supported |= (SUPPORTED_Autoneg | SUPPORTED_Pause);
+       cmd->phy_address = 0;
 
-               /* BUG: Erm, dtype hpna implies no phy regs */
-               /*
-               ctrl = readl(KS8695_MISC_VA + KS8695_HMC);
-               cmd->speed = (ctrl & HMC_HSS) ? SPEED_100 : SPEED_10;
-               cmd->duplex = (ctrl & HMC_HDS) ? DUPLEX_FULL : DUPLEX_HALF;
-               */
-               return -EOPNOTSUPP;
-       case KS8695_DTYPE_WAN:
-               cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
-               cmd->port = PORT_MII;
-               cmd->supported |= (SUPPORTED_Autoneg | SUPPORTED_Pause);
-               cmd->phy_address = 0;
+       ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+       if ((ctrl & WMC_WAND) == 0) {
+               /* auto-negotiation is enabled */
+               cmd->advertising |= ADVERTISED_Autoneg;
+               if (ctrl & WMC_WANA100F)
+                       cmd->advertising |= ADVERTISED_100baseT_Full;
+               if (ctrl & WMC_WANA100H)
+                       cmd->advertising |= ADVERTISED_100baseT_Half;
+               if (ctrl & WMC_WANA10F)
+                       cmd->advertising |= ADVERTISED_10baseT_Full;
+               if (ctrl & WMC_WANA10H)
+                       cmd->advertising |= ADVERTISED_10baseT_Half;
+               if (ctrl & WMC_WANAP)
+                       cmd->advertising |= ADVERTISED_Pause;
+               cmd->autoneg = AUTONEG_ENABLE;
+
+               cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10;
+               cmd->duplex = (ctrl & WMC_WDS) ?
+                       DUPLEX_FULL : DUPLEX_HALF;
+       } else {
+               /* auto-negotiation is disabled */
+               cmd->autoneg = AUTONEG_DISABLE;
 
-               ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-               if ((ctrl & WMC_WAND) == 0) {
-                       /* auto-negotiation is enabled */
-                       cmd->advertising |= ADVERTISED_Autoneg;
-                       if (ctrl & WMC_WANA100F)
-                               cmd->advertising |= ADVERTISED_100baseT_Full;
-                       if (ctrl & WMC_WANA100H)
-                               cmd->advertising |= ADVERTISED_100baseT_Half;
-                       if (ctrl & WMC_WANA10F)
-                               cmd->advertising |= ADVERTISED_10baseT_Full;
-                       if (ctrl & WMC_WANA10H)
-                               cmd->advertising |= ADVERTISED_10baseT_Half;
-                       if (ctrl & WMC_WANAP)
-                               cmd->advertising |= ADVERTISED_Pause;
-                       cmd->autoneg = AUTONEG_ENABLE;
-
-                       cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10;
-                       cmd->duplex = (ctrl & WMC_WDS) ?
-                               DUPLEX_FULL : DUPLEX_HALF;
-               } else {
-                       /* auto-negotiation is disabled */
-                       cmd->autoneg = AUTONEG_DISABLE;
-
-                       cmd->speed = (ctrl & WMC_WANF100) ?
-                               SPEED_100 : SPEED_10;
-                       cmd->duplex = (ctrl & WMC_WANFF) ?
-                               DUPLEX_FULL : DUPLEX_HALF;
-               }
-               break;
-       case KS8695_DTYPE_LAN:
-               return -EOPNOTSUPP;
+               cmd->speed = (ctrl & WMC_WANF100) ?
+                       SPEED_100 : SPEED_10;
+               cmd->duplex = (ctrl & WMC_WANFF) ?
+                       DUPLEX_FULL : DUPLEX_HALF;
        }
 
        return 0;
 }
 
 /**
- *     ks8695_set_settings - Set device-specific settings.
+ *     ks8695_wan_set_settings - Set device-specific settings.
  *     @ndev: The network device to configure
  *     @cmd: The settings to configure
  */
 static int
-ks8695_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+ks8695_wan_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
 {
        struct ks8695_priv *ksp = netdev_priv(ndev);
        u32 ctrl;
@@ -956,171 +937,85 @@ ks8695_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
                                ADVERTISED_100baseT_Full)) == 0)
                        return -EINVAL;
 
-               switch (ksp->dtype) {
-               case KS8695_DTYPE_HPNA:
-                       /* HPNA does not support auto-negotiation. */
-                       return -EINVAL;
-               case KS8695_DTYPE_WAN:
-                       ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
-                       ctrl &= ~(WMC_WAND | WMC_WANA100F | WMC_WANA100H |
-                                 WMC_WANA10F | WMC_WANA10H);
-                       if (cmd->advertising & ADVERTISED_100baseT_Full)
-                               ctrl |= WMC_WANA100F;
-                       if (cmd->advertising & ADVERTISED_100baseT_Half)
-                               ctrl |= WMC_WANA100H;
-                       if (cmd->advertising & ADVERTISED_10baseT_Full)
-                               ctrl |= WMC_WANA10F;
-                       if (cmd->advertising & ADVERTISED_10baseT_Half)
-                               ctrl |= WMC_WANA10H;
-
-                       /* force a re-negotiation */
-                       ctrl |= WMC_WANR;
-                       writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
-                       break;
-               case KS8695_DTYPE_LAN:
-                       return -EOPNOTSUPP;
-               }
+               ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
 
+               ctrl &= ~(WMC_WAND | WMC_WANA100F | WMC_WANA100H |
+                         WMC_WANA10F | WMC_WANA10H);
+               if (cmd->advertising & ADVERTISED_100baseT_Full)
+                       ctrl |= WMC_WANA100F;
+               if (cmd->advertising & ADVERTISED_100baseT_Half)
+                       ctrl |= WMC_WANA100H;
+               if (cmd->advertising & ADVERTISED_10baseT_Full)
+                       ctrl |= WMC_WANA10F;
+               if (cmd->advertising & ADVERTISED_10baseT_Half)
+                       ctrl |= WMC_WANA10H;
+
+               /* force a re-negotiation */
+               ctrl |= WMC_WANR;
+               writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
        } else {
-               switch (ksp->dtype) {
-               case KS8695_DTYPE_HPNA:
-                       /* BUG: dtype_hpna implies no phy registers */
-                       /*
-                       ctrl = __raw_readl(KS8695_MISC_VA + KS8695_HMC);
-
-                       ctrl &= ~(HMC_HSS | HMC_HDS);
-                       if (cmd->speed == SPEED_100)
-                               ctrl |= HMC_HSS;
-                       if (cmd->duplex == DUPLEX_FULL)
-                               ctrl |= HMC_HDS;
-
-                       __raw_writel(ctrl, KS8695_MISC_VA + KS8695_HMC);
-                       */
-                       return -EOPNOTSUPP;
-               case KS8695_DTYPE_WAN:
-                       ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
-                       /* disable auto-negotiation */
-                       ctrl |= WMC_WAND;
-                       ctrl &= ~(WMC_WANF100 | WMC_WANFF);
-
-                       if (cmd->speed == SPEED_100)
-                               ctrl |= WMC_WANF100;
-                       if (cmd->duplex == DUPLEX_FULL)
-                               ctrl |= WMC_WANFF;
-
-                       writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
-                       break;
-               case KS8695_DTYPE_LAN:
-                       return -EOPNOTSUPP;
-               }
+               ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+
+               /* disable auto-negotiation */
+               ctrl |= WMC_WAND;
+               ctrl &= ~(WMC_WANF100 | WMC_WANFF);
+
+               if (cmd->speed == SPEED_100)
+                       ctrl |= WMC_WANF100;
+               if (cmd->duplex == DUPLEX_FULL)
+                       ctrl |= WMC_WANFF;
+
+               writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
        }
 
        return 0;
 }
 
 /**
- *     ks8695_nwayreset - Restart the autonegotiation on the port.
+ *     ks8695_wan_nwayreset - Restart the autonegotiation on the port.
  *     @ndev: The network device to restart autoneotiation on
  */
 static int
-ks8695_nwayreset(struct net_device *ndev)
+ks8695_wan_nwayreset(struct net_device *ndev)
 {
        struct ks8695_priv *ksp = netdev_priv(ndev);
        u32 ctrl;
 
-       switch (ksp->dtype) {
-       case KS8695_DTYPE_HPNA:
-               /* No phy means no autonegotiation on hpna */
-               return -EINVAL;
-       case KS8695_DTYPE_WAN:
-               ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
-               if ((ctrl & WMC_WAND) == 0)
-                       writel(ctrl | WMC_WANR,
-                              ksp->phyiface_regs + KS8695_WMC);
-               else
-                       /* auto-negotiation not enabled */
-                       return -EINVAL;
-               break;
-       case KS8695_DTYPE_LAN:
-               return -EOPNOTSUPP;
-       }
-
-       return 0;
-}
+       ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
 
-/**
- *     ks8695_get_link - Retrieve link status of network interface
- *     @ndev: The network interface to retrive the link status of.
- */
-static u32
-ks8695_get_link(struct net_device *ndev)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-       u32 ctrl;
+       if ((ctrl & WMC_WAND) == 0)
+               writel(ctrl | WMC_WANR,
+                      ksp->phyiface_regs + KS8695_WMC);
+       else
+               /* auto-negotiation not enabled */
+               return -EINVAL;
 
-       switch (ksp->dtype) {
-       case KS8695_DTYPE_HPNA:
-               /* HPNA always has link */
-               return 1;
-       case KS8695_DTYPE_WAN:
-               /* WAN we can read the PHY for */
-               ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-               return ctrl & WMC_WLS;
-       case KS8695_DTYPE_LAN:
-               return -EOPNOTSUPP;
-       }
        return 0;
 }
 
 /**
- *     ks8695_get_pause - Retrieve network pause/flow-control advertising
+ *     ks8695_wan_get_pause - Retrieve network pause/flow-control advertising
  *     @ndev: The device to retrieve settings from
  *     @param: The structure to fill out with the information
  */
 static void
-ks8695_get_pause(struct net_device *ndev, struct ethtool_pauseparam *param)
+ks8695_wan_get_pause(struct net_device *ndev, struct ethtool_pauseparam *param)
 {
        struct ks8695_priv *ksp = netdev_priv(ndev);
        u32 ctrl;
 
-       switch (ksp->dtype) {
-       case KS8695_DTYPE_HPNA:
-               /* No phy link on hpna to configure */
-               return;
-       case KS8695_DTYPE_WAN:
-               ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
-               /* advertise Pause */
-               param->autoneg = (ctrl & WMC_WANAP);
+       ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
 
-               /* current Rx Flow-control */
-               ctrl = ks8695_readreg(ksp, KS8695_DRXC);
-               param->rx_pause = (ctrl & DRXC_RFCE);
+       /* advertise Pause */
+       param->autoneg = (ctrl & WMC_WANAP);
 
-               /* current Tx Flow-control */
-               ctrl = ks8695_readreg(ksp, KS8695_DTXC);
-               param->tx_pause = (ctrl & DTXC_TFCE);
-               break;
-       case KS8695_DTYPE_LAN:
-               /* The LAN's "phy" is a direct-attached switch */
-               return;
-       }
-}
+       /* current Rx Flow-control */
+       ctrl = ks8695_readreg(ksp, KS8695_DRXC);
+       param->rx_pause = (ctrl & DRXC_RFCE);
 
-/**
- *     ks8695_set_pause - Configure pause/flow-control
- *     @ndev: The device to configure
- *     @param: The pause parameters to set
- *
- *     TODO: Implement this
- */
-static int
-ks8695_set_pause(struct net_device *ndev, struct ethtool_pauseparam *param)
-{
-       return -EOPNOTSUPP;
+       /* current Tx Flow-control */
+       ctrl = ks8695_readreg(ksp, KS8695_DTXC);
+       param->tx_pause = (ctrl & DTXC_TFCE);
 }
 
 /**
@@ -1140,12 +1035,17 @@ ks8695_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
 static const struct ethtool_ops ks8695_ethtool_ops = {
        .get_msglevel   = ks8695_get_msglevel,
        .set_msglevel   = ks8695_set_msglevel,
-       .get_settings   = ks8695_get_settings,
-       .set_settings   = ks8695_set_settings,
-       .nway_reset     = ks8695_nwayreset,
-       .get_link       = ks8695_get_link,
-       .get_pauseparam = ks8695_get_pause,
-       .set_pauseparam = ks8695_set_pause,
+       .get_drvinfo    = ks8695_get_drvinfo,
+};
+
+static const struct ethtool_ops ks8695_wan_ethtool_ops = {
+       .get_msglevel   = ks8695_get_msglevel,
+       .set_msglevel   = ks8695_set_msglevel,
+       .get_settings   = ks8695_wan_get_settings,
+       .set_settings   = ks8695_wan_set_settings,
+       .nway_reset     = ks8695_wan_nwayreset,
+       .get_link       = ethtool_op_get_link,
+       .get_pauseparam = ks8695_wan_get_pause,
        .get_drvinfo    = ks8695_get_drvinfo,
 };
 
@@ -1541,7 +1441,6 @@ ks8695_probe(struct platform_device *pdev)
 
        /* driver system setup */
        ndev->netdev_ops = &ks8695_netdev_ops;
-       SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
        ndev->watchdog_timeo     = msecs_to_jiffies(watchdog);
 
        netif_napi_add(ndev, &ksp->napi, ks8695_poll, NAPI_WEIGHT);
@@ -1608,12 +1507,15 @@ ks8695_probe(struct platform_device *pdev)
        if (ksp->phyiface_regs && ksp->link_irq == -1) {
                ks8695_init_switch(ksp);
                ksp->dtype = KS8695_DTYPE_LAN;
+               SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
        } else if (ksp->phyiface_regs && ksp->link_irq != -1) {
                ks8695_init_wan_phy(ksp);
                ksp->dtype = KS8695_DTYPE_WAN;
+               SET_ETHTOOL_OPS(ndev, &ks8695_wan_ethtool_ops);
        } else {
                /* No initialisation since HPNA does not have a PHY */
                ksp->dtype = KS8695_DTYPE_HPNA;
+               SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
        }
 
        /* And bring up the net_device with the net core */
index 0b9fc5173aef1478355e9cadbcb635f1fdca594d..22abfb39d8131f4f9685fd4a914c0aa2873b525a 100644 (file)
@@ -1284,19 +1284,12 @@ static void bfin_mac_multicast_hash(struct net_device *dev)
 {
        u32 emac_hashhi, emac_hashlo;
        struct netdev_hw_addr *ha;
-       char *addrs;
        u32 crc;
 
        emac_hashhi = emac_hashlo = 0;
 
        netdev_for_each_mc_addr(ha, dev) {
-               addrs = ha->addr;
-
-               /* skip non-multicast addresses */
-               if (!(*addrs & 1))
-                       continue;
-
-               crc = ether_crc(ETH_ALEN, addrs);
+               crc = ether_crc(ETH_ALEN, ha->addr);
                crc >>= 26;
 
                if (crc & 0x20)
index 99be5ae91991f84554faf98d682f31c75cbf3b0e..142d6047da2795c879b3b2d54c862ad7d30a7e86 100644 (file)
@@ -275,7 +275,6 @@ bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
 
        ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
        if (ioc_attr) {
-               memset(ioc_attr, 0, sizeof(*ioc_attr));
                spin_lock_irqsave(&bnad->bna_lock, flags);
                bfa_nw_ioc_get_attr(&bnad->bna.device.ioc, ioc_attr);
                spin_unlock_irqrestore(&bnad->bna_lock, flags);
index 7206ab2cbbf8e16526775de5ec4d2f9bb5789f60..3437613f0454e97d00676766f6f7058abb5bbc5c 100644 (file)
@@ -3203,7 +3203,7 @@ static int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
        int phy_type = CAS_PHY_MII_MDIO0; /* default phy type */
        int mac_off  = 0;
 
-#if defined(CONFIG_OF)
+#if defined(CONFIG_SPARC)
        const unsigned char *addr;
 #endif
 
@@ -3354,7 +3354,7 @@ use_random_mac_addr:
        if (found & VPD_FOUND_MAC)
                goto done;
 
-#if defined(CONFIG_OF)
+#if defined(CONFIG_SPARC)
        addr = of_get_property(cp->of_node, "local-mac-address", NULL);
        if (addr != NULL) {
                memcpy(dev_addr, addr, 6);
@@ -5031,7 +5031,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
        cp->msg_enable = (cassini_debug < 0) ? CAS_DEF_MSG_ENABLE :
          cassini_debug;
 
-#if defined(CONFIG_OF)
+#if defined(CONFIG_SPARC)
        cp->of_node = pci_device_to_OF_node(pdev);
 #endif
 
index de69c54301c13fe78652c50e07ccfe9eefad441b..bfab14092d2c87b30f3e7bf3d1b72efd542b1d48 100644 (file)
@@ -3478,9 +3478,17 @@ static irqreturn_t e1000_intr(int irq, void *data)
        struct e1000_hw *hw = &adapter->hw;
        u32 icr = er32(ICR);
 
-       if (unlikely((!icr) || test_bit(__E1000_DOWN, &adapter->flags)))
+       if (unlikely((!icr)))
                return IRQ_NONE;  /* Not our interrupt */
 
+       /*
+        * we might have caused the interrupt, but the above
+        * read cleared it, and just in case the driver is
+        * down there is nothing to do so return handled
+        */
+       if (unlikely(test_bit(__E1000_DOWN, &adapter->flags)))
+               return IRQ_HANDLED;
+
        if (unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) {
                hw->get_link_status = 1;
                /* guard against interrupt when we're going down */
index 1397da118f0d310a45e67d18fd754d48d222191a..89a69035e538f2ef024e2c6e747a1b762744a118 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2010 Intel Corporation.
+  Copyright(c) 1999 - 2011 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -1310,7 +1310,7 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
                 * apply workaround for hardware errata documented in errata
                 * docs Fixes issue where some error prone or unreliable PCIe
                 * completions are occurring, particularly with ASPM enabled.
-                * Without fix, issue can cause tx timeouts.
+                * Without fix, issue can cause Tx timeouts.
                 */
                reg = er32(GCR2);
                reg |= 1;
index 360c91369f35f7e3bd94818116777ba1c499c2f2..28519acacd2d28f4eea74fd0fe4239c9d6ff1aa7 100644 (file)
@@ -1,7 +1,7 @@
 ################################################################################
 #
 # Intel PRO/1000 Linux driver
-# Copyright(c) 1999 - 2008 Intel Corporation.
+# Copyright(c) 1999 - 2011 Intel Corporation.
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms and conditions of the GNU General Public License,
index 7245dc2e0b7cc0d1d73aa84fa36378cc94f3db59..13149983d07ec993bca6487e2a16484349d6cf46 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2010 Intel Corporation.
+  Copyright(c) 1999 - 2011 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index 5255be75374659a959e13fce4e91c217221db036..e610e1369053154abf27e8665d60ca1392a2d0ff 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2010 Intel Corporation.
+  Copyright(c) 1999 - 2011 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index e45a61c8930a792b7333ca881fd291254de94058..2fefa820302b8c0b028c1a2945df0903dba0216c 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2010 Intel Corporation.
+  Copyright(c) 1999 - 2011 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index f8ed03dab9b173bd5228537661ffd3d5250de784..fa08b6336cfb0796ae901076d25460f52600bb7a 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2010 Intel Corporation.
+  Copyright(c) 1999 - 2011 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index e774380c7cecc6d645d543d253cbe05027646b39..bc0860a598c91673c86f012801bc178dccb72396 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2010 Intel Corporation.
+  Copyright(c) 1999 - 2011 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -102,7 +102,7 @@ enum e1e_registers {
        E1000_RDTR     = 0x02820, /* Rx Delay Timer - RW */
        E1000_RXDCTL_BASE = 0x02828, /* Rx Descriptor Control - RW */
 #define E1000_RXDCTL(_n)   (E1000_RXDCTL_BASE + (_n << 8))
-       E1000_RADV     = 0x0282C, /* RX Interrupt Absolute Delay Timer - RW */
+       E1000_RADV     = 0x0282C, /* Rx Interrupt Absolute Delay Timer - RW */
 
 /* Convenience macros
  *
index 5bb65b7382db024c80c54b6b2d05f3f76e3cff41..fb46974cfec1afd122edea3f3aa8a4058b8d1928 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2010 Intel Corporation.
+  Copyright(c) 1999 - 2011 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
index ff2872153b211dfdc447c9a82b133ce44479aa85..68aa1749bf66f027cb58a8bfba17dbfb34101043 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2010 Intel Corporation.
+  Copyright(c) 1999 - 2011 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -533,7 +533,7 @@ s32 e1000e_check_for_fiber_link(struct e1000_hw *hw)
                        mac->autoneg_failed = 1;
                        return 0;
                }
-               e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n");
+               e_dbg("NOT Rx'ing /C/, disable AutoNeg and force link.\n");
 
                /* Disable auto-negotiation in the TXCW register */
                ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
@@ -556,7 +556,7 @@ s32 e1000e_check_for_fiber_link(struct e1000_hw *hw)
                 * and disable forced link in the Device Control register
                 * in an attempt to auto-negotiate with our link partner.
                 */
-               e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n");
+               e_dbg("Rx'ing /C/, enable AutoNeg and stop forcing link.\n");
                ew32(TXCW, mac->txcw);
                ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
 
@@ -598,7 +598,7 @@ s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
                        mac->autoneg_failed = 1;
                        return 0;
                }
-               e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n");
+               e_dbg("NOT Rx'ing /C/, disable AutoNeg and force link.\n");
 
                /* Disable auto-negotiation in the TXCW register */
                ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
@@ -621,7 +621,7 @@ s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
                 * and disable forced link in the Device Control register
                 * in an attempt to auto-negotiate with our link partner.
                 */
-               e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n");
+               e_dbg("Rx'ing /C/, enable AutoNeg and stop forcing link.\n");
                ew32(TXCW, mac->txcw);
                ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
 
@@ -800,9 +800,9 @@ static s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
         * The possible values of the "fc" parameter are:
         *      0:  Flow control is completely disabled
         *      1:  Rx flow control is enabled (we can receive pause frames,
-        *        but not send pause frames).
+        *          but not send pause frames).
         *      2:  Tx flow control is enabled (we can send pause frames but we
-        *        do not support receiving pause frames).
+        *          do not support receiving pause frames).
         *      3:  Both Rx and Tx flow control (symmetric) are enabled.
         */
        switch (hw->fc.current_mode) {
@@ -1031,9 +1031,9 @@ s32 e1000e_force_mac_fc(struct e1000_hw *hw)
         * The possible values of the "fc" parameter are:
         *      0:  Flow control is completely disabled
         *      1:  Rx flow control is enabled (we can receive pause
-        *        frames but not send pause frames).
+        *          frames but not send pause frames).
         *      2:  Tx flow control is enabled (we can send pause frames
-        *        frames but we do not receive pause frames).
+        *          frames but we do not receive pause frames).
         *      3:  Both Rx and Tx flow control (symmetric) is enabled.
         *  other:  No other values should be possible at this point.
         */
@@ -1189,7 +1189,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
                        } else {
                                hw->fc.current_mode = e1000_fc_rx_pause;
                                e_dbg("Flow Control = "
-                                        "RX PAUSE frames only.\r\n");
+                                     "Rx PAUSE frames only.\r\n");
                        }
                }
                /*
index fa5b6045254732910a877f25c8f474a67cfea0e8..1c18f26b0812ac962708c68711abe58167c0eee0 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2010 Intel Corporation.
+  Copyright(c) 1999 - 2011 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -77,17 +77,17 @@ struct e1000_reg_info {
        char *name;
 };
 
-#define E1000_RDFH     0x02410 /* Rx Data FIFO Head - RW */
-#define E1000_RDFT     0x02418 /* Rx Data FIFO Tail - RW */
-#define E1000_RDFHS    0x02420 /* Rx Data FIFO Head Saved - RW */
-#define E1000_RDFTS    0x02428 /* Rx Data FIFO Tail Saved - RW */
-#define E1000_RDFPC    0x02430 /* Rx Data FIFO Packet Count - RW */
+#define E1000_RDFH     0x02410 /* Rx Data FIFO Head - RW */
+#define E1000_RDFT     0x02418 /* Rx Data FIFO Tail - RW */
+#define E1000_RDFHS    0x02420 /* Rx Data FIFO Head Saved - RW */
+#define E1000_RDFTS    0x02428 /* Rx Data FIFO Tail Saved - RW */
+#define E1000_RDFPC    0x02430 /* Rx Data FIFO Packet Count - RW */
 
-#define E1000_TDFH     0x03410 /* Tx Data FIFO Head - RW */
-#define E1000_TDFT     0x03418 /* Tx Data FIFO Tail - RW */
-#define E1000_TDFHS    0x03420 /* Tx Data FIFO Head Saved - RW */
-#define E1000_TDFTS    0x03428 /* Tx Data FIFO Tail Saved - RW */
-#define E1000_TDFPC    0x03430 /* Tx Data FIFO Packet Count - RW */
+#define E1000_TDFH     0x03410 /* Tx Data FIFO Head - RW */
+#define E1000_TDFT     0x03418 /* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420 /* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428 /* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430 /* Tx Data FIFO Packet Count - RW */
 
 static const struct e1000_reg_info e1000_reg_info_tbl[] = {
 
@@ -99,7 +99,7 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = {
        /* Interrupt Registers */
        {E1000_ICR, "ICR"},
 
-       /* RX Registers */
+       /* Rx Registers */
        {E1000_RCTL, "RCTL"},
        {E1000_RDLEN, "RDLEN"},
        {E1000_RDH, "RDH"},
@@ -115,7 +115,7 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = {
        {E1000_RDFTS, "RDFTS"},
        {E1000_RDFPC, "RDFPC"},
 
-       /* TX Registers */
+       /* Tx Registers */
        {E1000_TCTL, "TCTL"},
        {E1000_TDBAL, "TDBAL"},
        {E1000_TDBAH, "TDBAH"},
@@ -160,7 +160,7 @@ static void e1000_regdump(struct e1000_hw *hw, struct e1000_reg_info *reginfo)
                break;
        default:
                printk(KERN_INFO "%-15s %08x\n",
-                       reginfo->name, __er32(hw, reginfo->ofs));
+                      reginfo->name, __er32(hw, reginfo->ofs));
                return;
        }
 
@@ -171,9 +171,8 @@ static void e1000_regdump(struct e1000_hw *hw, struct e1000_reg_info *reginfo)
        printk(KERN_CONT "\n");
 }
 
-
 /*
- * e1000e_dump - Print registers, tx-ring and rx-ring
+ * e1000e_dump - Print registers, Tx-ring and Rx-ring
  */
 static void e1000e_dump(struct e1000_adapter *adapter)
 {
@@ -182,12 +181,20 @@ static void e1000e_dump(struct e1000_adapter *adapter)
        struct e1000_reg_info *reginfo;
        struct e1000_ring *tx_ring = adapter->tx_ring;
        struct e1000_tx_desc *tx_desc;
-       struct my_u0 { u64 a; u64 b; } *u0;
+       struct my_u0 {
+               u64 a;
+               u64 b;
+       } *u0;
        struct e1000_buffer *buffer_info;
        struct e1000_ring *rx_ring = adapter->rx_ring;
        union e1000_rx_desc_packet_split *rx_desc_ps;
        struct e1000_rx_desc *rx_desc;
-       struct my_u1 { u64 a; u64 b; u64 c; u64 d; } *u1;
+       struct my_u1 {
+               u64 a;
+               u64 b;
+               u64 c;
+               u64 d;
+       } *u1;
        u32 staterr;
        int i = 0;
 
@@ -198,12 +205,10 @@ static void e1000e_dump(struct e1000_adapter *adapter)
        if (netdev) {
                dev_info(&adapter->pdev->dev, "Net device Info\n");
                printk(KERN_INFO "Device Name     state            "
-                       "trans_start      last_rx\n");
+                      "trans_start      last_rx\n");
                printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
-                       netdev->name,
-                       netdev->state,
-                       netdev->trans_start,
-                       netdev->last_rx);
+                      netdev->name, netdev->state, netdev->trans_start,
+                      netdev->last_rx);
        }
 
        /* Print Registers */
@@ -214,26 +219,26 @@ static void e1000e_dump(struct e1000_adapter *adapter)
                e1000_regdump(hw, reginfo);
        }
 
-       /* Print TX Ring Summary */
+       /* Print Tx Ring Summary */
        if (!netdev || !netif_running(netdev))
                goto exit;
 
-       dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
+       dev_info(&adapter->pdev->dev, "Tx Ring Summary\n");
        printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma  ]"
-               " leng ntw timestamp\n");
+              " leng ntw timestamp\n");
        buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
        printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
-               0, tx_ring->next_to_use, tx_ring->next_to_clean,
-               (unsigned long long)buffer_info->dma,
-               buffer_info->length,
-               buffer_info->next_to_watch,
-               (unsigned long long)buffer_info->time_stamp);
+              0, tx_ring->next_to_use, tx_ring->next_to_clean,
+              (unsigned long long)buffer_info->dma,
+              buffer_info->length,
+              buffer_info->next_to_watch,
+              (unsigned long long)buffer_info->time_stamp);
 
-       /* Print TX Rings */
+       /* Print Tx Ring */
        if (!netif_msg_tx_done(adapter))
                goto rx_ring_summary;
 
-       dev_info(&adapter->pdev->dev, "TX Rings Dump\n");
+       dev_info(&adapter->pdev->dev, "Tx Ring Dump\n");
 
        /* Transmit Descriptor Formats - DEXT[29] is 0 (Legacy) or 1 (Extended)
         *
@@ -263,22 +268,22 @@ static void e1000e_dump(struct e1000_adapter *adapter)
         *   63       48 47     40 39  36 35    32 31     24 23  20 19        0
         */
        printk(KERN_INFO "Tl[desc]     [address 63:0  ] [SpeCssSCmCsLen]"
-               " [bi->dma       ] leng  ntw timestamp        bi->skb "
-               "<-- Legacy format\n");
+              " [bi->dma       ] leng  ntw timestamp        bi->skb "
+              "<-- Legacy format\n");
        printk(KERN_INFO "Tc[desc]     [Ce CoCsIpceCoS] [MssHlRSCm0Plen]"
-               " [bi->dma       ] leng  ntw timestamp        bi->skb "
-               "<-- Ext Context format\n");
+              " [bi->dma       ] leng  ntw timestamp        bi->skb "
+              "<-- Ext Context format\n");
        printk(KERN_INFO "Td[desc]     [address 63:0  ] [VlaPoRSCm1Dlen]"
-               " [bi->dma       ] leng  ntw timestamp        bi->skb "
-               "<-- Ext Data format\n");
+              " [bi->dma       ] leng  ntw timestamp        bi->skb "
+              "<-- Ext Data format\n");
        for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
                tx_desc = E1000_TX_DESC(*tx_ring, i);
                buffer_info = &tx_ring->buffer_info[i];
                u0 = (struct my_u0 *)tx_desc;
                printk(KERN_INFO "T%c[0x%03X]    %016llX %016llX %016llX "
-                       "%04X  %3X %016llX %p",
-                      (!(le64_to_cpu(u0->b) & (1<<29)) ? 'l' :
-                       ((le64_to_cpu(u0->b) & (1<<20)) ? 'd' : 'c')), i,
+                      "%04X  %3X %016llX %p",
+                      (!(le64_to_cpu(u0->b) & (1 << 29)) ? 'l' :
+                       ((le64_to_cpu(u0->b) & (1 << 20)) ? 'd' : 'c')), i,
                       (unsigned long long)le64_to_cpu(u0->a),
                       (unsigned long long)le64_to_cpu(u0->b),
                       (unsigned long long)buffer_info->dma,
@@ -296,22 +301,22 @@ static void e1000e_dump(struct e1000_adapter *adapter)
 
                if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
                        print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS,
-                                       16, 1, phys_to_virt(buffer_info->dma),
-                                       buffer_info->length, true);
+                                      16, 1, phys_to_virt(buffer_info->dma),
+                                      buffer_info->length, true);
        }
 
-       /* Print RX Rings Summary */
+       /* Print Rx Ring Summary */
 rx_ring_summary:
-       dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
+       dev_info(&adapter->pdev->dev, "Rx Ring Summary\n");
        printk(KERN_INFO "Queue [NTU] [NTC]\n");
        printk(KERN_INFO " %5d %5X %5X\n", 0,
-               rx_ring->next_to_use, rx_ring->next_to_clean);
+              rx_ring->next_to_use, rx_ring->next_to_clean);
 
-       /* Print RX Rings */
+       /* Print Rx Ring */
        if (!netif_msg_rx_status(adapter))
                goto exit;
 
-       dev_info(&adapter->pdev->dev, "RX Rings Dump\n");
+       dev_info(&adapter->pdev->dev, "Rx Ring Dump\n");
        switch (adapter->rx_ps_pages) {
        case 1:
        case 2:
@@ -329,7 +334,7 @@ rx_ring_summary:
                 *    +-----------------------------------------------------+
                 */
                printk(KERN_INFO "R  [desc]      [buffer 0 63:0 ] "
-                       "[buffer 1 63:0 ] "
+                      "[buffer 1 63:0 ] "
                       "[buffer 2 63:0 ] [buffer 3 63:0 ] [bi->dma       ] "
                       "[bi->skb] <-- Ext Pkt Split format\n");
                /* [Extended] Receive Descriptor (Write-Back) Format
@@ -344,7 +349,7 @@ rx_ring_summary:
                 *   63       48 47    32 31            20 19               0
                 */
                printk(KERN_INFO "RWB[desc]      [ck ipid mrqhsh] "
-                       "[vl   l0 ee  es] "
+                      "[vl   l0 ee  es] "
                       "[ l3  l2  l1 hs] [reserved      ] ---------------- "
                       "[bi->skb] <-- Ext Rx Write-Back format\n");
                for (i = 0; i < rx_ring->count; i++) {
@@ -352,26 +357,26 @@ rx_ring_summary:
                        rx_desc_ps = E1000_RX_DESC_PS(*rx_ring, i);
                        u1 = (struct my_u1 *)rx_desc_ps;
                        staterr =
-                               le32_to_cpu(rx_desc_ps->wb.middle.status_error);
+                           le32_to_cpu(rx_desc_ps->wb.middle.status_error);
                        if (staterr & E1000_RXD_STAT_DD) {
                                /* Descriptor Done */
                                printk(KERN_INFO "RWB[0x%03X]     %016llX "
-                                       "%016llX %016llX %016llX "
-                                       "---------------- %p", i,
-                                       (unsigned long long)le64_to_cpu(u1->a),
-                                       (unsigned long long)le64_to_cpu(u1->b),
-                                       (unsigned long long)le64_to_cpu(u1->c),
-                                       (unsigned long long)le64_to_cpu(u1->d),
-                                       buffer_info->skb);
+                                      "%016llX %016llX %016llX "
+                                      "---------------- %p", i,
+                                      (unsigned long long)le64_to_cpu(u1->a),
+                                      (unsigned long long)le64_to_cpu(u1->b),
+                                      (unsigned long long)le64_to_cpu(u1->c),
+                                      (unsigned long long)le64_to_cpu(u1->d),
+                                      buffer_info->skb);
                        } else {
                                printk(KERN_INFO "R  [0x%03X]     %016llX "
-                                       "%016llX %016llX %016llX %016llX %p", i,
-                                       (unsigned long long)le64_to_cpu(u1->a),
-                                       (unsigned long long)le64_to_cpu(u1->b),
-                                       (unsigned long long)le64_to_cpu(u1->c),
-                                       (unsigned long long)le64_to_cpu(u1->d),
-                                       (unsigned long long)buffer_info->dma,
-                                       buffer_info->skb);
+                                      "%016llX %016llX %016llX %016llX %p", i,
+                                      (unsigned long long)le64_to_cpu(u1->a),
+                                      (unsigned long long)le64_to_cpu(u1->b),
+                                      (unsigned long long)le64_to_cpu(u1->c),
+                                      (unsigned long long)le64_to_cpu(u1->d),
+                                      (unsigned long long)buffer_info->dma,
+                                      buffer_info->skb);
 
                                if (netif_msg_pktdata(adapter))
                                        print_hex_dump(KERN_INFO, "",
@@ -400,18 +405,18 @@ rx_ring_summary:
                 * 63       48 47    40 39      32 31         16 15      0
                 */
                printk(KERN_INFO "Rl[desc]     [address 63:0  ] "
-                       "[vl er S cks ln] [bi->dma       ] [bi->skb] "
-                       "<-- Legacy format\n");
+                      "[vl er S cks ln] [bi->dma       ] [bi->skb] "
+                      "<-- Legacy format\n");
                for (i = 0; rx_ring->desc && (i < rx_ring->count); i++) {
                        rx_desc = E1000_RX_DESC(*rx_ring, i);
                        buffer_info = &rx_ring->buffer_info[i];
                        u0 = (struct my_u0 *)rx_desc;
                        printk(KERN_INFO "Rl[0x%03X]    %016llX %016llX "
-                               "%016llX %p", i,
-                               (unsigned long long)le64_to_cpu(u0->a),
-                               (unsigned long long)le64_to_cpu(u0->b),
-                               (unsigned long long)buffer_info->dma,
-                               buffer_info->skb);
+                              "%016llX %p", i,
+                              (unsigned long long)le64_to_cpu(u0->a),
+                              (unsigned long long)le64_to_cpu(u0->b),
+                              (unsigned long long)buffer_info->dma,
+                              buffer_info->skb);
                        if (i == rx_ring->next_to_use)
                                printk(KERN_CONT " NTU\n");
                        else if (i == rx_ring->next_to_clean)
@@ -421,9 +426,10 @@ rx_ring_summary:
 
                        if (netif_msg_pktdata(adapter))
                                print_hex_dump(KERN_INFO, "",
-                                       DUMP_PREFIX_ADDRESS,
-                                       16, 1, phys_to_virt(buffer_info->dma),
-                                       adapter->rx_buffer_len, true);
+                                              DUMP_PREFIX_ADDRESS,
+                                              16, 1,
+                                              phys_to_virt(buffer_info->dma),
+                                              adapter->rx_buffer_len, true);
                }
        }
 
@@ -450,8 +456,7 @@ static int e1000_desc_unused(struct e1000_ring *ring)
  * @skb: pointer to sk_buff to be indicated to stack
  **/
 static void e1000_receive_skb(struct e1000_adapter *adapter,
-                             struct net_device *netdev,
-                             struct sk_buff *skb,
+                             struct net_device *netdev, struct sk_buff *skb,
                              u8 status, __le16 vlan)
 {
        skb->protocol = eth_type_trans(skb, netdev);
@@ -464,7 +469,7 @@ static void e1000_receive_skb(struct e1000_adapter *adapter,
 }
 
 /**
- * e1000_rx_checksum - Receive Checksum Offload for 82543
+ * e1000_rx_checksum - Receive Checksum Offload
  * @adapter:     board private structure
  * @status_err:  receive descriptor status and error fields
  * @csum:      receive descriptor csum field
@@ -548,7 +553,7 @@ map_skb:
                                                  adapter->rx_buffer_len,
                                                  DMA_FROM_DEVICE);
                if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
-                       dev_err(&pdev->dev, "RX DMA map failed\n");
+                       dev_err(&pdev->dev, "Rx DMA map failed\n");
                        adapter->rx_dma_failed++;
                        break;
                }
@@ -601,7 +606,8 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
                        ps_page = &buffer_info->ps_pages[j];
                        if (j >= adapter->rx_ps_pages) {
                                /* all unused desc entries get hw null ptr */
-                               rx_desc->read.buffer_addr[j+1] = ~cpu_to_le64(0);
+                               rx_desc->read.buffer_addr[j + 1] =
+                                   ~cpu_to_le64(0);
                                continue;
                        }
                        if (!ps_page->page) {
@@ -617,7 +623,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
                                if (dma_mapping_error(&pdev->dev,
                                                      ps_page->dma)) {
                                        dev_err(&adapter->pdev->dev,
-                                         "RX DMA page map failed\n");
+                                               "Rx DMA page map failed\n");
                                        adapter->rx_dma_failed++;
                                        goto no_buffers;
                                }
@@ -627,8 +633,8 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
                         * didn't change because each write-back
                         * erases this info.
                         */
-                       rx_desc->read.buffer_addr[j+1] =
-                            cpu_to_le64(ps_page->dma);
+                       rx_desc->read.buffer_addr[j + 1] =
+                           cpu_to_le64(ps_page->dma);
                }
 
                skb = netdev_alloc_skb_ip_align(netdev,
@@ -644,7 +650,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
                                                  adapter->rx_ps_bsize0,
                                                  DMA_FROM_DEVICE);
                if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
-                       dev_err(&pdev->dev, "RX DMA map failed\n");
+                       dev_err(&pdev->dev, "Rx DMA map failed\n");
                        adapter->rx_dma_failed++;
                        /* cleanup skb */
                        dev_kfree_skb_any(skb);
@@ -662,7 +668,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
                         * such as IA-64).
                         */
                        wmb();
-                       writel(i<<1, adapter->hw.hw_addr + rx_ring->tail);
+                       writel(i << 1, adapter->hw.hw_addr + rx_ring->tail);
                }
 
                i++;
@@ -1106,11 +1112,10 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
                cleaned = 1;
                cleaned_count++;
                dma_unmap_single(&pdev->dev, buffer_info->dma,
-                                adapter->rx_ps_bsize0,
-                                DMA_FROM_DEVICE);
+                                adapter->rx_ps_bsize0, DMA_FROM_DEVICE);
                buffer_info->dma = 0;
 
-               /* see !EOP comment in other rx routine */
+               /* see !EOP comment in other Rx routine */
                if (!(staterr & E1000_RXD_STAT_EOP))
                        adapter->flags2 |= FLAG2_IS_DISCARDING;
 
@@ -2610,7 +2615,7 @@ static void e1000_init_manageability_pt(struct e1000_adapter *adapter)
 }
 
 /**
- * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
+ * e1000_configure_tx - Configure Transmit Unit after Reset
  * @adapter: board private structure
  *
  * Configure the Tx unit of the MAC after a reset.
@@ -2663,7 +2668,7 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
                 * hthresh = 1 ==> prefetch when one or more available
                 * pthresh = 0x1f ==> prefetch if internal cache 31 or less
                 * BEWARE: this seems to work but should be considered first if
-                * there are tx hangs or other tx related bugs
+                * there are Tx hangs or other Tx related bugs
                 */
                txdctl |= E1000_TXDCTL_DMA_BURST_ENABLE;
                ew32(TXDCTL(0), txdctl);
@@ -2877,7 +2882,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
        if (adapter->rx_ps_pages) {
                /* this is a 32 byte descriptor */
                rdlen = rx_ring->count *
-                       sizeof(union e1000_rx_desc_packet_split);
+                   sizeof(union e1000_rx_desc_packet_split);
                adapter->clean_rx = e1000_clean_rx_irq_ps;
                adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
        } else if (adapter->netdev->mtu > ETH_FRAME_LEN + ETH_FCS_LEN) {
@@ -2900,7 +2905,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
                /*
                 * set the writeback threshold (only takes effect if the RDTR
                 * is set). set GRAN=1 and write back up to 0x4 worth, and
-                * enable prefetching of 0x20 rx descriptors
+                * enable prefetching of 0x20 Rx descriptors
                 * granularity = 01
                 * wthresh = 04,
                 * hthresh = 04,
@@ -2981,12 +2986,10 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
                         * excessive C-state transition latencies result in
                         * dropped transactions.
                         */
-                       pm_qos_update_request(
-                               &adapter->netdev->pm_qos_req, 55);
+                       pm_qos_update_request(&adapter->netdev->pm_qos_req, 55);
                } else {
-                       pm_qos_update_request(
-                               &adapter->netdev->pm_qos_req,
-                               PM_QOS_DEFAULT_VALUE);
+                       pm_qos_update_request(&adapter->netdev->pm_qos_req,
+                                             PM_QOS_DEFAULT_VALUE);
                }
        }
 
@@ -3152,7 +3155,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
                /* lower 16 bits has Rx packet buffer allocation size in KB */
                pba &= 0xffff;
                /*
-                * the Tx fifo also stores 16 bytes of information about the tx
+                * the Tx fifo also stores 16 bytes of information about the Tx
                 * but don't include ethernet FCS because hardware appends it
                 */
                min_tx_space = (adapter->max_frame_size +
@@ -3175,7 +3178,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
                        pba -= min_tx_space - tx_space;
 
                        /*
-                        * if short on Rx space, Rx wins and must trump tx
+                        * if short on Rx space, Rx wins and must trump Tx
                         * adjustment or use Early Receive if available
                         */
                        if ((pba < min_rx_space) &&
@@ -4039,11 +4042,11 @@ static void e1000_print_link_info(struct e1000_adapter *adapter)
               adapter->netdev->name,
               adapter->link_speed,
               (adapter->link_duplex == FULL_DUPLEX) ?
-                               "Full Duplex" : "Half Duplex",
+              "Full Duplex" : "Half Duplex",
               ((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ?
-                               "RX/TX" :
-              ((ctrl & E1000_CTRL_RFCE) ? "RX" :
-              ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" )));
+              "Rx/Tx" :
+              ((ctrl & E1000_CTRL_RFCE) ? "Rx" :
+               ((ctrl & E1000_CTRL_TFCE) ? "Tx" : "None")));
 }
 
 static bool e1000e_has_link(struct e1000_adapter *adapter)
@@ -4338,7 +4341,7 @@ link_up:
        /* Force detection of hung controller every watchdog period */
        adapter->detect_tx_hung = 1;
 
-       /* flush partial descriptors to memory before detecting tx hang */
+       /* flush partial descriptors to memory before detecting Tx hang */
        if (adapter->flags2 & FLAG2_DMA_BURST) {
                ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD);
                ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD);
@@ -4529,7 +4532,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                buffer_info->next_to_watch = i;
                buffer_info->dma = dma_map_single(&pdev->dev,
                                                  skb->data + offset,
-                                                 size, DMA_TO_DEVICE);
+                                                 size, DMA_TO_DEVICE);
                buffer_info->mapped_as_page = false;
                if (dma_mapping_error(&pdev->dev, buffer_info->dma))
                        goto dma_error;
@@ -4576,7 +4579,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                }
        }
 
-       segs = skb_shinfo(skb)->gso_segs ?: 1;
+       segs = skb_shinfo(skb)->gso_segs ? : 1;
        /* multiply data chunks by size of headers */
        bytecount = ((segs - 1) * skb_headlen(skb)) + skb->len;
 
@@ -4588,13 +4591,13 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
        return count;
 
 dma_error:
-       dev_err(&pdev->dev, "TX DMA map failed\n");
+       dev_err(&pdev->dev, "Tx DMA map failed\n");
        buffer_info->dma = 0;
        if (count)
                count--;
 
        while (count--) {
-               if (i==0)
+               if (i == 0)
                        i += tx_ring->count;
                i--;
                buffer_info = &tx_ring->buffer_info[i];
@@ -6193,7 +6196,7 @@ static int __init e1000_init_module(void)
        int ret;
        pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
                e1000e_driver_version);
-       pr_info("Copyright (c) 1999 - 2010 Intel Corporation.\n");
+       pr_info("Copyright(c) 1999 - 2011 Intel Corporation.\n");
        ret = pci_register_driver(&e1000_driver);
 
        return ret;
index a9612b0e4bca89938117c6febffbc4ab07098b1b..4dd9b63273f62eac9917d69df9a613dd3fa14e61 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2010 Intel Corporation.
+  Copyright(c) 1999 - 2011 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -62,10 +62,9 @@ MODULE_PARM_DESC(copybreak,
        module_param_array_named(X, X, int, &num_##X, 0);       \
        MODULE_PARM_DESC(X, desc);
 
-
 /*
  * Transmit Interrupt Delay in units of 1.024 microseconds
- * Tx interrupt delay needs to typically be set to something non zero
+ * Tx interrupt delay needs to typically be set to something non-zero
  *
  * Valid Range: 0-65535
  */
@@ -112,6 +111,7 @@ E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
 #define DEFAULT_ITR 3
 #define MAX_ITR 100000
 #define MIN_ITR 100
+
 /* IntMode (Interrupt Mode)
  *
  * Valid Range: 0 - 2
index 00f89e8a9fa02a5288543e4806b45fd15a3b9c88..6bea051b134b5e7e48f0c85feb9a4879d956974b 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2010 Intel Corporation.
+  Copyright(c) 1999 - 2011 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -640,7 +640,7 @@ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw)
        s32 ret_val;
        u16 phy_data;
 
-       /* Enable CRS on TX. This must be set for half-duplex operation. */
+       /* Enable CRS on Tx. This must be set for half-duplex operation. */
        ret_val = e1e_rphy(hw, I82577_CFG_REG, &phy_data);
        if (ret_val)
                goto out;
index 6de4675016b5303e186d3c2350c8a81b0c98ae7c..119aa2000c24a7e7091c517588ab64b175e50c39 100644 (file)
@@ -434,7 +434,6 @@ static void gfar_init_mac(struct net_device *ndev)
 static struct net_device_stats *gfar_get_stats(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
-       struct netdev_queue *txq;
        unsigned long rx_packets = 0, rx_bytes = 0, rx_dropped = 0;
        unsigned long tx_packets = 0, tx_bytes = 0;
        int i = 0;
@@ -450,9 +449,8 @@ static struct net_device_stats *gfar_get_stats(struct net_device *dev)
        dev->stats.rx_dropped = rx_dropped;
 
        for (i = 0; i < priv->num_tx_queues; i++) {
-               txq = netdev_get_tx_queue(dev, i);
-               tx_bytes += txq->tx_bytes;
-               tx_packets += txq->tx_packets;
+               tx_bytes += priv->tx_queue[i]->stats.tx_bytes;
+               tx_packets += priv->tx_queue[i]->stats.tx_packets;
        }
 
        dev->stats.tx_bytes = tx_bytes;
@@ -2109,8 +2107,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        /* Update transmit stats */
-       txq->tx_bytes += skb->len;
-       txq->tx_packets ++;
+       tx_queue->stats.tx_bytes += skb->len;
+       tx_queue->stats.tx_packets++;
 
        txbdp = txbdp_start = tx_queue->cur_tx;
        lstatus = txbdp->lstatus;
index 68984eb88ae03ed519ca9ce8dfdcaa2df7f827a8..54de4135e932b9dd2d92eedd32cf0338a20f3011 100644 (file)
@@ -907,12 +907,21 @@ enum {
        MQ_MG_MODE
 };
 
+/*
+ * Per TX queue stats
+ */
+struct tx_q_stats {
+       unsigned long tx_packets;
+       unsigned long tx_bytes;
+};
+
 /**
  *     struct gfar_priv_tx_q - per tx queue structure
  *     @txlock: per queue tx spin lock
  *     @tx_skbuff:skb pointers
  *     @skb_curtx: to be used skb pointer
  *     @skb_dirtytx:the last used skb pointer
+ *     @stats: bytes/packets stats
  *     @qindex: index of this queue
  *     @dev: back pointer to the dev structure
  *     @grp: back pointer to the group to which this queue belongs
@@ -934,6 +943,7 @@ struct gfar_priv_tx_q {
        struct  txbd8 *tx_bd_base;
        struct  txbd8 *cur_tx;
        struct  txbd8 *dirty_tx;
+       struct tx_q_stats stats;
        struct  net_device *dev;
        struct gfar_priv_grp *grp;
        u16     skb_curtx;
index 27d6960ce09ea7a8d7f12ef970f9de5c769ebd37..fdb0333f5cb60145bdeb2ec9940b85a319d14cad 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Aeroflex Gaisler GRETH 10/100/1G Ethernet MAC.
  *
- * 2005-2009 (c) Aeroflex Gaisler AB
+ * 2005-2010 (c) Aeroflex Gaisler AB
  *
  * This driver supports GRETH 10/100 and GRETH 10/100/1G Ethernet MACs
  * available in the GRLIB VHDL IP core library.
@@ -356,6 +356,8 @@ static int greth_open(struct net_device *dev)
                dev_dbg(&dev->dev, " starting queue\n");
        netif_start_queue(dev);
 
+       GRETH_REGSAVE(greth->regs->status, 0xFF);
+
        napi_enable(&greth->napi);
 
        greth_enable_irqs(greth);
@@ -371,7 +373,9 @@ static int greth_close(struct net_device *dev)
 
        napi_disable(&greth->napi);
 
+       greth_disable_irqs(greth);
        greth_disable_tx(greth);
+       greth_disable_rx(greth);
 
        netif_stop_queue(dev);
 
@@ -388,12 +392,20 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct greth_private *greth = netdev_priv(dev);
        struct greth_bd *bdp;
        int err = NETDEV_TX_OK;
-       u32 status, dma_addr;
+       u32 status, dma_addr, ctrl;
+       unsigned long flags;
 
-       bdp = greth->tx_bd_base + greth->tx_next;
+       /* Clean TX Ring */
+       greth_clean_tx(greth->netdev);
 
        if (unlikely(greth->tx_free <= 0)) {
+               spin_lock_irqsave(&greth->devlock, flags);/*save from poll/irq*/
+               ctrl = GRETH_REGLOAD(greth->regs->control);
+               /* Enable TX IRQ only if not already in poll() routine */
+               if (ctrl & GRETH_RXI)
+                       GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
                netif_stop_queue(dev);
+               spin_unlock_irqrestore(&greth->devlock, flags);
                return NETDEV_TX_BUSY;
        }
 
@@ -406,13 +418,14 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
                goto out;
        }
 
+       bdp = greth->tx_bd_base + greth->tx_next;
        dma_addr = greth_read_bd(&bdp->addr);
 
        memcpy((unsigned char *) phys_to_virt(dma_addr), skb->data, skb->len);
 
        dma_sync_single_for_device(greth->dev, dma_addr, skb->len, DMA_TO_DEVICE);
 
-       status = GRETH_BD_EN | (skb->len & GRETH_BD_LEN);
+       status = GRETH_BD_EN | GRETH_BD_IE | (skb->len & GRETH_BD_LEN);
 
        /* Wrap around descriptor ring */
        if (greth->tx_next == GRETH_TXBD_NUM_MASK) {
@@ -422,22 +435,11 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
        greth->tx_next = NEXT_TX(greth->tx_next);
        greth->tx_free--;
 
-       /* No more descriptors */
-       if (unlikely(greth->tx_free == 0)) {
-
-               /* Free transmitted descriptors */
-               greth_clean_tx(dev);
-
-               /* If nothing was cleaned, stop queue & wait for irq */
-               if (unlikely(greth->tx_free == 0)) {
-                       status |= GRETH_BD_IE;
-                       netif_stop_queue(dev);
-               }
-       }
-
        /* Write descriptor control word and enable transmission */
        greth_write_bd(&bdp->stat, status);
+       spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
        greth_enable_tx(greth);
+       spin_unlock_irqrestore(&greth->devlock, flags);
 
 out:
        dev_kfree_skb(skb);
@@ -450,13 +452,23 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
 {
        struct greth_private *greth = netdev_priv(dev);
        struct greth_bd *bdp;
-       u32 status = 0, dma_addr;
+       u32 status = 0, dma_addr, ctrl;
        int curr_tx, nr_frags, i, err = NETDEV_TX_OK;
+       unsigned long flags;
 
        nr_frags = skb_shinfo(skb)->nr_frags;
 
+       /* Clean TX Ring */
+       greth_clean_tx_gbit(dev);
+
        if (greth->tx_free < nr_frags + 1) {
+               spin_lock_irqsave(&greth->devlock, flags);/*save from poll/irq*/
+               ctrl = GRETH_REGLOAD(greth->regs->control);
+               /* Enable TX IRQ only if not already in poll() routine */
+               if (ctrl & GRETH_RXI)
+                       GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
                netif_stop_queue(dev);
+               spin_unlock_irqrestore(&greth->devlock, flags);
                err = NETDEV_TX_BUSY;
                goto out;
        }
@@ -499,7 +511,7 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
                greth->tx_skbuff[curr_tx] = NULL;
                bdp = greth->tx_bd_base + curr_tx;
 
-               status = GRETH_TXBD_CSALL;
+               status = GRETH_TXBD_CSALL | GRETH_BD_EN;
                status |= frag->size & GRETH_BD_LEN;
 
                /* Wrap around descriptor ring */
@@ -509,14 +521,8 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
                /* More fragments left */
                if (i < nr_frags - 1)
                        status |= GRETH_TXBD_MORE;
-
-               /* ... last fragment, check if out of descriptors  */
-               else if (greth->tx_free - nr_frags - 1 < (MAX_SKB_FRAGS + 1)) {
-
-                       /* Enable interrupts and stop queue */
-                       status |= GRETH_BD_IE;
-                       netif_stop_queue(dev);
-               }
+               else
+                       status |= GRETH_BD_IE; /* enable IRQ on last fragment */
 
                greth_write_bd(&bdp->stat, status);
 
@@ -536,26 +542,29 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
 
        wmb();
 
-       /* Enable the descriptors that we configured ...  */
-       for (i = 0; i < nr_frags + 1; i++) {
-               bdp = greth->tx_bd_base + greth->tx_next;
-               greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN);
-               greth->tx_next = NEXT_TX(greth->tx_next);
-               greth->tx_free--;
-       }
+       /* Enable the descriptor chain by enabling the first descriptor */
+       bdp = greth->tx_bd_base + greth->tx_next;
+       greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN);
+       greth->tx_next = curr_tx;
+       greth->tx_free -= nr_frags + 1;
 
+       wmb();
+
+       spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
        greth_enable_tx(greth);
+       spin_unlock_irqrestore(&greth->devlock, flags);
 
        return NETDEV_TX_OK;
 
 frag_map_error:
-       /* Unmap SKB mappings that succeeded */
+       /* Unmap SKB mappings that succeeded and disable descriptor */
        for (i = 0; greth->tx_next + i != curr_tx; i++) {
                bdp = greth->tx_bd_base + greth->tx_next + i;
                dma_unmap_single(greth->dev,
                                 greth_read_bd(&bdp->addr),
                                 greth_read_bd(&bdp->stat) & GRETH_BD_LEN,
                                 DMA_TO_DEVICE);
+               greth_write_bd(&bdp->stat, 0);
        }
 map_error:
        if (net_ratelimit())
@@ -565,12 +574,11 @@ out:
        return err;
 }
 
-
 static irqreturn_t greth_interrupt(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
        struct greth_private *greth;
-       u32 status;
+       u32 status, ctrl;
        irqreturn_t retval = IRQ_NONE;
 
        greth = netdev_priv(dev);
@@ -580,13 +588,15 @@ static irqreturn_t greth_interrupt(int irq, void *dev_id)
        /* Get the interrupt events that caused us to be here. */
        status = GRETH_REGLOAD(greth->regs->status);
 
-       /* Handle rx and tx interrupts through poll */
-       if (status & (GRETH_INT_RX | GRETH_INT_TX)) {
-
-               /* Clear interrupt status */
-               GRETH_REGORIN(greth->regs->status,
-                             status & (GRETH_INT_RX | GRETH_INT_TX));
+       /* Must see if interrupts are enabled also, INT_TX|INT_RX flags may be
+        * set regardless of whether IRQ is enabled or not. Especially
+        * important when shared IRQ.
+        */
+       ctrl = GRETH_REGLOAD(greth->regs->control);
 
+       /* Handle rx and tx interrupts through poll */
+       if (((status & (GRETH_INT_RE | GRETH_INT_RX)) && (ctrl & GRETH_RXI)) ||
+           ((status & (GRETH_INT_TE | GRETH_INT_TX)) && (ctrl & GRETH_TXI))) {
                retval = IRQ_HANDLED;
 
                /* Disable interrupts and schedule poll() */
@@ -610,6 +620,8 @@ static void greth_clean_tx(struct net_device *dev)
 
        while (1) {
                bdp = greth->tx_bd_base + greth->tx_last;
+               GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
+               mb();
                stat = greth_read_bd(&bdp->stat);
 
                if (unlikely(stat & GRETH_BD_EN))
@@ -670,7 +682,10 @@ static void greth_clean_tx_gbit(struct net_device *dev)
 
                /* We only clean fully completed SKBs */
                bdp_last_frag = greth->tx_bd_base + SKIP_TX(greth->tx_last, nr_frags);
-               stat = bdp_last_frag->stat;
+
+               GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
+               mb();
+               stat = greth_read_bd(&bdp_last_frag->stat);
 
                if (stat & GRETH_BD_EN)
                        break;
@@ -702,21 +717,9 @@ static void greth_clean_tx_gbit(struct net_device *dev)
                greth->tx_free += nr_frags+1;
                dev_kfree_skb(skb);
        }
-       if (greth->tx_free > (MAX_SKB_FRAGS + 1)) {
-               netif_wake_queue(dev);
-       }
-}
 
-static int greth_pending_packets(struct greth_private *greth)
-{
-       struct greth_bd *bdp;
-       u32 status;
-       bdp = greth->rx_bd_base + greth->rx_cur;
-       status = greth_read_bd(&bdp->stat);
-       if (status & GRETH_BD_EN)
-               return 0;
-       else
-               return 1;
+       if (netif_queue_stopped(dev) && (greth->tx_free > (MAX_SKB_FRAGS+1)))
+               netif_wake_queue(dev);
 }
 
 static int greth_rx(struct net_device *dev, int limit)
@@ -727,20 +730,24 @@ static int greth_rx(struct net_device *dev, int limit)
        int pkt_len;
        int bad, count;
        u32 status, dma_addr;
+       unsigned long flags;
 
        greth = netdev_priv(dev);
 
        for (count = 0; count < limit; ++count) {
 
                bdp = greth->rx_bd_base + greth->rx_cur;
+               GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
+               mb();
                status = greth_read_bd(&bdp->stat);
-               dma_addr = greth_read_bd(&bdp->addr);
-               bad = 0;
 
                if (unlikely(status & GRETH_BD_EN)) {
                        break;
                }
 
+               dma_addr = greth_read_bd(&bdp->addr);
+               bad = 0;
+
                /* Check status for errors. */
                if (unlikely(status & GRETH_RXBD_STATUS)) {
                        if (status & GRETH_RXBD_ERR_FT) {
@@ -802,7 +809,9 @@ static int greth_rx(struct net_device *dev, int limit)
 
                dma_sync_single_for_device(greth->dev, dma_addr, MAX_FRAME_SIZE, DMA_FROM_DEVICE);
 
+               spin_lock_irqsave(&greth->devlock, flags); /* save from XMIT */
                greth_enable_rx(greth);
+               spin_unlock_irqrestore(&greth->devlock, flags);
 
                greth->rx_cur = NEXT_RX(greth->rx_cur);
        }
@@ -836,6 +845,7 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
        int pkt_len;
        int bad, count = 0;
        u32 status, dma_addr;
+       unsigned long flags;
 
        greth = netdev_priv(dev);
 
@@ -843,6 +853,8 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
 
                bdp = greth->rx_bd_base + greth->rx_cur;
                skb = greth->rx_skbuff[greth->rx_cur];
+               GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
+               mb();
                status = greth_read_bd(&bdp->stat);
                bad = 0;
 
@@ -865,10 +877,9 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
                        }
                }
 
-               /* Allocate new skb to replace current */
-               newskb = netdev_alloc_skb(dev, MAX_FRAME_SIZE + NET_IP_ALIGN);
-
-               if (!bad && newskb) {
+               /* Allocate new skb to replace current, not needed if the
+                * current skb can be reused */
+               if (!bad && (newskb=netdev_alloc_skb(dev, MAX_FRAME_SIZE + NET_IP_ALIGN))) {
                        skb_reserve(newskb, NET_IP_ALIGN);
 
                        dma_addr = dma_map_single(greth->dev,
@@ -905,11 +916,22 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
                                if (net_ratelimit())
                                        dev_warn(greth->dev, "Could not create DMA mapping, dropping packet\n");
                                dev_kfree_skb(newskb);
+                               /* reusing current skb, so it is a drop */
                                dev->stats.rx_dropped++;
                        }
+               } else if (bad) {
+                       /* Bad Frame transfer, the skb is reused */
+                       dev->stats.rx_dropped++;
                } else {
+                       /* Failed Allocating a new skb. This is rather stupid
+                        * but the current "filled" skb is reused, as if
+                        * transfer failure. One could argue that RX descriptor
+                        * table handling should be divided into cleaning and
+                        * filling as the TX part of the driver
+                        */
                        if (net_ratelimit())
                                dev_warn(greth->dev, "Could not allocate SKB, dropping packet\n");
+                       /* reusing current skb, so it is a drop */
                        dev->stats.rx_dropped++;
                }
 
@@ -920,7 +942,9 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
 
                wmb();
                greth_write_bd(&bdp->stat, status);
+               spin_lock_irqsave(&greth->devlock, flags);
                greth_enable_rx(greth);
+               spin_unlock_irqrestore(&greth->devlock, flags);
                greth->rx_cur = NEXT_RX(greth->rx_cur);
        }
 
@@ -932,15 +956,18 @@ static int greth_poll(struct napi_struct *napi, int budget)
 {
        struct greth_private *greth;
        int work_done = 0;
+       unsigned long flags;
+       u32 mask, ctrl;
        greth = container_of(napi, struct greth_private, napi);
 
-       if (greth->gbit_mac) {
-               greth_clean_tx_gbit(greth->netdev);
-       } else {
-               greth_clean_tx(greth->netdev);
+restart_txrx_poll:
+       if (netif_queue_stopped(greth->netdev)) {
+               if (greth->gbit_mac)
+                       greth_clean_tx_gbit(greth->netdev);
+               else
+                       greth_clean_tx(greth->netdev);
        }
 
-restart_poll:
        if (greth->gbit_mac) {
                work_done += greth_rx_gbit(greth->netdev, budget - work_done);
        } else {
@@ -949,15 +976,29 @@ restart_poll:
 
        if (work_done < budget) {
 
-               napi_complete(napi);
+               spin_lock_irqsave(&greth->devlock, flags);
+
+               ctrl = GRETH_REGLOAD(greth->regs->control);
+               if (netif_queue_stopped(greth->netdev)) {
+                       GRETH_REGSAVE(greth->regs->control,
+                                       ctrl | GRETH_TXI | GRETH_RXI);
+                       mask = GRETH_INT_RX | GRETH_INT_RE |
+                              GRETH_INT_TX | GRETH_INT_TE;
+               } else {
+                       GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_RXI);
+                       mask = GRETH_INT_RX | GRETH_INT_RE;
+               }
 
-               if (greth_pending_packets(greth)) {
-                       napi_reschedule(napi);
-                       goto restart_poll;
+               if (GRETH_REGLOAD(greth->regs->status) & mask) {
+                       GRETH_REGSAVE(greth->regs->control, ctrl);
+                       spin_unlock_irqrestore(&greth->devlock, flags);
+                       goto restart_txrx_poll;
+               } else {
+                       __napi_complete(napi);
+                       spin_unlock_irqrestore(&greth->devlock, flags);
                }
        }
 
-       greth_enable_irqs(greth);
        return work_done;
 }
 
@@ -1152,11 +1193,11 @@ static const struct ethtool_ops greth_ethtool_ops = {
 };
 
 static struct net_device_ops greth_netdev_ops = {
-       .ndo_open = greth_open,
-       .ndo_stop = greth_close,
-       .ndo_start_xmit = greth_start_xmit,
-       .ndo_set_mac_address = greth_set_mac_add,
-       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_open               = greth_open,
+       .ndo_stop               = greth_close,
+       .ndo_start_xmit         = greth_start_xmit,
+       .ndo_set_mac_address    = greth_set_mac_add,
+       .ndo_validate_addr      = eth_validate_addr,
 };
 
 static inline int wait_for_mdio(struct greth_private *greth)
@@ -1217,29 +1258,26 @@ static void greth_link_change(struct net_device *dev)
        struct greth_private *greth = netdev_priv(dev);
        struct phy_device *phydev = greth->phy;
        unsigned long flags;
-
        int status_change = 0;
+       u32 ctrl;
 
        spin_lock_irqsave(&greth->devlock, flags);
 
        if (phydev->link) {
 
                if ((greth->speed != phydev->speed) || (greth->duplex != phydev->duplex)) {
-
-                       GRETH_REGANDIN(greth->regs->control,
-                                      ~(GRETH_CTRL_FD | GRETH_CTRL_SP | GRETH_CTRL_GB));
+                       ctrl = GRETH_REGLOAD(greth->regs->control) &
+                              ~(GRETH_CTRL_FD | GRETH_CTRL_SP | GRETH_CTRL_GB);
 
                        if (phydev->duplex)
-                               GRETH_REGORIN(greth->regs->control, GRETH_CTRL_FD);
-
-                       if (phydev->speed == SPEED_100) {
-
-                               GRETH_REGORIN(greth->regs->control, GRETH_CTRL_SP);
-                       }
+                               ctrl |= GRETH_CTRL_FD;
 
+                       if (phydev->speed == SPEED_100)
+                               ctrl |= GRETH_CTRL_SP;
                        else if (phydev->speed == SPEED_1000)
-                               GRETH_REGORIN(greth->regs->control, GRETH_CTRL_GB);
+                               ctrl |= GRETH_CTRL_GB;
 
+                       GRETH_REGSAVE(greth->regs->control, ctrl);
                        greth->speed = phydev->speed;
                        greth->duplex = phydev->duplex;
                        status_change = 1;
@@ -1600,6 +1638,9 @@ static struct of_device_id greth_of_match[] = {
        {
         .name = "GAISLER_ETHMAC",
         },
+       {
+        .name = "01_01d",
+        },
        {},
 };
 
index 03ad903cd676a1dd8f65e55a491aa8cb45c8956e..be0f2062bd14df7cc12753beddcf809867082de7 100644 (file)
@@ -23,6 +23,7 @@
 #define GRETH_BD_LEN 0x7FF
 
 #define GRETH_TXEN 0x1
+#define GRETH_INT_TE 0x2
 #define GRETH_INT_TX 0x8
 #define GRETH_TXI 0x4
 #define GRETH_TXBD_STATUS 0x0001C000
@@ -35,6 +36,7 @@
 #define GRETH_TXBD_ERR_UE 0x4000
 #define GRETH_TXBD_ERR_AL 0x8000
 
+#define GRETH_INT_RE         0x1
 #define GRETH_INT_RX         0x4
 #define GRETH_RXEN           0x2
 #define GRETH_RXI            0x8
index a060610a42dbddf22429d7762c57a6f1d3723d3f..602078b848920a44f0c8e8398e6d3151f417fd4d 100644 (file)
@@ -6667,8 +6667,6 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
                          struct ixgbe_adapter *adapter,
                          struct ixgbe_ring *tx_ring)
 {
-       struct net_device *netdev = tx_ring->netdev;
-       struct netdev_queue *txq;
        unsigned int first;
        unsigned int tx_flags = 0;
        u8 hdr_len = 0;
@@ -6765,9 +6763,6 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
                /* add the ATR filter if ATR is on */
                if (test_bit(__IXGBE_TX_FDIR_INIT_DONE, &tx_ring->state))
                        ixgbe_atr(tx_ring, skb, tx_flags, protocol);
-               txq = netdev_get_tx_queue(netdev, tx_ring->queue_index);
-               txq->tx_bytes += skb->len;
-               txq->tx_packets++;
                ixgbe_tx_queue(tx_ring, tx_flags, count, skb->len, hdr_len);
                ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
 
@@ -6925,8 +6920,6 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        int i;
 
-       /* accurate rx/tx bytes/packets stats */
-       dev_txq_stats_fold(netdev, stats);
        rcu_read_lock();
        for (i = 0; i < adapter->num_rx_queues; i++) {
                struct ixgbe_ring *ring = ACCESS_ONCE(adapter->rx_ring[i]);
@@ -6943,6 +6936,22 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
                        stats->rx_bytes   += bytes;
                }
        }
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               struct ixgbe_ring *ring = ACCESS_ONCE(adapter->tx_ring[i]);
+               u64 bytes, packets;
+               unsigned int start;
+
+               if (ring) {
+                       do {
+                               start = u64_stats_fetch_begin_bh(&ring->syncp);
+                               packets = ring->stats.packets;
+                               bytes   = ring->stats.bytes;
+                       } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+                       stats->tx_packets += packets;
+                       stats->tx_bytes   += bytes;
+               }
+       }
        rcu_read_unlock();
        /* following stats updated by ixgbe_watchdog_task() */
        stats->multicast        = netdev->stats.multicast;
index 21845affea1303ed80a952d38b78d24c39281e28..5933621ac3ffa73f7c3a19db049b5bbc813560be 100644 (file)
@@ -585,7 +585,7 @@ err:
        rcu_read_lock_bh();
        vlan = rcu_dereference(q->vlan);
        if (vlan)
-               netdev_get_tx_queue(vlan->dev, 0)->tx_dropped++;
+               vlan->dev->stats.tx_dropped++;
        rcu_read_unlock_bh();
 
        return err;
index a37fcf11ab3622febf86e65499ff21fe9ba76b13..ea5cfe2c3a040aec2815c8020f15feb745064039 100644 (file)
@@ -3403,9 +3403,7 @@ static int myri10ge_resume(struct pci_dev *pdev)
                return -EIO;
        }
 
-       status = pci_restore_state(pdev);
-       if (status)
-               return status;
+       pci_restore_state(pdev);
 
        status = pci_enable_device(pdev);
        if (status) {
index bb8645ab247cc3e586932c9f5f8143ce381a50d1..bde7d61f193063b91ffb7fb02c0a1db787ca7d78 100644 (file)
@@ -554,6 +554,8 @@ struct rtl8169_private {
        struct mii_if_info mii;
        struct rtl8169_counters counters;
        u32 saved_wolopts;
+
+       const struct firmware *fw;
 };
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -1766,6 +1768,29 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw)
        }
 }
 
+static void rtl_release_firmware(struct rtl8169_private *tp)
+{
+       release_firmware(tp->fw);
+       tp->fw = NULL;
+}
+
+static int rtl_apply_firmware(struct rtl8169_private *tp, const char *fw_name)
+{
+       const struct firmware **fw = &tp->fw;
+       int rc = !*fw;
+
+       if (rc) {
+               rc = request_firmware(fw, fw_name, &tp->pci_dev->dev);
+               if (rc < 0)
+                       goto out;
+       }
+
+       /* TODO: release firmware once rtl_phy_write_fw signals failures. */
+       rtl_phy_write_fw(tp, *fw);
+out:
+       return rc;
+}
+
 static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
 {
        static const struct phy_reg phy_reg_init[] = {
@@ -2139,7 +2164,6 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
                { 0x0d, 0xf880 }
        };
        void __iomem *ioaddr = tp->mmio_addr;
-       const struct firmware *fw;
 
        rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
 
@@ -2203,11 +2227,8 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
 
        rtl_writephy(tp, 0x1f, 0x0005);
        rtl_writephy(tp, 0x05, 0x001b);
-       if (rtl_readphy(tp, 0x06) == 0xbf00 &&
-           request_firmware(&fw, FIRMWARE_8168D_1, &tp->pci_dev->dev) == 0) {
-               rtl_phy_write_fw(tp, fw);
-               release_firmware(fw);
-       } else {
+       if ((rtl_readphy(tp, 0x06) != 0xbf00) ||
+           (rtl_apply_firmware(tp, FIRMWARE_8168D_1) < 0)) {
                netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n");
        }
 
@@ -2257,7 +2278,6 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
                { 0x0d, 0xf880 }
        };
        void __iomem *ioaddr = tp->mmio_addr;
-       const struct firmware *fw;
 
        rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
 
@@ -2312,11 +2332,8 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
 
        rtl_writephy(tp, 0x1f, 0x0005);
        rtl_writephy(tp, 0x05, 0x001b);
-       if (rtl_readphy(tp, 0x06) == 0xb300 &&
-           request_firmware(&fw, FIRMWARE_8168D_2, &tp->pci_dev->dev) == 0) {
-               rtl_phy_write_fw(tp, fw);
-               release_firmware(fw);
-       } else {
+       if ((rtl_readphy(tp, 0x06) != 0xb300) ||
+           (rtl_apply_firmware(tp, FIRMWARE_8168D_2) < 0)) {
                netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n");
        }
 
@@ -3200,6 +3217,8 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
 
        cancel_delayed_work_sync(&tp->task);
 
+       rtl_release_firmware(tp);
+
        unregister_netdev(dev);
 
        if (pci_dev_run_wake(pdev))
index 711449c6e675ed7dee9cee2343b4a3bbb01ba7d2..002bac7438434f8eb240a891815e1223b55b7c5c 100644 (file)
@@ -1153,6 +1153,9 @@ static int efx_wanted_channels(void)
        int count;
        int cpu;
 
+       if (rss_cpus)
+               return rss_cpus;
+
        if (unlikely(!zalloc_cpumask_var(&core_mask, GFP_KERNEL))) {
                printk(KERN_WARNING
                       "sfc: RSS disabled due to allocation failure\n");
@@ -1266,27 +1269,18 @@ static void efx_remove_interrupts(struct efx_nic *efx)
        efx->legacy_irq = 0;
 }
 
-struct efx_tx_queue *
-efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
-{
-       unsigned tx_channel_offset =
-               separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
-       EFX_BUG_ON_PARANOID(index >= efx->n_tx_channels ||
-                           type >= EFX_TXQ_TYPES);
-       return &efx->channel[tx_channel_offset + index]->tx_queue[type];
-}
-
 static void efx_set_channels(struct efx_nic *efx)
 {
        struct efx_channel *channel;
        struct efx_tx_queue *tx_queue;
-       unsigned tx_channel_offset =
+
+       efx->tx_channel_offset =
                separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
 
        /* Channel pointers were set in efx_init_struct() but we now
         * need to clear them for TX queues in any RX-only channels. */
        efx_for_each_channel(channel, efx) {
-               if (channel->channel - tx_channel_offset >=
+               if (channel->channel - efx->tx_channel_offset >=
                    efx->n_tx_channels) {
                        efx_for_each_channel_tx_queue(tx_queue, channel)
                                tx_queue->channel = NULL;
index 70e4f7dcce8198b5484a2045f73165cfefa896e8..61ddd2c6e750cfd5fe93725612d3af256832acfb 100644 (file)
@@ -1107,22 +1107,9 @@ static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
 
        /* Restore PCI configuration if needed */
        if (method == RESET_TYPE_WORLD) {
-               if (efx_nic_is_dual_func(efx)) {
-                       rc = pci_restore_state(nic_data->pci_dev2);
-                       if (rc) {
-                               netif_err(efx, drv, efx->net_dev,
-                                         "failed to restore PCI config for "
-                                         "the secondary function\n");
-                               goto fail3;
-                       }
-               }
-               rc = pci_restore_state(efx->pci_dev);
-               if (rc) {
-                       netif_err(efx, drv, efx->net_dev,
-                                 "failed to restore PCI config for the "
-                                 "primary function\n");
-                       goto fail4;
-               }
+               if (efx_nic_is_dual_func(efx))
+                       pci_restore_state(nic_data->pci_dev2);
+               pci_restore_state(efx->pci_dev);
                netif_dbg(efx, drv, efx->net_dev,
                          "successfully restored PCI config\n");
        }
@@ -1133,7 +1120,7 @@ static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
                rc = -ETIMEDOUT;
                netif_err(efx, hw, efx->net_dev,
                          "timed out waiting for hardware reset\n");
-               goto fail5;
+               goto fail3;
        }
        netif_dbg(efx, hw, efx->net_dev, "hardware reset complete\n");
 
@@ -1141,11 +1128,9 @@ static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
 
        /* pci_save_state() and pci_restore_state() MUST be called in pairs */
 fail2:
-fail3:
        pci_restore_state(efx->pci_dev);
 fail1:
-fail4:
-fail5:
+fail3:
        return rc;
 }
 
index bdce66ddf93aa95ed27e78fc888d218b8266eef5..28df8665256a2167a5081fe4a69e3903ac22b1b5 100644 (file)
@@ -735,6 +735,7 @@ struct efx_nic {
        unsigned next_buffer_table;
        unsigned n_channels;
        unsigned n_rx_channels;
+       unsigned tx_channel_offset;
        unsigned n_tx_channels;
        unsigned int rx_buffer_len;
        unsigned int rx_buffer_order;
@@ -929,8 +930,13 @@ efx_get_channel(struct efx_nic *efx, unsigned index)
             _channel = (_channel->channel + 1 < (_efx)->n_channels) ?  \
                     (_efx)->channel[_channel->channel + 1] : NULL)
 
-extern struct efx_tx_queue *
-efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type);
+static inline struct efx_tx_queue *
+efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
+{
+       EFX_BUG_ON_PARANOID(index >= efx->n_tx_channels ||
+                           type >= EFX_TXQ_TYPES);
+       return &efx->channel[efx->tx_channel_offset + index]->tx_queue[type];
+}
 
 static inline struct efx_tx_queue *
 efx_channel_get_tx_queue(struct efx_channel *channel, unsigned type)
index 0e6bac5ec65b8a3c67f5460d06e512bbdeeac778..7cb301da747440dd9d14d8e68aced335450b2be0 100644 (file)
 MODULE_AUTHOR("Tilera");
 MODULE_LICENSE("GPL");
 
-
-#define IS_MULTICAST(mac_addr) \
-       (((u8 *)(mac_addr))[0] & 0x01)
-
-#define IS_BROADCAST(mac_addr) \
-       (((u16 *)(mac_addr))[0] == 0xffff)
-
-
 /*
  * Queue of incoming packets for a specific cpu and device.
  *
@@ -795,7 +787,7 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
                /*
                 * FIXME: Implement HW multicast filter.
                 */
-               if (!IS_MULTICAST(buf) && !IS_BROADCAST(buf)) {
+               if (is_unicast_ether_addr(buf)) {
                        /* Filter packets not for our address. */
                        const u8 *mine = dev->dev_addr;
                        filter = compare_ether_addr(mine, buf);
index 73a3e0d93237c97127e4eff1f31c52b4915f1119..715e7b47e7e987ff47c502c229686911cae17bc5 100644 (file)
@@ -2032,7 +2032,7 @@ static void ucc_geth_set_multi(struct net_device *dev)
                        netdev_for_each_mc_addr(ha, dev) {
                                /* Only support group multicast for now.
                                 */
-                               if (!(ha->addr[0] & 1))
+                               if (!is_multicast_ether_addr(ha->addr))
                                        continue;
 
                                /* Ask CPM to run CRC and set bit in
index 593c104ab19997eacf5bc35b238d4676293d71c2..d776c4a8d3c1bda74b9699156d5b9690eed74863 100644 (file)
@@ -1021,13 +1021,15 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
                    (temp > CDC_NCM_MAX_DATAGRAM_SIZE) || (temp < ETH_HLEN)) {
                        pr_debug("invalid frame detected (ignored)"
                                "offset[%u]=%u, length=%u, skb=%p\n",
-                                                       x, offset, temp, skb);
+                                                       x, offset, temp, skb_in);
                        if (!x)
                                goto error;
                        break;
 
                } else {
                        skb = skb_clone(skb_in, GFP_ATOMIC);
+                       if (!skb)
+                               goto error;
                        skb->len = temp;
                        skb->data = ((u8 *)skb_in->data) + offset;
                        skb_set_tail_pointer(skb, temp);
index 1ac9b568f1b0cfcc62e1fd7f7f1c32f0749849f5..c81a6512c683d4dee03d0b515895ce2846ebf4ec 100644 (file)
@@ -4120,6 +4120,7 @@ int vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override)
               "hotplug event.\n");
 
 out:
+       release_firmware(fw);
        return ret;
 }
 
index 01880aa13e369af80b9e4059b7e60dc3c8907860..ea2e7d714bdad0888e070dc61faf5acfba26ff15 100644 (file)
@@ -954,6 +954,9 @@ static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
                                &adc_dc_cal_multi_sample;
                }
                ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
+
+               if (AR_SREV_9287(ah))
+                       ah->supp_cals &= ~ADC_GAIN_CAL;
        }
 }
 
index 088f141f20064fffaf21849978d1efb5b51ac47c..749a93608664916f4c737bb15fa1d58fa03e204a 100644 (file)
@@ -226,6 +226,10 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
            eep->baseEepHeader.pwdclkind == 0)
                ah->need_an_top2_fixup = 1;
 
+       if ((common->bus_ops->ath_bus_type == ATH_USB) &&
+           (AR_SREV_9280(ah)))
+               eep->modalHeader[0].xpaBiasLvl = 0;
+
        return 0;
 }
 
index a099b3e87ed3c4477c6fcb24514cd43a7529054c..1ce506f231107a22893f9da8aba0faa8dde5e686 100644 (file)
@@ -433,6 +433,7 @@ void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id,
 void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
                        enum htc_endpoint_id ep_id, bool txok);
 
+int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv);
 void ath9k_htc_station_work(struct work_struct *work);
 void ath9k_htc_aggr_work(struct work_struct *work);
 void ath9k_ani_work(struct work_struct *work);;
index 845b4c938d166090efc045ea11083e1cf0ce0789..f4d576bc3ccdbce3bef81d4702a756e9b900a34d 100644 (file)
@@ -301,6 +301,16 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
 
        priv->nstations++;
 
+       /*
+        * Set chainmask etc. on the target.
+        */
+       ret = ath9k_htc_update_cap_target(priv);
+       if (ret)
+               ath_dbg(common, ATH_DBG_CONFIG,
+                       "Failed to update capability in target\n");
+
+       priv->ah->is_monitoring = true;
+
        return 0;
 
 err_vif:
@@ -328,6 +338,7 @@ static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
        }
 
        priv->nstations--;
+       priv->ah->is_monitoring = false;
 
        return 0;
 }
@@ -419,7 +430,7 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
        return 0;
 }
 
-static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
+int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
 {
        struct ath9k_htc_cap_target tcap;
        int ret;
@@ -1186,6 +1197,20 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
                }
        }
 
+       /*
+        * Monitor interface should be added before
+        * IEEE80211_CONF_CHANGE_CHANNEL is handled.
+        */
+       if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
+               if (conf->flags & IEEE80211_CONF_MONITOR) {
+                       if (ath9k_htc_add_monitor_interface(priv))
+                               ath_err(common, "Failed to set monitor mode\n");
+                       else
+                               ath_dbg(common, ATH_DBG_CONFIG,
+                                       "HW opmode set to Monitor mode\n");
+               }
+       }
+
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
                struct ieee80211_channel *curchan = hw->conf.channel;
                int pos = curchan->hw_value;
@@ -1221,16 +1246,6 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
                ath_update_txpow(priv);
        }
 
-       if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
-               if (conf->flags & IEEE80211_CONF_MONITOR) {
-                       if (ath9k_htc_add_monitor_interface(priv))
-                               ath_err(common, "Failed to set monitor mode\n");
-                       else
-                               ath_dbg(common, ATH_DBG_CONFIG,
-                                       "HW opmode set to Monitor mode\n");
-               }
-       }
-
        if (changed & IEEE80211_CONF_CHANGE_IDLE) {
                mutex_lock(&priv->htc_pm_lock);
                if (!priv->ps_idle) {
index fde978665e07c63328e675823eb6d53f65fbf7c7..1afb8bb85756ee55e5a2a82d5f1f825279c803ea 100644 (file)
@@ -436,9 +436,10 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah)
 
 static int ath9k_hw_post_init(struct ath_hw *ah)
 {
+       struct ath_common *common = ath9k_hw_common(ah);
        int ecode;
 
-       if (!AR_SREV_9271(ah)) {
+       if (common->bus_ops->ath_bus_type != ATH_USB) {
                if (!ath9k_hw_chip_test(ah))
                        return -ENODEV;
        }
@@ -1213,7 +1214,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ah->txchainmask = common->tx_chainmask;
        ah->rxchainmask = common->rx_chainmask;
 
-       if (!ah->chip_fullsleep) {
+       if ((common->bus_ops->ath_bus_type != ATH_USB) && !ah->chip_fullsleep) {
                ath9k_hw_abortpcurecv(ah);
                if (!ath9k_hw_stopdmarecv(ah)) {
                        ath_dbg(common, ATH_DBG_XMIT,
index bd8a4134edebcae378d89fa9add3c2ae7f4dea9f..2176edede39b78db45e337e313c860802b92f66b 100644 (file)
@@ -518,22 +518,21 @@ static int prism2_config(struct pcmcia_device *link)
        hw_priv->link = link;
 
        /*
-        * Make sure the IRQ handler cannot proceed until at least
-        * dev->base_addr is initialized.
+        * We enable IRQ here, but IRQ handler will not proceed
+        * until dev->base_addr is set below. This protect us from
+        * receive interrupts when driver is not initialized.
         */
-       spin_lock_irqsave(&local->irq_init_lock, flags);
-
        ret = pcmcia_request_irq(link, prism2_interrupt);
        if (ret)
-               goto failed_unlock;
+               goto failed;
 
        ret = pcmcia_enable_device(link);
        if (ret)
-               goto failed_unlock;
+               goto failed;
 
+       spin_lock_irqsave(&local->irq_init_lock, flags);
        dev->irq = link->irq;
        dev->base_addr = link->resource[0]->start;
-
        spin_unlock_irqrestore(&local->irq_init_lock, flags);
 
        local->shutdown = 0;
@@ -546,8 +545,6 @@ static int prism2_config(struct pcmcia_device *link)
 
        return ret;
 
- failed_unlock:
-       spin_unlock_irqrestore(&local->irq_init_lock, flags);
  failed:
        kfree(hw_priv);
        prism2_release((u_long)link);
index 8d6ed5f6f46f4a423e31943dc70b70fd3727569f..ae438ed80c2fa73dcafc17577c54194f6cc054fb 100644 (file)
@@ -1973,6 +1973,13 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
 
        inta = ipw_read32(priv, IPW_INTA_RW);
        inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
+
+       if (inta == 0xFFFFFFFF) {
+               /* Hardware disappeared */
+               IPW_WARNING("TASKLET INTA == 0xFFFFFFFF\n");
+               /* Only handle the cached INTA values */
+               inta = 0;
+       }
        inta &= (IPW_INTA_MASK_ALL & inta_mask);
 
        /* Add any cached INTA values that need to be handled */
index 76b2318a7dc776a460c335133289953cff8806fc..f618b9623e5a6d38753a8ee010fb61f4f8777820 100644 (file)
@@ -618,7 +618,7 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
        else
                *burst_possible = false;
 
-       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+       if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
                *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
 
        if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)
index 73631c6fbb305352deab11e7703a7ebcd56a1437..ace0b668c04ea01f42a5fdaa140c204fd5339667 100644 (file)
@@ -363,12 +363,12 @@ int rt2x00pci_resume(struct pci_dev *pci_dev)
        struct rt2x00_dev *rt2x00dev = hw->priv;
 
        if (pci_set_power_state(pci_dev, PCI_D0) ||
-           pci_enable_device(pci_dev) ||
-           pci_restore_state(pci_dev)) {
+           pci_enable_device(pci_dev)) {
                ERROR(rt2x00dev, "Failed to resume device.\n");
                return -EIO;
        }
 
+       pci_restore_state(pci_dev);
        return rt2x00lib_resume(rt2x00dev);
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_resume);
index 7c24dcef29897fce34da71e112669f045fdd820e..44b0aeee83e52c1bcbeeaa73417ec577681cfe0a 100644 (file)
@@ -168,8 +168,9 @@ static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag)
        u32 mask_bits = desc->masked;
        unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
                                                PCI_MSIX_ENTRY_VECTOR_CTRL;
-       mask_bits &= ~1;
-       mask_bits |= flag;
+       mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
+       if (flag)
+               mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
        writel(mask_bits, desc->mask_base + offset);
 
        return mask_bits;
index feff3bee6fe5fcaf1b107e0f3907d984ca882b5b..65c42f80f23ef6dc320c9cdb84270c17f8dddae2 100644 (file)
@@ -6,12 +6,6 @@
 #ifndef MSI_H
 #define MSI_H
 
-#define PCI_MSIX_ENTRY_SIZE            16
-#define  PCI_MSIX_ENTRY_LOWER_ADDR     0
-#define  PCI_MSIX_ENTRY_UPPER_ADDR     4
-#define  PCI_MSIX_ENTRY_DATA           8
-#define  PCI_MSIX_ENTRY_VECTOR_CTRL    12
-
 #define msi_control_reg(base)          (base + PCI_MSI_FLAGS)
 #define msi_lower_address_reg(base)    (base + PCI_MSI_ADDRESS_LO)
 #define msi_upper_address_reg(base)    (base + PCI_MSI_ADDRESS_HI)
index 24e19c594e57abe55aa284054bde746606863694..6fe0772e0e7de2432d9353d8871b3bc5e8ba04ee 100644 (file)
@@ -46,9 +46,9 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
        struct pci_dev *pci_dev = context;
 
        if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) {
+               pci_wakeup_event(pci_dev);
                pci_check_pme_status(pci_dev);
                pm_runtime_resume(&pci_dev->dev);
-               pci_wakeup_event(pci_dev);
                if (pci_dev->subordinate)
                        pci_pme_wakeup_bus(pci_dev->subordinate);
        }
@@ -399,6 +399,7 @@ static int __init acpi_pci_init(void)
 
        if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
                printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
+               pcie_clear_aspm();
                pcie_no_aspm();
        }
 
index 8a6f797de8e55af1b3d0380aefb2173b58ab9fa5..88246dd4645258d865102cbc20dba99ccfe0a5e3 100644 (file)
@@ -338,7 +338,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
 }
 
 /**
- * __pci_device_probe()
+ * __pci_device_probe - check if a driver wants to claim a specific PCI device
  * @drv: driver to call to check if it wants the PCI device
  * @pci_dev: PCI device being probed
  * 
@@ -449,7 +449,8 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
                        return error;
        }
 
-       return pci_restore_state(pci_dev);
+       pci_restore_state(pci_dev);
+       return 0;
 }
 
 static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
index f7b68ca6cc98301d0d4d13bdc43d7af8be6f1ab4..775e933c222547d14c30840daebd16b5a438be72 100644 (file)
@@ -47,6 +47,10 @@ static int __init pci_stub_init(void)
        if (rc)
                return rc;
 
+       /* no ids passed actually */
+       if (ids[0] == '\0')
+               return 0;
+
        /* add ids specified in the module parameter */
        p = ids;
        while ((id = strsep(&p, ","))) {
@@ -54,6 +58,9 @@ static int __init pci_stub_init(void)
                        subdevice = PCI_ANY_ID, class=0, class_mask=0;
                int fields;
 
+               if (!strlen(id))
+                       continue;
+
                fields = sscanf(id, "%x:%x:%x:%x:%x:%x",
                                &vendor, &device, &subvendor, &subdevice,
                                &class, &class_mask);
index 63d5042f2079141a8740d77fae118d9c5bb707af..8ecaac983923d9c6b22c2e0246907db089b5e43a 100644 (file)
@@ -1149,7 +1149,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
                sysfs_bin_attr_init(attr);
                attr->size = rom_size;
                attr->attr.name = "rom";
-               attr->attr.mode = S_IRUSR;
+               attr->attr.mode = S_IRUSR | S_IWUSR;
                attr->read = pci_read_rom;
                attr->write = pci_write_rom;
                retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
index 710c8a29be0d5b8028eafb239bde42ae5d5934b6..b714d787bdddeb8306324dada56412c6eef2ac68 100644 (file)
@@ -937,14 +937,13 @@ pci_save_state(struct pci_dev *dev)
  * pci_restore_state - Restore the saved state of a PCI device
  * @dev: - PCI device that we're dealing with
  */
-int 
-pci_restore_state(struct pci_dev *dev)
+void pci_restore_state(struct pci_dev *dev)
 {
        int i;
        u32 val;
 
        if (!dev->state_saved)
-               return 0;
+               return;
 
        /* PCI Express register must be restored first */
        pci_restore_pcie_state(dev);
@@ -968,8 +967,6 @@ pci_restore_state(struct pci_dev *dev)
        pci_restore_iov_state(dev);
 
        dev->state_saved = false;
-
-       return 0;
 }
 
 static int do_pci_enable_device(struct pci_dev *dev, int bars)
@@ -1300,22 +1297,6 @@ bool pci_check_pme_status(struct pci_dev *dev)
        return ret;
 }
 
-/*
- * Time to wait before the system can be put into a sleep state after reporting
- * a wakeup event signaled by a PCI device.
- */
-#define PCI_WAKEUP_COOLDOWN    100
-
-/**
- * pci_wakeup_event - Report a wakeup event related to a given PCI device.
- * @dev: Device to report the wakeup event for.
- */
-void pci_wakeup_event(struct pci_dev *dev)
-{
-       if (device_may_wakeup(&dev->dev))
-               pm_wakeup_event(&dev->dev, PCI_WAKEUP_COOLDOWN);
-}
-
 /**
  * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set.
  * @dev: Device to handle.
@@ -1327,8 +1308,8 @@ void pci_wakeup_event(struct pci_dev *dev)
 static int pci_pme_wakeup(struct pci_dev *dev, void *ign)
 {
        if (pci_check_pme_status(dev)) {
-               pm_request_resume(&dev->dev);
                pci_wakeup_event(dev);
+               pm_request_resume(&dev->dev);
        }
        return 0;
 }
index 7d33f6673868ff5b3254e136770dae4edc635faf..f69d6e0fda75569fc2a8faf1536fc2a4381bc41e 100644 (file)
@@ -74,6 +74,12 @@ 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);
 
+static inline void pci_wakeup_event(struct pci_dev *dev)
+{
+       /* Wait 100 ms before the system can be put into a sleep state. */
+       pm_wakeup_event(&dev->dev, 100);
+}
+
 static inline bool pci_is_bridge(struct pci_dev *pci_dev)
 {
        return !!(pci_dev->subordinate);
@@ -140,14 +146,6 @@ static inline void pci_no_msi(void) { }
 static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
 #endif
 
-#ifdef CONFIG_PCIEAER
-void pci_no_aer(void);
-bool pci_aer_available(void);
-#else
-static inline void pci_no_aer(void) { }
-static inline bool pci_aer_available(void) { return false; }
-#endif
-
 static inline int pci_no_d1d2(struct pci_dev *dev)
 {
        unsigned int parent_dstates = 0;
index 2b2b6508efde1c951afe0e913394a1babeab1d1e..58ad7917553c34e8933f7a0151796412cbeb6c12 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/pci-acpi.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
index 9656e3060412d137109b9978ed0b5a9a4fa2b15c..80c11d1314999c77f9666dd6f892610b90e07bd0 100644 (file)
@@ -132,7 +132,6 @@ static inline int aer_osc_setup(struct pcie_device *pciedev)
 
 #ifdef CONFIG_ACPI_APEI
 extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
-extern bool aer_acpi_firmware_first(void);
 #else
 static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
 {
@@ -140,8 +139,6 @@ static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
                return pci_dev->__aer_firmware_first;
        return 0;
 }
-
-static inline bool aer_acpi_firmware_first(void) { return false; }
 #endif
 
 static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev,
index 71222814c1ecf602880352d8cb3df7ff7930d5db..3188cd96b3386c2992d2b3df1d5a7bb0e363c266 100644 (file)
@@ -68,7 +68,7 @@ struct pcie_link_state {
        struct aspm_latency acceptable[8];
 };
 
-static int aspm_disabled, aspm_force;
+static int aspm_disabled, aspm_force, aspm_clear_state;
 static DEFINE_MUTEX(aspm_lock);
 static LIST_HEAD(link_list);
 
@@ -139,7 +139,7 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
 {
        /* Don't enable Clock PM if the link is not Clock PM capable */
        if (!link->clkpm_capable && enable)
-               return;
+               enable = 0;
        /* Need nothing if the specified equals to current state */
        if (link->clkpm_enabled == enable)
                return;
@@ -498,6 +498,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
        struct pci_dev *child;
        int pos;
        u32 reg32;
+
+       if (aspm_clear_state)
+               return -EINVAL;
+
        /*
         * Some functions in a slot might not all be PCIe functions,
         * very strange. Disable ASPM for the whole slot
@@ -563,12 +567,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
        struct pcie_link_state *link;
        int blacklist = !!pcie_aspm_sanity_check(pdev);
 
-       if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state)
+       if (!pci_is_pcie(pdev) || pdev->link_state)
                return;
        if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
            pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
                return;
 
+       if (aspm_disabled && !aspm_clear_state)
+               return;
+
        /* VIA has a strange chipset, root port is under a bridge */
        if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
            pdev->bus->self)
@@ -641,7 +648,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
        struct pci_dev *parent = pdev->bus->self;
        struct pcie_link_state *link, *root, *parent_link;
 
-       if (aspm_disabled || !pci_is_pcie(pdev) ||
+       if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) ||
            !parent || !parent->link_state)
                return;
        if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
@@ -899,6 +906,12 @@ static int __init pcie_aspm_disable(char *str)
 
 __setup("pcie_aspm=", pcie_aspm_disable);
 
+void pcie_clear_aspm(void)
+{
+       if (!aspm_force)
+               aspm_clear_state = 1;
+}
+
 void pcie_no_aspm(void)
 {
        if (!aspm_force)
index 2f3c904072273fcdaf5c5a660405281720dff7aa..0057344a3fcb231507a115d4d97ac84125da2161 100644 (file)
@@ -26,9 +26,6 @@
 #include "../pci.h"
 #include "portdrv.h"
 
-#define PCI_EXP_RTSTA_PME      0x10000 /* PME status */
-#define PCI_EXP_RTSTA_PENDING  0x20000 /* PME pending */
-
 /*
  * If this switch is set, MSI will not be used for PCIe PME signaling.  This
  * causes the PCIe port driver to use INTx interrupts only, but it turns out
@@ -73,22 +70,6 @@ void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable)
        pci_write_config_word(dev, rtctl_pos, rtctl);
 }
 
-/**
- * pcie_pme_clear_status - Clear root port PME interrupt status.
- * @dev: PCIe root port or event collector.
- */
-static void pcie_pme_clear_status(struct pci_dev *dev)
-{
-       int rtsta_pos;
-       u32 rtsta;
-
-       rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA;
-
-       pci_read_config_dword(dev, rtsta_pos, &rtsta);
-       rtsta |= PCI_EXP_RTSTA_PME;
-       pci_write_config_dword(dev, rtsta_pos, rtsta);
-}
-
 /**
  * pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#.
  * @bus: PCI bus to scan.
@@ -103,8 +84,8 @@ static bool pcie_pme_walk_bus(struct pci_bus *bus)
        list_for_each_entry(dev, &bus->devices, bus_list) {
                /* Skip PCIe devices in case we started from a root port. */
                if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) {
-                       pm_request_resume(&dev->dev);
                        pci_wakeup_event(dev);
+                       pm_request_resume(&dev->dev);
                        ret = true;
                }
 
@@ -206,8 +187,8 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id)
                /* The device is there, but we have to check its PME status. */
                found = pci_check_pme_status(dev);
                if (found) {
-                       pm_request_resume(&dev->dev);
                        pci_wakeup_event(dev);
+                       pm_request_resume(&dev->dev);
                }
                pci_dev_put(dev);
        } else if (devfn) {
@@ -253,7 +234,7 @@ static void pcie_pme_work_fn(struct work_struct *work)
                         * Clear PME status of the port.  If there are other
                         * pending PMEs, the status will be set again.
                         */
-                       pcie_pme_clear_status(port);
+                       pcie_clear_root_pme_status(port);
 
                        spin_unlock_irq(&data->lock);
                        pcie_pme_handle_request(port, rtsta & 0xffff);
@@ -378,7 +359,7 @@ static int pcie_pme_probe(struct pcie_device *srv)
 
        port = srv->port;
        pcie_pme_interrupt_enable(port, false);
-       pcie_pme_clear_status(port);
+       pcie_clear_root_pme_status(port);
 
        ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv);
        if (ret) {
@@ -402,7 +383,7 @@ static int pcie_pme_suspend(struct pcie_device *srv)
 
        spin_lock_irq(&data->lock);
        pcie_pme_interrupt_enable(port, false);
-       pcie_pme_clear_status(port);
+       pcie_clear_root_pme_status(port);
        data->noirq = true;
        spin_unlock_irq(&data->lock);
 
@@ -422,7 +403,7 @@ static int pcie_pme_resume(struct pcie_device *srv)
 
        spin_lock_irq(&data->lock);
        data->noirq = false;
-       pcie_pme_clear_status(port);
+       pcie_clear_root_pme_status(port);
        pcie_pme_interrupt_enable(port, true);
        spin_unlock_irq(&data->lock);
 
index 7b5aba0a3291107a231a8b6ee6a90cacf0c4557c..bd00a01aef1463a09691944446991bb14bddcfed 100644 (file)
@@ -20,9 +20,6 @@
 
 #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
 
-extern bool pcie_ports_disabled;
-extern bool pcie_ports_auto;
-
 extern struct bus_type pcie_port_bus_type;
 extern int pcie_port_device_register(struct pci_dev *dev);
 #ifdef CONFIG_PM
@@ -35,6 +32,8 @@ extern void pcie_port_bus_unregister(void);
 
 struct pci_dev;
 
+extern void pcie_clear_root_pme_status(struct pci_dev *dev);
+
 #ifdef CONFIG_PCIE_PME
 extern bool pcie_pme_msi_disabled;
 
index 5982b6a63b895a989b2c2888847795bffda6f316..a86b56e5f2f2c5c4761f029c79c674b078f13a1d 100644 (file)
@@ -33,7 +33,7 @@
  */
 int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
 {
-       acpi_status status;
+       struct acpi_pci_root *root;
        acpi_handle handle;
        u32 flags;
 
@@ -44,26 +44,11 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
        if (!handle)
                return -EINVAL;
 
-       flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
-               | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
-               | OSC_PCI_EXPRESS_PME_CONTROL;
-
-       if (pci_aer_available()) {
-               if (aer_acpi_firmware_first())
-                       dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
-               else
-                       flags |= OSC_PCI_EXPRESS_AER_CONTROL;
-       }
-
-       status = acpi_pci_osc_control_set(handle, &flags,
-                                       OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
-       if (ACPI_FAILURE(status)) {
-               dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n",
-                       status);
+       root = acpi_pci_find_root(handle);
+       if (!root)
                return -ENODEV;
-       }
 
-       dev_info(&port->dev, "ACPI _OSC control granted for 0x%02x\n", flags);
+       flags = root->osc_control_set;
 
        *srv_mask = PCIE_PORT_SERVICE_VC;
        if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)
index a9c222d79ebc5dc32cd6c4fad37f616ac291ff6a..5130d0d22390bba5266fdfb18a10cb7aa2dccb7d 100644 (file)
@@ -241,17 +241,17 @@ static int get_port_device_capability(struct pci_dev *dev)
        int cap_mask;
        int err;
 
+       if (pcie_ports_disabled)
+               return 0;
+
        err = pcie_port_platform_notify(dev, &cap_mask);
-       if (pcie_ports_auto) {
-               if (err) {
-                       pcie_no_aspm();
-                       return 0;
-               }
-       } else {
+       if (!pcie_ports_auto) {
                cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
                                | PCIE_PORT_SERVICE_VC;
                if (pci_aer_available())
                        cap_mask |= PCIE_PORT_SERVICE_AER;
+       } else if (err) {
+                       return 0;
        }
 
        pos = pci_pcie_cap(dev);
@@ -349,15 +349,18 @@ int pcie_port_device_register(struct pci_dev *dev)
        int status, capabilities, i, nr_service;
        int irqs[PCIE_PORT_DEVICE_MAXSERVICES];
 
-       /* Get and check PCI Express port services */
-       capabilities = get_port_device_capability(dev);
-       if (!capabilities)
-               return -ENODEV;
-
        /* Enable PCI Express port device */
        status = pci_enable_device(dev);
        if (status)
                return status;
+
+       /* Get and check PCI Express port services */
+       capabilities = get_port_device_capability(dev);
+       if (!capabilities) {
+               pcie_no_aspm();
+               return 0;
+       }
+
        pci_set_master(dev);
        /*
         * Initialize service irqs. Don't use service devices that
index f9033e190fb62060e701ebf44b0eb1d3dfbefa90..e0610bda1dea8ace0c03c202ff52e33a278036ff 100644 (file)
@@ -57,6 +57,22 @@ __setup("pcie_ports=", pcie_port_setup);
 
 /* global data */
 
+/**
+ * pcie_clear_root_pme_status - Clear root port PME interrupt status.
+ * @dev: PCIe root port or event collector.
+ */
+void pcie_clear_root_pme_status(struct pci_dev *dev)
+{
+       int rtsta_pos;
+       u32 rtsta;
+
+       rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA;
+
+       pci_read_config_dword(dev, rtsta_pos, &rtsta);
+       rtsta |= PCI_EXP_RTSTA_PME;
+       pci_write_config_dword(dev, rtsta_pos, rtsta);
+}
+
 static int pcie_portdrv_restore_config(struct pci_dev *dev)
 {
        int retval;
@@ -69,6 +85,20 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev)
 }
 
 #ifdef CONFIG_PM
+static int pcie_port_resume_noirq(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       /*
+        * Some BIOSes forget to clear Root PME Status bits after system wakeup
+        * which breaks ACPI-based runtime wakeup on PCI Express, so clear those
+        * bits now just in case (shouldn't hurt).
+        */
+       if(pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+               pcie_clear_root_pme_status(pdev);
+       return 0;
+}
+
 static const struct dev_pm_ops pcie_portdrv_pm_ops = {
        .suspend        = pcie_port_device_suspend,
        .resume         = pcie_port_device_resume,
@@ -76,6 +106,7 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
        .thaw           = pcie_port_device_resume,
        .poweroff       = pcie_port_device_suspend,
        .restore        = pcie_port_device_resume,
+       .resume_noirq   = pcie_port_resume_noirq,
 };
 
 #define PCIE_PORTDRV_PM_OPS    (&pcie_portdrv_pm_ops)
@@ -327,10 +358,8 @@ static int __init pcie_portdrv_init(void)
 {
        int retval;
 
-       if (pcie_ports_disabled) {
-               pcie_no_aspm();
-               return -EACCES;
-       }
+       if (pcie_ports_disabled)
+               return pci_register_driver(&pcie_portdriver);
 
        dmi_check_system(pcie_portdrv_dmi_table);
 
index 60d83d983a36d7fb0be13eb056d4db3849e7fe21..61bf5d724139c80a93fd86350dd7ebb46f9eb8c0 100644 (file)
@@ -136,6 +136,16 @@ config BATTERY_MAX17040
          in handheld and portable equipment. The MAX17040 is configured
          to operate with a single lithium cell
 
+config BATTERY_MAX17042
+       tristate "Maxim MAX17042/8997/8966 Fuel Gauge"
+       depends on I2C
+       help
+         MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries
+         in handheld and portable equipment. The MAX17042 is configured
+         to operate with a single lithium cell. MAX8997 and MAX8966 are
+         multi-function devices that include fuel gauages that are compatible
+         with MAX17042.
+
 config BATTERY_Z2
        tristate "Z2 battery driver"
        depends on I2C && MACH_ZIPIT2
@@ -185,4 +195,14 @@ config CHARGER_TWL4030
        help
          Say Y here to enable support for TWL4030 Battery Charge Interface.
 
+config CHARGER_GPIO
+       tristate "GPIO charger"
+       depends on GPIOLIB
+       help
+         Say Y to include support for chargers which report their online status
+         through a GPIO pin.
+
+         This driver can be build as a module. If so, the module will be
+         called gpio-charger.
+
 endif # POWER_SUPPLY
index c75772eb157c09fe915d756ebe9ba38ee0c4e43f..8385bfae872836bf367e937b1f627cbe82c39421 100644 (file)
@@ -25,6 +25,7 @@ obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75.o
 obj-$(CONFIG_BATTERY_BQ27x00)  += bq27x00_battery.o
 obj-$(CONFIG_BATTERY_DA9030)   += da9030_battery.o
 obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
+obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
 obj-$(CONFIG_BATTERY_Z2)       += z2_battery.o
 obj-$(CONFIG_BATTERY_S3C_ADC)  += s3c_adc_battery.o
 obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
@@ -32,3 +33,4 @@ obj-$(CONFIG_BATTERY_JZ4740)  += jz4740-battery.o
 obj-$(CONFIG_BATTERY_INTEL_MID)        += intel_mid_battery.o
 obj-$(CONFIG_CHARGER_ISP1704)  += isp1704_charger.o
 obj-$(CONFIG_CHARGER_TWL4030)  += twl4030_charger.o
+obj-$(CONFIG_CHARGER_GPIO)     += gpio-charger.o
index 039f41ae217d5beedff750f992c795591ae5c31f..548d263b1ad0b1444cf65198c112e7c237b9f1bc 100644 (file)
@@ -295,7 +295,7 @@ static struct {
 static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state)
 {
        /* flush all pending status updates */
-       flush_scheduled_work();
+       flush_work_sync(&bat_work);
        return 0;
 }
 
@@ -362,7 +362,7 @@ err_psy_reg_bu:
 err_psy_reg_main:
 
        /* see comment in collie_bat_remove */
-       flush_scheduled_work();
+       cancel_work_sync(&bat_work);
 
        i--;
 err_gpio:
@@ -382,12 +382,11 @@ static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
        power_supply_unregister(&collie_bat_main.psy);
 
        /*
-        * now flush all pending work.
-        * we won't get any more schedules, since all
-        * sources (isr and external_power_changed)
-        * are unregistered now.
+        * Now cancel the bat_work.  We won't get any more schedules,
+        * since all sources (isr and external_power_changed) are
+        * unregistered now.
         */
-       flush_scheduled_work();
+       cancel_work_sync(&bat_work);
 
        for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
                gpio_free(gpios[i].gpio);
index e7f89785beefa6114e8afc0136265bdbc69f8c7d..e534290f32561d6d8322375f6baccf086f0c6de1 100644 (file)
@@ -212,7 +212,7 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di)
        if (di->rem_capacity > 100)
                di->rem_capacity = 100;
 
-       if (di->current_uA >= 100L)
+       if (di->current_uA < -100L)
                di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 36L)
                                        / (di->current_uA / 100L);
        else
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c
new file mode 100644 (file)
index 0000000..25b88ac
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *  Driver for chargers which report their online status through a GPIO pin
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+
+#include <linux/power/gpio-charger.h>
+
+struct gpio_charger {
+       const struct gpio_charger_platform_data *pdata;
+       unsigned int irq;
+
+       struct power_supply charger;
+};
+
+static irqreturn_t gpio_charger_irq(int irq, void *devid)
+{
+       struct power_supply *charger = devid;
+
+       power_supply_changed(charger);
+
+       return IRQ_HANDLED;
+}
+
+static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy)
+{
+       return container_of(psy, struct gpio_charger, charger);
+}
+
+static int gpio_charger_get_property(struct power_supply *psy,
+               enum power_supply_property psp, union power_supply_propval *val)
+{
+       struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy);
+       const struct gpio_charger_platform_data *pdata = gpio_charger->pdata;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = gpio_get_value(pdata->gpio);
+               val->intval ^= pdata->gpio_active_low;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static enum power_supply_property gpio_charger_properties[] = {
+       POWER_SUPPLY_PROP_ONLINE,
+};
+
+static int __devinit gpio_charger_probe(struct platform_device *pdev)
+{
+       const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_charger *gpio_charger;
+       struct power_supply *charger;
+       int ret;
+       int irq;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "No platform data\n");
+               return -EINVAL;
+       }
+
+       if (!gpio_is_valid(pdata->gpio)) {
+               dev_err(&pdev->dev, "Invalid gpio pin\n");
+               return -EINVAL;
+       }
+
+       gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL);
+       if (!gpio_charger) {
+               dev_err(&pdev->dev, "Failed to alloc driver structure\n");
+               return -ENOMEM;
+       }
+
+       charger = &gpio_charger->charger;
+
+       charger->name = pdata->name ? pdata->name : "gpio-charger";
+       charger->type = pdata->type;
+       charger->properties = gpio_charger_properties;
+       charger->num_properties = ARRAY_SIZE(gpio_charger_properties);
+       charger->get_property = gpio_charger_get_property;
+       charger->supplied_to = pdata->supplied_to;
+       charger->num_supplicants = pdata->num_supplicants;
+
+       ret = gpio_request(pdata->gpio, dev_name(&pdev->dev));
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret);
+               goto err_free;
+       }
+       ret = gpio_direction_input(pdata->gpio);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret);
+               goto err_gpio_free;
+       }
+
+       gpio_charger->pdata = pdata;
+
+       ret = power_supply_register(&pdev->dev, charger);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register power supply: %d\n",
+                       ret);
+               goto err_gpio_free;
+       }
+
+       irq = gpio_to_irq(pdata->gpio);
+       if (irq > 0) {
+               ret = request_any_context_irq(irq, gpio_charger_irq,
+                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                               dev_name(&pdev->dev), charger);
+               if (ret)
+                       dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret);
+               else
+                       gpio_charger->irq = irq;
+       }
+
+       platform_set_drvdata(pdev, gpio_charger);
+
+       return 0;
+
+err_gpio_free:
+       gpio_free(pdata->gpio);
+err_free:
+       kfree(gpio_charger);
+       return ret;
+}
+
+static int __devexit gpio_charger_remove(struct platform_device *pdev)
+{
+       struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
+
+       if (gpio_charger->irq)
+               free_irq(gpio_charger->irq, &gpio_charger->charger);
+
+       power_supply_unregister(&gpio_charger->charger);
+
+       gpio_free(gpio_charger->pdata->gpio);
+
+       platform_set_drvdata(pdev, NULL);
+       kfree(gpio_charger);
+
+       return 0;
+}
+
+static struct platform_driver gpio_charger_driver = {
+       .probe = gpio_charger_probe,
+       .remove = __devexit_p(gpio_charger_remove),
+       .driver = {
+               .name = "gpio-charger",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init gpio_charger_init(void)
+{
+       return platform_driver_register(&gpio_charger_driver);
+}
+module_init(gpio_charger_init);
+
+static void __exit gpio_charger_exit(void)
+{
+       platform_driver_unregister(&gpio_charger_driver);
+}
+module_exit(gpio_charger_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-charger");
index 36cf402c06772b6b34a7d5dd1c042c46cadd8ad2..bce3a01da2f0f33137e5901c066cc0f3f2a0f48b 100644 (file)
@@ -765,7 +765,7 @@ static int __devexit platform_pmic_battery_remove(struct platform_device *pdev)
        power_supply_unregister(&pbi->usb);
        power_supply_unregister(&pbi->batt);
 
-       flush_scheduled_work();
+       cancel_work_sync(&pbi->handler);
        kfree(pbi);
        return 0;
 }
index 72512185f3e281febf049f23dde76464782ed92c..2ad9b14a5ce37c4ec15f8cb8b319c7845e982c4f 100644 (file)
@@ -59,10 +59,60 @@ struct isp1704_charger {
        struct notifier_block   nb;
        struct work_struct      work;
 
-       char                    model[7];
+       /* properties */
+       char                    model[8];
        unsigned                present:1;
+       unsigned                online:1;
+       unsigned                current_max;
+
+       /* temp storage variables */
+       unsigned long           event;
+       unsigned                max_power;
 };
 
+/*
+ * Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB
+ * chargers).
+ *
+ * REVISIT: The method is defined in Battery Charging Specification and is
+ * applicable to any ULPI transceiver. Nothing isp170x specific here.
+ */
+static inline int isp1704_charger_type(struct isp1704_charger *isp)
+{
+       u8 reg;
+       u8 func_ctrl;
+       u8 otg_ctrl;
+       int type = POWER_SUPPLY_TYPE_USB_DCP;
+
+       func_ctrl = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
+       otg_ctrl = otg_io_read(isp->otg, ULPI_OTG_CTRL);
+
+       /* disable pulldowns */
+       reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN;
+       otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), reg);
+
+       /* full speed */
+       otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+                       ULPI_FUNC_CTRL_XCVRSEL_MASK);
+       otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL),
+                       ULPI_FUNC_CTRL_FULL_SPEED);
+
+       /* Enable strong pull-up on DP (1.5K) and reset */
+       reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
+       otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), reg);
+       usleep_range(1000, 2000);
+
+       reg = otg_io_read(isp->otg, ULPI_DEBUG);
+       if ((reg & 3) != 3)
+               type = POWER_SUPPLY_TYPE_USB_CDP;
+
+       /* recover original state */
+       otg_io_write(isp->otg, ULPI_FUNC_CTRL, func_ctrl);
+       otg_io_write(isp->otg, ULPI_OTG_CTRL, otg_ctrl);
+
+       return type;
+}
+
 /*
  * ISP1704 detects PS/2 adapters as charger. To make sure the detected charger
  * is actually a dedicated charger, the following steps need to be taken.
@@ -127,16 +177,19 @@ static inline int isp1704_charger_verify(struct isp1704_charger *isp)
 static inline int isp1704_charger_detect(struct isp1704_charger *isp)
 {
        unsigned long   timeout;
-       u8              r;
+       u8              pwr_ctrl;
        int             ret = 0;
 
+       pwr_ctrl = otg_io_read(isp->otg, ISP1704_PWR_CTRL);
+
        /* set SW control bit in PWR_CTRL register */
        otg_io_write(isp->otg, ISP1704_PWR_CTRL,
                        ISP1704_PWR_CTRL_SWCTRL);
 
        /* enable manual charger detection */
-       r = (ISP1704_PWR_CTRL_SWCTRL | ISP1704_PWR_CTRL_DPVSRC_EN);
-       otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), r);
+       otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
+                       ISP1704_PWR_CTRL_SWCTRL
+                       | ISP1704_PWR_CTRL_DPVSRC_EN);
        usleep_range(1000, 2000);
 
        timeout = jiffies + msecs_to_jiffies(300);
@@ -147,7 +200,10 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
                        ret = isp1704_charger_verify(isp);
                        break;
                }
-       } while (!time_after(jiffies, timeout));
+       } while (!time_after(jiffies, timeout) && isp->online);
+
+       /* recover original state */
+       otg_io_write(isp->otg, ISP1704_PWR_CTRL, pwr_ctrl);
 
        return ret;
 }
@@ -155,52 +211,92 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
 static void isp1704_charger_work(struct work_struct *data)
 {
        int                     detect;
+       unsigned long           event;
+       unsigned                power;
        struct isp1704_charger  *isp =
                container_of(data, struct isp1704_charger, work);
+       static DEFINE_MUTEX(lock);
 
-       /*
-        * FIXME Only supporting dedicated chargers even though isp1704 can
-        * detect HUB and HOST chargers. If the device has already been
-        * enumerated, the detection will break the connection.
-        */
-       if (isp->otg->state != OTG_STATE_B_IDLE)
-               return;
+       event = isp->event;
+       power = isp->max_power;
 
-       /* disable data pullups */
-       if (isp->otg->gadget)
-               usb_gadget_disconnect(isp->otg->gadget);
+       mutex_lock(&lock);
+
+       switch (event) {
+       case USB_EVENT_VBUS:
+               isp->online = true;
+
+               /* detect charger */
+               detect = isp1704_charger_detect(isp);
+
+               if (detect) {
+                       isp->present = detect;
+                       isp->psy.type = isp1704_charger_type(isp);
+               }
 
-       /* detect charger */
-       detect = isp1704_charger_detect(isp);
-       if (detect) {
-               isp->present = detect;
-               power_supply_changed(&isp->psy);
+               switch (isp->psy.type) {
+               case POWER_SUPPLY_TYPE_USB_DCP:
+                       isp->current_max = 1800;
+                       break;
+               case POWER_SUPPLY_TYPE_USB_CDP:
+                       /*
+                        * Only 500mA here or high speed chirp
+                        * handshaking may break
+                        */
+                       isp->current_max = 500;
+                       /* FALLTHROUGH */
+               case POWER_SUPPLY_TYPE_USB:
+               default:
+                       /* enable data pullups */
+                       if (isp->otg->gadget)
+                               usb_gadget_connect(isp->otg->gadget);
+               }
+               break;
+       case USB_EVENT_NONE:
+               isp->online = false;
+               isp->current_max = 0;
+               isp->present = 0;
+               isp->current_max = 0;
+               isp->psy.type = POWER_SUPPLY_TYPE_USB;
+
+               /*
+                * Disable data pullups. We need to prevent the controller from
+                * enumerating.
+                *
+                * FIXME: This is here to allow charger detection with Host/HUB
+                * chargers. The pullups may be enabled elsewhere, so this can
+                * not be the final solution.
+                */
+               if (isp->otg->gadget)
+                       usb_gadget_disconnect(isp->otg->gadget);
+               break;
+       case USB_EVENT_ENUMERATED:
+               if (isp->present)
+                       isp->current_max = 1800;
+               else
+                       isp->current_max = power;
+               break;
+       default:
+               goto out;
        }
 
-       /* enable data pullups */
-       if (isp->otg->gadget)
-               usb_gadget_connect(isp->otg->gadget);
+       power_supply_changed(&isp->psy);
+out:
+       mutex_unlock(&lock);
 }
 
 static int isp1704_notifier_call(struct notifier_block *nb,
-               unsigned long event, void *unused)
+               unsigned long event, void *power)
 {
        struct isp1704_charger *isp =
                container_of(nb, struct isp1704_charger, nb);
 
-       switch (event) {
-       case USB_EVENT_VBUS:
-               schedule_work(&isp->work);
-               break;
-       case USB_EVENT_NONE:
-               if (isp->present) {
-                       isp->present = 0;
-                       power_supply_changed(&isp->psy);
-               }
-               break;
-       default:
-               return NOTIFY_DONE;
-       }
+       isp->event = event;
+
+       if (power)
+               isp->max_power = *((unsigned *)power);
+
+       schedule_work(&isp->work);
 
        return NOTIFY_OK;
 }
@@ -216,6 +312,12 @@ static int isp1704_charger_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_PRESENT:
                val->intval = isp->present;
                break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = isp->online;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_MAX:
+               val->intval = isp->current_max;
+               break;
        case POWER_SUPPLY_PROP_MODEL_NAME:
                val->strval = isp->model;
                break;
@@ -230,6 +332,8 @@ static int isp1704_charger_get_property(struct power_supply *psy,
 
 static enum power_supply_property power_props[] = {
        POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_CURRENT_MAX,
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_MANUFACTURER,
 };
@@ -287,13 +391,13 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
        if (!isp->otg)
                goto fail0;
 
+       isp->dev = &pdev->dev;
+       platform_set_drvdata(pdev, isp);
+
        ret = isp1704_test_ulpi(isp);
        if (ret < 0)
                goto fail1;
 
-       isp->dev = &pdev->dev;
-       platform_set_drvdata(pdev, isp);
-
        isp->psy.name           = "isp1704";
        isp->psy.type           = POWER_SUPPLY_TYPE_USB;
        isp->psy.properties     = power_props;
@@ -318,6 +422,23 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
 
        dev_info(isp->dev, "registered with product id %s\n", isp->model);
 
+       /*
+        * Taking over the D+ pullup.
+        *
+        * FIXME: The device will be disconnected if it was already
+        * enumerated. The charger driver should be always loaded before any
+        * gadget is loaded.
+        */
+       if (isp->otg->gadget)
+               usb_gadget_disconnect(isp->otg->gadget);
+
+       /* Detect charger if VBUS is valid (the cable was already plugged). */
+       ret = otg_io_read(isp->otg, ULPI_USB_INT_STS);
+       if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) {
+               isp->event = USB_EVENT_VBUS;
+               schedule_work(&isp->work);
+       }
+
        return 0;
 fail2:
        power_supply_unregister(&isp->psy);
index a8108a73593e49e19b64ce29e72c45c8b3c9d879..02414db6a94c151208bab6ff51917765cc074db1 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 
 #include <linux/delay.h>
 #include <linux/gpio.h>
@@ -47,6 +48,8 @@ struct jz_battery {
 
        struct power_supply battery;
        struct delayed_work work;
+
+       struct mutex lock;
 };
 
 static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy)
@@ -68,6 +71,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery)
        unsigned long val;
        long voltage;
 
+       mutex_lock(&battery->lock);
+
        INIT_COMPLETION(battery->read_completion);
 
        enable_irq(battery->irq);
@@ -91,6 +96,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery)
        battery->cell->disable(battery->pdev);
        disable_irq(battery->irq);
 
+       mutex_unlock(&battery->lock);
+
        return voltage;
 }
 
@@ -240,6 +247,11 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
        struct jz_battery *jz_battery;
        struct power_supply *battery;
 
+       if (!pdata) {
+               dev_err(&pdev->dev, "No platform_data supplied\n");
+               return -ENXIO;
+       }
+
        jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL);
        if (!jz_battery) {
                dev_err(&pdev->dev, "Failed to allocate driver structure\n");
@@ -291,6 +303,7 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
        jz_battery->pdev = pdev;
 
        init_completion(&jz_battery->read_completion);
+       mutex_init(&jz_battery->lock);
 
        INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work);
 
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
new file mode 100644 (file)
index 0000000..c5c8805
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Fuel gauge driver for Maxim 17042 / 8966 / 8997
+ *  Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max17040_battery.c
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/power_supply.h>
+#include <linux/power/max17042_battery.h>
+
+enum max17042_register {
+       MAX17042_STATUS         = 0x00,
+       MAX17042_VALRT_Th       = 0x01,
+       MAX17042_TALRT_Th       = 0x02,
+       MAX17042_SALRT_Th       = 0x03,
+       MAX17042_AtRate         = 0x04,
+       MAX17042_RepCap         = 0x05,
+       MAX17042_RepSOC         = 0x06,
+       MAX17042_Age            = 0x07,
+       MAX17042_TEMP           = 0x08,
+       MAX17042_VCELL          = 0x09,
+       MAX17042_Current        = 0x0A,
+       MAX17042_AvgCurrent     = 0x0B,
+       MAX17042_Qresidual      = 0x0C,
+       MAX17042_SOC            = 0x0D,
+       MAX17042_AvSOC          = 0x0E,
+       MAX17042_RemCap         = 0x0F,
+       MAX17402_FullCAP        = 0x10,
+       MAX17042_TTE            = 0x11,
+       MAX17042_V_empty        = 0x12,
+
+       MAX17042_RSLOW          = 0x14,
+
+       MAX17042_AvgTA          = 0x16,
+       MAX17042_Cycles         = 0x17,
+       MAX17042_DesignCap      = 0x18,
+       MAX17042_AvgVCELL       = 0x19,
+       MAX17042_MinMaxTemp     = 0x1A,
+       MAX17042_MinMaxVolt     = 0x1B,
+       MAX17042_MinMaxCurr     = 0x1C,
+       MAX17042_CONFIG         = 0x1D,
+       MAX17042_ICHGTerm       = 0x1E,
+       MAX17042_AvCap          = 0x1F,
+       MAX17042_ManName        = 0x20,
+       MAX17042_DevName        = 0x21,
+       MAX17042_DevChem        = 0x22,
+
+       MAX17042_TempNom        = 0x24,
+       MAX17042_TempCold       = 0x25,
+       MAX17042_TempHot        = 0x26,
+       MAX17042_AIN            = 0x27,
+       MAX17042_LearnCFG       = 0x28,
+       MAX17042_SHFTCFG        = 0x29,
+       MAX17042_RelaxCFG       = 0x2A,
+       MAX17042_MiscCFG        = 0x2B,
+       MAX17042_TGAIN          = 0x2C,
+       MAx17042_TOFF           = 0x2D,
+       MAX17042_CGAIN          = 0x2E,
+       MAX17042_COFF           = 0x2F,
+
+       MAX17042_Q_empty        = 0x33,
+       MAX17042_T_empty        = 0x34,
+
+       MAX17042_RCOMP0         = 0x38,
+       MAX17042_TempCo         = 0x39,
+       MAX17042_Rx             = 0x3A,
+       MAX17042_T_empty0       = 0x3B,
+       MAX17042_TaskPeriod     = 0x3C,
+       MAX17042_FSTAT          = 0x3D,
+
+       MAX17042_SHDNTIMER      = 0x3F,
+
+       MAX17042_VFRemCap       = 0x4A,
+
+       MAX17042_QH             = 0x4D,
+       MAX17042_QL             = 0x4E,
+};
+
+struct max17042_chip {
+       struct i2c_client *client;
+       struct power_supply battery;
+       struct max17042_platform_data *pdata;
+};
+
+static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value)
+{
+       int ret = i2c_smbus_write_word_data(client, reg, value);
+
+       if (ret < 0)
+               dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+       return ret;
+}
+
+static int max17042_read_reg(struct i2c_client *client, u8 reg)
+{
+       int ret = i2c_smbus_read_word_data(client, reg);
+
+       if (ret < 0)
+               dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+       return ret;
+}
+
+static enum power_supply_property max17042_battery_props[] = {
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_VOLTAGE_AVG,
+       POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static int max17042_get_property(struct power_supply *psy,
+                           enum power_supply_property psp,
+                           union power_supply_propval *val)
+{
+       struct max17042_chip *chip = container_of(psy,
+                               struct max17042_chip, battery);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_AvgVCELL) * 83;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_SOC) / 256;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int __devinit max17042_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct max17042_chip *chip;
+       int ret;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+               return -EIO;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->client = client;
+       chip->pdata = client->dev.platform_data;
+
+       i2c_set_clientdata(client, chip);
+
+       chip->battery.name              = "max17042_battery";
+       chip->battery.type              = POWER_SUPPLY_TYPE_BATTERY;
+       chip->battery.get_property      = max17042_get_property;
+       chip->battery.properties        = max17042_battery_props;
+       chip->battery.num_properties    = ARRAY_SIZE(max17042_battery_props);
+
+       ret = power_supply_register(&client->dev, &chip->battery);
+       if (ret) {
+               dev_err(&client->dev, "failed: power supply register\n");
+               i2c_set_clientdata(client, NULL);
+               kfree(chip);
+               return ret;
+       }
+
+       if (!chip->pdata->enable_current_sense) {
+               max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
+               max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
+               max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
+       }
+
+       return 0;
+}
+
+static int __devexit max17042_remove(struct i2c_client *client)
+{
+       struct max17042_chip *chip = i2c_get_clientdata(client);
+
+       power_supply_unregister(&chip->battery);
+       i2c_set_clientdata(client, NULL);
+       kfree(chip);
+       return 0;
+}
+
+static const struct i2c_device_id max17042_id[] = {
+       { "max17042", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max17042_id);
+
+static struct i2c_driver max17042_i2c_driver = {
+       .driver = {
+               .name   = "max17042",
+       },
+       .probe          = max17042_probe,
+       .remove         = __devexit_p(max17042_remove),
+       .id_table       = max17042_id,
+};
+
+static int __init max17042_init(void)
+{
+       return i2c_add_driver(&max17042_i2c_driver);
+}
+module_init(max17042_init);
+
+static void __exit max17042_exit(void)
+{
+       i2c_del_driver(&max17042_i2c_driver);
+}
+module_exit(max17042_exit);
+
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("MAX17042 Fuel Gauge");
+MODULE_LICENSE("GPL");
index 5bc1dcf7785ec20874c191206ecc982768b93cbc..0b0ff3a936a61722be4fbb9a48d0a9de44626f1f 100644 (file)
@@ -201,6 +201,72 @@ static int olpc_bat_get_tech(union power_supply_propval *val)
        return ret;
 }
 
+static int olpc_bat_get_charge_full_design(union power_supply_propval *val)
+{
+       uint8_t ec_byte;
+       union power_supply_propval tech;
+       int ret, mfr;
+
+       ret = olpc_bat_get_tech(&tech);
+       if (ret)
+               return ret;
+
+       ec_byte = BAT_ADDR_MFR_TYPE;
+       ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
+       if (ret)
+               return ret;
+
+       mfr = ec_byte >> 4;
+
+       switch (tech.intval) {
+       case POWER_SUPPLY_TECHNOLOGY_NiMH:
+               switch (mfr) {
+               case 1: /* Gold Peak */
+                       val->intval = 3000000*.8;
+                       break;
+               default:
+                       return -EIO;
+               }
+               break;
+
+       case POWER_SUPPLY_TECHNOLOGY_LiFe:
+               switch (mfr) {
+               case 1: /* Gold Peak */
+                       val->intval = 2800000;
+                       break;
+               case 2: /* BYD */
+                       val->intval = 3100000;
+                       break;
+               default:
+                       return -EIO;
+               }
+               break;
+
+       default:
+               return -EIO;
+       }
+
+       return ret;
+}
+
+static int olpc_bat_get_charge_now(union power_supply_propval *val)
+{
+       uint8_t soc;
+       union power_supply_propval full;
+       int ret;
+
+       ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &soc, 1);
+       if (ret)
+               return ret;
+
+       ret = olpc_bat_get_charge_full_design(&full);
+       if (ret)
+               return ret;
+
+       val->intval = soc * (full.intval / 100);
+       return 0;
+}
+
 /*********************************************************************
  *             Battery properties
  *********************************************************************/
@@ -267,6 +333,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
                        return ret;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
                ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2);
                if (ret)
                        return ret;
@@ -274,6 +341,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
                val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32;
                break;
        case POWER_SUPPLY_PROP_CURRENT_AVG:
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
                ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
                if (ret)
                        return ret;
@@ -294,6 +362,16 @@ static int olpc_bat_get_property(struct power_supply *psy,
                else
                        val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
                break;
+       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+               ret = olpc_bat_get_charge_full_design(val);
+               if (ret)
+                       return ret;
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+               ret = olpc_bat_get_charge_now(val);
+               if (ret)
+                       return ret;
+               break;
        case POWER_SUPPLY_PROP_TEMP:
                ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
                if (ret)
@@ -331,16 +409,20 @@ static int olpc_bat_get_property(struct power_supply *psy,
        return ret;
 }
 
-static enum power_supply_property olpc_bat_props[] = {
+static enum power_supply_property olpc_xo1_bat_props[] = {
        POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_CHARGE_TYPE,
        POWER_SUPPLY_PROP_PRESENT,
        POWER_SUPPLY_PROP_HEALTH,
        POWER_SUPPLY_PROP_TECHNOLOGY,
        POWER_SUPPLY_PROP_VOLTAGE_AVG,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
        POWER_SUPPLY_PROP_CURRENT_AVG,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
        POWER_SUPPLY_PROP_CAPACITY,
        POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+       POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+       POWER_SUPPLY_PROP_CHARGE_NOW,
        POWER_SUPPLY_PROP_TEMP,
        POWER_SUPPLY_PROP_TEMP_AMBIENT,
        POWER_SUPPLY_PROP_MANUFACTURER,
@@ -348,6 +430,27 @@ static enum power_supply_property olpc_bat_props[] = {
        POWER_SUPPLY_PROP_CHARGE_COUNTER,
 };
 
+/* XO-1.5 does not have ambient temperature property */
+static enum power_supply_property olpc_xo15_bat_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_CHARGE_TYPE,
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_VOLTAGE_AVG,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CURRENT_AVG,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+       POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+       POWER_SUPPLY_PROP_CHARGE_NOW,
+       POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_MANUFACTURER,
+       POWER_SUPPLY_PROP_SERIAL_NUMBER,
+       POWER_SUPPLY_PROP_CHARGE_COUNTER,
+};
+
 /* EEPROM reading goes completely around the power_supply API, sadly */
 
 #define EEPROM_START   0x20
@@ -419,8 +522,6 @@ static struct device_attribute olpc_bat_error = {
 static struct platform_device *bat_pdev;
 
 static struct power_supply olpc_bat = {
-       .properties = olpc_bat_props,
-       .num_properties = ARRAY_SIZE(olpc_bat_props),
        .get_property = olpc_bat_get_property,
        .use_for_apm = 1,
 };
@@ -466,6 +567,13 @@ static int __init olpc_bat_init(void)
                goto ac_failed;
 
        olpc_bat.name = bat_pdev->name;
+       if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
+               olpc_bat.properties = olpc_xo15_bat_props;
+               olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
+       } else { /* XO-1 */
+               olpc_bat.properties = olpc_xo1_bat_props;
+               olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
+       }
 
        ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
        if (ret)
index 91606bb55318110307e3997bcb61722cd247ee73..970f7335d3a7f67bade76d6fad08eb954427a949 100644 (file)
@@ -190,10 +190,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
        goto success;
 
 create_triggers_failed:
-       device_unregister(psy->dev);
+       device_del(dev);
 kobject_set_name_failed:
 device_add_failed:
-       kfree(dev);
+       put_device(dev);
 success:
        return rc;
 }
@@ -201,7 +201,7 @@ EXPORT_SYMBOL_GPL(power_supply_register);
 
 void power_supply_unregister(struct power_supply *psy)
 {
-       flush_scheduled_work();
+       cancel_work_sync(&psy->changed_work);
        power_supply_remove_triggers(psy);
        device_unregister(psy->dev);
 }
index 4a8ae3935b3bfe56fef914ccd3328eabd8425840..4255f2358b138beb96305e832d778bef9ab15285 100644 (file)
@@ -112,6 +112,13 @@ static int calc_full_volt(int volt_val, int cur_val, int impedance)
        return volt_val + cur_val * impedance / 1000;
 }
 
+static int charge_finished(struct s3c_adc_bat *bat)
+{
+       return bat->pdata->gpio_inverted ?
+               !gpio_get_value(bat->pdata->gpio_charge_finished) :
+               gpio_get_value(bat->pdata->gpio_charge_finished);
+}
+
 static int s3c_adc_bat_get_property(struct power_supply *psy,
                                    enum power_supply_property psp,
                                    union power_supply_propval *val)
@@ -140,7 +147,7 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
 
        if (bat->cable_plugged &&
                ((bat->pdata->gpio_charge_finished < 0) ||
-               !gpio_get_value(bat->pdata->gpio_charge_finished))) {
+               !charge_finished(bat))) {
                lut = bat->pdata->lut_acin;
                lut_size = bat->pdata->lut_acin_cnt;
        }
@@ -236,8 +243,7 @@ static void s3c_adc_bat_work(struct work_struct *work)
                }
        } else {
                if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) {
-                       is_charged = gpio_get_value(
-                               main_bat.pdata->gpio_charge_finished);
+                       is_charged = charge_finished(&main_bat);
                        if (is_charged) {
                                if (bat->pdata->disable_charger)
                                        bat->pdata->disable_charger();
index ee04936b2db56da2b49258bb067e8a813126d7f9..53f0d3524fcd58f483a0ebcda42ccc0a353726e8 100644 (file)
@@ -332,7 +332,7 @@ static struct {
 static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state)
 {
        /* flush all pending status updates */
-       flush_scheduled_work();
+       flush_work_sync(&bat_work);
        return 0;
 }
 
@@ -422,7 +422,7 @@ err_psy_reg_jacket:
 err_psy_reg_main:
 
        /* see comment in tosa_bat_remove */
-       flush_scheduled_work();
+       cancel_work_sync(&bat_work);
 
        i--;
 err_gpio:
@@ -445,12 +445,11 @@ static int __devexit tosa_bat_remove(struct platform_device *dev)
        power_supply_unregister(&tosa_bat_main.psy);
 
        /*
-        * now flush all pending work.
-        * we won't get any more schedules, since all
-        * sources (isr and external_power_changed)
-        * are unregistered now.
+        * Now cancel the bat_work.  We won't get any more schedules,
+        * since all sources (isr and external_power_changed) are
+        * unregistered now.
         */
-       flush_scheduled_work();
+       cancel_work_sync(&bat_work);
 
        for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
                gpio_free(gpios[i].gpio);
index 5071d85ec12df66438a7b9a41b337f59e333ff50..156559e56fa5e808e48ce095efde1b3178767e91 100644 (file)
@@ -147,7 +147,7 @@ static irqreturn_t wm97xx_chrg_irq(int irq, void *data)
 #ifdef CONFIG_PM
 static int wm97xx_bat_suspend(struct device *dev)
 {
-       flush_scheduled_work();
+       flush_work_sync(&bat_work);
        return 0;
 }
 
@@ -273,7 +273,7 @@ static int __devexit wm97xx_bat_remove(struct platform_device *dev)
                free_irq(gpio_to_irq(pdata->charge_gpio), dev);
                gpio_free(pdata->charge_gpio);
        }
-       flush_scheduled_work();
+       cancel_work_sync(&bat_work);
        power_supply_unregister(&bat_ps);
        kfree(prop);
        return 0;
index 85064a9f649ed34acbfad8db3980afd42bb208ec..e5ed52d719376e41c35de6c1368c8723af532f89 100644 (file)
@@ -254,7 +254,7 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
        struct z2_charger *charger = i2c_get_clientdata(client);
        struct z2_battery_info *info = charger->info;
 
-       flush_scheduled_work();
+       cancel_work_sync(&charger->bat_work);
        power_supply_unregister(&charger->batt_ps);
 
        kfree(charger->batt_ps.properties);
@@ -271,7 +271,9 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
 #ifdef CONFIG_PM
 static int z2_batt_suspend(struct i2c_client *client, pm_message_t state)
 {
-       flush_scheduled_work();
+       struct z2_charger *charger = i2c_get_clientdata(client);
+
+       flush_work_sync(&charger->bat_work);
        return 0;
 }
 
index 7568df6122ab64a9303f1788e151908ad5bdd094..0ec49ca527a84de2f16b3eb8ab14bfe70df05e11 100644 (file)
@@ -424,6 +424,9 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
                                }
                        }
 
+                       if (pdata->buck_voltage_lock)
+                               return -EINVAL;
+
                        /* no predefine regulator found */
                        max8998->buck1_idx = (buck1_last_val % 2) + 2;
                        dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n",
@@ -451,18 +454,26 @@ buck1_exit:
                        "BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n"
                        , i, max8998->buck2_vol[0], max8998->buck2_vol[1]);
                if (gpio_is_valid(pdata->buck2_set3)) {
-                       if (max8998->buck2_vol[0] == i) {
-                               max8998->buck1_idx = 0;
-                               buck2_gpio_set(pdata->buck2_set3, 0);
-                       } else {
-                               max8998->buck1_idx = 1;
-                               ret = max8998_get_voltage_register(rdev, &reg,
-                                                                  &shift,
-                                                                  &mask);
-                               ret = max8998_write_reg(i2c, reg, i);
-                               max8998->buck2_vol[1] = i;
-                               buck2_gpio_set(pdata->buck2_set3, 1);
+
+                       /* check if requested voltage */
+                       /* value is already defined */
+                       for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) {
+                               if (max8998->buck2_vol[j] == i) {
+                                       max8998->buck2_idx = j;
+                                       buck2_gpio_set(pdata->buck2_set3, j);
+                                       goto buck2_exit;
+                               }
                        }
+
+                       if (pdata->buck_voltage_lock)
+                               return -EINVAL;
+
+                       max8998_get_voltage_register(rdev,
+                                       &reg, &shift, &mask);
+                       ret = max8998_write_reg(i2c, reg, i);
+                       max8998->buck2_vol[max8998->buck2_idx] = i;
+                       buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx);
+buck2_exit:
                        dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name,
                                gpio_get_value(pdata->buck2_set3));
                } else {
@@ -707,6 +718,9 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, max8998);
        i2c = max8998->iodev->i2c;
 
+       max8998->buck1_idx = pdata->buck1_default_idx;
+       max8998->buck2_idx = pdata->buck2_default_idx;
+
        /* NOTE: */
        /* For unused GPIO NOT marked as -1 (thereof equal to 0)  WARN_ON */
        /* will be displayed */
@@ -739,23 +753,46 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
                i = 0;
                while (buck12_voltage_map_desc.min +
                       buck12_voltage_map_desc.step*i
-                      != (pdata->buck1_max_voltage1 / 1000))
+                      < (pdata->buck1_voltage1 / 1000))
                        i++;
-               printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx);
                max8998->buck1_vol[0] = i;
                ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i);
+               if (ret)
+                       return ret;
 
                /* Set predefined value for BUCK1 register 2 */
                i = 0;
                while (buck12_voltage_map_desc.min +
                       buck12_voltage_map_desc.step*i
-                      != (pdata->buck1_max_voltage2 / 1000))
+                      < (pdata->buck1_voltage2 / 1000))
                        i++;
 
                max8998->buck1_vol[1] = i;
-               printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx);
-               ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i)
-                       + ret;
+               ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i);
+               if (ret)
+                       return ret;
+
+               /* Set predefined value for BUCK1 register 3 */
+               i = 0;
+               while (buck12_voltage_map_desc.min +
+                      buck12_voltage_map_desc.step*i
+                      < (pdata->buck1_voltage3 / 1000))
+                       i++;
+
+               max8998->buck1_vol[2] = i;
+               ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE3, i);
+               if (ret)
+                       return ret;
+
+               /* Set predefined value for BUCK1 register 4 */
+               i = 0;
+               while (buck12_voltage_map_desc.min +
+                      buck12_voltage_map_desc.step*i
+                      < (pdata->buck1_voltage4 / 1000))
+                       i++;
+
+               max8998->buck1_vol[3] = i;
+               ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE4, i);
                if (ret)
                        return ret;
 
@@ -772,18 +809,28 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
                gpio_direction_output(pdata->buck2_set3,
                                      max8998->buck2_idx & 0x1);
 
-               /* BUCK2 - set preset default voltage value to buck2_vol[0] */
+               /* BUCK2 register 1 */
                i = 0;
                while (buck12_voltage_map_desc.min +
                       buck12_voltage_map_desc.step*i
-                      != (pdata->buck2_max_voltage / 1000))
+                      < (pdata->buck2_voltage1 / 1000))
                        i++;
-               printk(KERN_ERR "i:%d, buck2_idx:%d\n", i, max8998->buck2_idx);
                max8998->buck2_vol[0] = i;
                ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i);
                if (ret)
                        return ret;
 
+               /* BUCK2 register 2 */
+               i = 0;
+               while (buck12_voltage_map_desc.min +
+                      buck12_voltage_map_desc.step*i
+                      < (pdata->buck2_voltage2 / 1000))
+                       i++;
+               printk(KERN_ERR "i2:%d, buck2_idx:%d\n", i, max8998->buck2_idx);
+               max8998->buck2_vol[1] = i;
+               ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i);
+               if (ret)
+                       return ret;
        }
 
        for (i = 0; i < pdata->num_regulators; i++) {
@@ -835,6 +882,12 @@ static int __devexit max8998_pmic_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct platform_device_id max8998_pmic_id[] = {
+       { "max8998-pmic", TYPE_MAX8998 },
+       { "lp3974-pmic", TYPE_LP3974 },
+       { }
+};
+
 static struct platform_driver max8998_pmic_driver = {
        .driver = {
                .name = "max8998-pmic",
@@ -842,6 +895,7 @@ static struct platform_driver max8998_pmic_driver = {
        },
        .probe = max8998_pmic_probe,
        .remove = __devexit_p(max8998_pmic_remove),
+       .id_table = max8998_pmic_id,
 };
 
 static int __init max8998_pmic_init(void)
index f22dee35f330e73554188b246d96eb454b31f06c..3f7bc6b9fefa94186c020503e8614304606d336b 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/mfd/max8998.h>
 #include <linux/mfd/max8998-private.h>
+#include <linux/delay.h>
 
 #define MAX8998_RTC_SEC                        0x00
 #define MAX8998_RTC_MIN                        0x01
@@ -73,6 +74,7 @@ struct max8998_rtc_info {
        struct i2c_client       *rtc;
        struct rtc_device       *rtc_dev;
        int irq;
+       bool lp3974_bug_workaround;
 };
 
 static void max8998_data_to_tm(u8 *data, struct rtc_time *tm)
@@ -124,10 +126,16 @@ static int max8998_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        struct max8998_rtc_info *info = dev_get_drvdata(dev);
        u8 data[8];
+       int ret;
 
        max8998_tm_to_data(tm, data);
 
-       return max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
+       ret = max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
+
+       if (info->lp3974_bug_workaround)
+               msleep(2000);
+
+       return ret;
 }
 
 static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -163,12 +171,29 @@ static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 
 static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info)
 {
-       return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
+       int ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
+
+       if (info->lp3974_bug_workaround)
+               msleep(2000);
+
+       return ret;
 }
 
 static int max8998_rtc_start_alarm(struct max8998_rtc_info *info)
 {
-       return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0x77);
+       int ret;
+       u8 alarm0_conf = 0x77;
+
+       /* LP3974 with delay bug chips has rtc alarm bugs with "MONTH" field */
+       if (info->lp3974_bug_workaround)
+               alarm0_conf = 0x57;
+
+       ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, alarm0_conf);
+
+       if (info->lp3974_bug_workaround)
+               msleep(2000);
+
+       return ret;
 }
 
 static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -187,10 +212,13 @@ static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        if (ret < 0)
                return ret;
 
+       if (info->lp3974_bug_workaround)
+               msleep(2000);
+
        if (alrm->enabled)
-               return max8998_rtc_start_alarm(info);
+               ret = max8998_rtc_start_alarm(info);
 
-       return 0;
+       return ret;
 }
 
 static int max8998_rtc_alarm_irq_enable(struct device *dev,
@@ -224,6 +252,7 @@ static const struct rtc_class_ops max8998_rtc_ops = {
 static int __devinit max8998_rtc_probe(struct platform_device *pdev)
 {
        struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent);
+       struct max8998_platform_data *pdata = dev_get_platdata(max8998->dev);
        struct max8998_rtc_info *info;
        int ret;
 
@@ -249,10 +278,18 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev)
 
        ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0,
                        "rtc-alarm0", info);
+
        if (ret < 0)
                dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
                        info->irq, ret);
 
+       dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name);
+       if (pdata->rtc_delay) {
+               info->lp3974_bug_workaround = true;
+               dev_warn(&pdev->dev, "LP3974 with RTC REGERR option."
+                               " RTC updates will be extremely slow.\n");
+       }
+
        return 0;
 
 out_rtc:
@@ -273,6 +310,12 @@ static int __devexit max8998_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct platform_device_id max8998_rtc_id[] = {
+       { "max8998-rtc", TYPE_MAX8998 },
+       { "lp3974-rtc", TYPE_LP3974 },
+       { }
+};
+
 static struct platform_driver max8998_rtc_driver = {
        .driver         = {
                .name   = "max8998-rtc",
@@ -280,6 +323,7 @@ static struct platform_driver max8998_rtc_driver = {
        },
        .probe          = max8998_rtc_probe,
        .remove         = __devexit_p(max8998_rtc_remove),
+       .id_table       = max8998_rtc_id,
 };
 
 static int __init max8998_rtc_init(void)
index e8391b89eff4bbbcb41896b3232c05a4070d8917..b7eaff9ca19e3be5a31d175ca2ce3765eddf76f7 100644 (file)
@@ -1835,6 +1835,7 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev)
         * available again. Kick re-detection.
         */
        cdev->private->flags.resuming = 1;
+       cdev->private->path_new_mask = LPM_ANYPATH;
        css_schedule_eval(sch->schid);
        spin_unlock_irq(sch->lock);
        css_complete_work();
index d3c5905b22ec6202649800a37dddf13c154a3d71..9c5c8be72231c867b58afe7d26e8068e4e5f82de 100644 (file)
@@ -7515,16 +7515,10 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        volatile u32 int_reg;
-       int rc;
 
        ENTER;
        ioa_cfg->pdev->state_saved = true;
-       rc = pci_restore_state(ioa_cfg->pdev);
-
-       if (rc != PCIBIOS_SUCCESSFUL) {
-               ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
-               return IPR_RC_JOB_CONTINUE;
-       }
+       pci_restore_state(ioa_cfg->pdev);
 
        if (ipr_set_pcix_cmd_reg(ioa_cfg)) {
                ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
index 300d59f389da76175ac4720fc2d9a69b0a16b163..321cf3ae863084d5f655f1dbe410fbca4c9ce75c 100644 (file)
@@ -2228,12 +2228,7 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
                /* Once either bist or pci reset is done, restore PCI config
                 * space. If this fails, proceed with hard reset again
                 */
-               if (pci_restore_state(pinstance->pdev)) {
-                       pmcraid_info("config-space error resetting again\n");
-                       pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
-                       pmcraid_reset_alert(cmd);
-                       break;
-               }
+               pci_restore_state(pinstance->pdev);
 
                /* fail all pending commands */
                pmcraid_fail_outstanding_cmds(pinstance);
index 1906840c1113cb6505a87418f7d97d5c324d7ec7..13bfa9d480822243b6254ad6f8e4c8867e595d90 100644 (file)
@@ -156,10 +156,10 @@ config SPI_IMX_VER_0_4
        def_bool y if ARCH_MX31
 
 config SPI_IMX_VER_0_7
-       def_bool y if ARCH_MX25 || ARCH_MX35 || ARCH_MX51
+       def_bool y if ARCH_MX25 || ARCH_MX35 || ARCH_MX51 || ARCH_MX53
 
 config SPI_IMX_VER_2_3
-       def_bool y if ARCH_MX51
+       def_bool y if ARCH_MX51 || ARCH_MX53
 
 config SPI_IMX
        tristate "Freescale i.MX SPI controllers"
@@ -310,8 +310,8 @@ config SPI_S3C24XX_GPIO
 
 config SPI_S3C64XX
        tristate "Samsung S3C64XX series type SPI"
-       depends on ARCH_S3C64XX && EXPERIMENTAL
-       select S3C64XX_DMA
+       depends on (ARCH_S3C64XX || ARCH_S5P64X0)
+       select S3C64XX_DMA if ARCH_S3C64XX
        help
          SPI driver for Samsung S3C64XX and newer SoCs.
 
index a2a5921c730a89007d19e7d5d3b1645e893f69ca..71a1219a995d12fa0f33fc45f8602a5681f4d6a8 100644 (file)
@@ -1795,7 +1795,7 @@ static int pl022_setup(struct spi_device *spi)
 {
        struct pl022_config_chip const *chip_info;
        struct chip_data *chip;
-       struct ssp_clock_params clk_freq;
+       struct ssp_clock_params clk_freq = {0, };
        int status = 0;
        struct pl022 *pl022 = spi_master_get_devdata(spi->master);
        unsigned int bits = spi->bits_per_word;
index db35bd9c1b24bf89f15c308de5915ce7fd04d97e..2fa012c109bc9627bf5c00d457b4cf85eb24790d 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -68,8 +69,8 @@ static int __devinit dw_spi_mmio_probe(struct platform_device *pdev)
        }
 
        dwsmmio->clk = clk_get(&pdev->dev, NULL);
-       if (!dwsmmio->clk) {
-               ret = -ENODEV;
+       if (IS_ERR(dwsmmio->clk)) {
+               ret = PTR_ERR(dwsmmio->clk);
                goto err_irq;
        }
        clk_enable(dwsmmio->clk);
index 9469564e6888e3a2715f82c21a330ca98759ec45..1cf9d5faabf4ac1f9347a62628ba48e31bede889 100644 (file)
@@ -742,6 +742,12 @@ static struct platform_device_id spi_imx_devtype[] = {
        }, {
                .name = "imx51-ecspi",
                .driver_data = SPI_IMX_VER_2_3,
+       }, {
+               .name = "imx53-cspi",
+               .driver_data = SPI_IMX_VER_0_7,
+       }, {
+               .name = "imx53-ecspi",
+               .driver_data = SPI_IMX_VER_2_3,
        }, {
                /* sentinel */
        }
index bb7df02a5472fdf3f7caf73d6ae82a6ffca9464b..891e5909038c4e4dd20bd956b33dca8e317630ac 100644 (file)
@@ -513,7 +513,7 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
        }
 
        tspi->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR_OR_NULL(tspi->clk)) {
+       if (IS_ERR(tspi->clk)) {
                dev_err(&pdev->dev, "can not get clock\n");
                ret = PTR_ERR(tspi->clk);
                goto err2;
index 5a0985d4ce1590b4e32efb5ded52861aabda451d..29884c00c4d53a4da03150e79987e6ed66fc6331 100644 (file)
@@ -420,6 +420,16 @@ int ssb_bus_scan(struct ssb_bus *bus,
                        bus->pcicore.dev = dev;
 #endif /* CONFIG_SSB_DRIVER_PCICORE */
                        break;
+               case SSB_DEV_ETHERNET:
+                       if (bus->bustype == SSB_BUSTYPE_PCI) {
+                               if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
+                                   (bus->host_pci->device & 0xFF00) == 0x4300) {
+                                       /* This is a dangling ethernet core on a
+                                        * wireless device. Ignore it. */
+                                       continue;
+                               }
+                       }
+                       break;
                default:
                        break;
                }
index f4b163f7338a41d9fdba29912bdacead56626f0f..0bc113c44d393423665b80f888c78660d67e8e6b 100644 (file)
@@ -1071,7 +1071,7 @@ static int __maybe_unused smtcfb_resume(struct pci_dev *pdev)
        /* when resuming, restore pci data and fb cursor */
        if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) {
                retv = pci_set_power_state(pdev, PCI_D0);
-               retv = pci_restore_state(pdev);
+               pci_restore_state(pdev);
                if (pci_enable_device(pdev))
                        return -1;
                pci_set_master(pdev);
index 38244f59cdd91e76acc63f7fb4d7b66a5a730fbf..ade0568c07a4e9ff3ab2fc56e9dc527ca58bdf72 100644 (file)
@@ -97,22 +97,26 @@ void vhost_poll_stop(struct vhost_poll *poll)
        remove_wait_queue(poll->wqh, &poll->wait);
 }
 
+static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work,
+                               unsigned seq)
+{
+       int left;
+       spin_lock_irq(&dev->work_lock);
+       left = seq - work->done_seq;
+       spin_unlock_irq(&dev->work_lock);
+       return left <= 0;
+}
+
 static void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work)
 {
        unsigned seq;
-       int left;
        int flushing;
 
        spin_lock_irq(&dev->work_lock);
        seq = work->queue_seq;
        work->flushing++;
        spin_unlock_irq(&dev->work_lock);
-       wait_event(work->done, ({
-                  spin_lock_irq(&dev->work_lock);
-                  left = seq - work->done_seq <= 0;
-                  spin_unlock_irq(&dev->work_lock);
-                  left;
-       }));
+       wait_event(work->done, vhost_work_seq_done(dev, work, seq));
        spin_lock_irq(&dev->work_lock);
        flushing = --work->flushing;
        spin_unlock_irq(&dev->work_lock);
index a3bcec75c54aa2302728edddfd93de15f4ac513c..1c8c6cc6de3097ceab15a5a16307e0b569ee6a29 100644 (file)
@@ -289,7 +289,7 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
        call->server = server;
 
        INIT_WORK(&call->work, SRXAFSCB_CallBack);
-       schedule_work(&call->work);
+       queue_work(afs_wq, &call->work);
        return 0;
 }
 
@@ -336,7 +336,7 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
        call->server = server;
 
        INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
-       schedule_work(&call->work);
+       queue_work(afs_wq, &call->work);
        return 0;
 }
 
@@ -367,7 +367,7 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call,
        call->server = server;
 
        INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
-       schedule_work(&call->work);
+       queue_work(afs_wq, &call->work);
        return 0;
 }
 
@@ -400,7 +400,7 @@ static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
        call->state = AFS_CALL_REPLYING;
 
        INIT_WORK(&call->work, SRXAFSCB_Probe);
-       schedule_work(&call->work);
+       queue_work(afs_wq, &call->work);
        return 0;
 }
 
@@ -496,7 +496,7 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb,
        call->state = AFS_CALL_REPLYING;
 
        INIT_WORK(&call->work, SRXAFSCB_ProbeUuid);
-       schedule_work(&call->work);
+       queue_work(afs_wq, &call->work);
        return 0;
 }
 
@@ -580,6 +580,6 @@ static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call,
        call->state = AFS_CALL_REPLYING;
 
        INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself);
-       schedule_work(&call->work);
+       queue_work(afs_wq, &call->work);
        return 0;
 }
index ab6db5abaf535047fae82bcabe239eae9ccbacfd..58c633b80246ca896852797ffba5587249561df1 100644 (file)
@@ -577,6 +577,7 @@ extern int afs_drop_inode(struct inode *);
 /*
  * main.c
  */
+extern struct workqueue_struct *afs_wq;
 extern struct afs_uuid afs_uuid;
 
 /*
index cfd1cbe25b220e990977d7bdec5222e8109ab689..42dd2e499ed8902c08bddbba1ff1723363f833dd 100644 (file)
@@ -30,6 +30,7 @@ module_param(rootcell, charp, 0);
 MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
 
 struct afs_uuid afs_uuid;
+struct workqueue_struct *afs_wq;
 
 /*
  * get a client UUID
@@ -87,10 +88,16 @@ static int __init afs_init(void)
        if (ret < 0)
                return ret;
 
+       /* create workqueue */
+       ret = -ENOMEM;
+       afs_wq = alloc_workqueue("afs", 0, 0);
+       if (!afs_wq)
+               return ret;
+
        /* register the /proc stuff */
        ret = afs_proc_init();
        if (ret < 0)
-               return ret;
+               goto error_proc;
 
 #ifdef CONFIG_AFS_FSCACHE
        /* we want to be able to cache */
@@ -140,6 +147,8 @@ error_cell_init:
 error_cache:
 #endif
        afs_proc_cleanup();
+error_proc:
+       destroy_workqueue(afs_wq);
        rcu_barrier();
        printk(KERN_ERR "kAFS: failed to register: %d\n", ret);
        return ret;
@@ -163,7 +172,7 @@ static void __exit afs_exit(void)
        afs_purge_servers();
        afs_callback_update_kill();
        afs_vlocation_purge();
-       flush_scheduled_work();
+       destroy_workqueue(afs_wq);
        afs_cell_purge();
 #ifdef CONFIG_AFS_FSCACHE
        fscache_unregister_netfs(&afs_cache_netfs);
index 6153417caf57e2b9219bbfdd40970c262b65fdcf..e83c0336e7b58a9cbcb4bea29f819d31ffc755a3 100644 (file)
@@ -268,8 +268,8 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd)
                path_put(&nd->path);
                nd->path.mnt = newmnt;
                nd->path.dentry = dget(newmnt->mnt_root);
-               schedule_delayed_work(&afs_mntpt_expiry_timer,
-                                     afs_mntpt_expiry_timeout * HZ);
+               queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
+                                  afs_mntpt_expiry_timeout * HZ);
                break;
        case -EBUSY:
                /* someone else made a mount here whilst we were busy */
@@ -295,8 +295,8 @@ static void afs_mntpt_expiry_timed_out(struct work_struct *work)
 
        if (!list_empty(&afs_vfsmounts)) {
                mark_mounts_for_expiry(&afs_vfsmounts);
-               schedule_delayed_work(&afs_mntpt_expiry_timer,
-                                     afs_mntpt_expiry_timeout * HZ);
+               queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
+                                  afs_mntpt_expiry_timeout * HZ);
        }
 
        _leave("");
@@ -310,6 +310,5 @@ void afs_mntpt_kill_timer(void)
        _enter("");
 
        ASSERT(list_empty(&afs_vfsmounts));
-       cancel_delayed_work(&afs_mntpt_expiry_timer);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&afs_mntpt_expiry_timer);
 }
index 654d8fdbf01f31ebd2f7ad05d7145ca024bee144..e45a323aebb4468711de395fd06e5f0f9d2833d0 100644 (file)
@@ -410,7 +410,7 @@ static void afs_rx_interceptor(struct sock *sk, unsigned long user_call_ID,
        if (!call) {
                /* its an incoming call for our callback service */
                skb_queue_tail(&afs_incoming_calls, skb);
-               schedule_work(&afs_collect_incoming_call_work);
+               queue_work(afs_wq, &afs_collect_incoming_call_work);
        } else {
                /* route the messages directly to the appropriate call */
                skb_queue_tail(&call->rx_queue, skb);
index 9fdc7fe3a7bc127da02963e76c3628221c334ed0..d59b7516e943ba2617f84e26088a2da42857d4e9 100644 (file)
@@ -238,8 +238,8 @@ void afs_put_server(struct afs_server *server)
        if (atomic_read(&server->usage) == 0) {
                list_move_tail(&server->grave, &afs_server_graveyard);
                server->time_of_death = get_seconds();
-               schedule_delayed_work(&afs_server_reaper,
-                                     afs_server_timeout * HZ);
+               queue_delayed_work(afs_wq, &afs_server_reaper,
+                                  afs_server_timeout * HZ);
        }
        spin_unlock(&afs_server_graveyard_lock);
        _leave(" [dead]");
@@ -285,10 +285,11 @@ static void afs_reap_server(struct work_struct *work)
                expiry = server->time_of_death + afs_server_timeout;
                if (expiry > now) {
                        delay = (expiry - now) * HZ;
-                       if (!schedule_delayed_work(&afs_server_reaper, delay)) {
+                       if (!queue_delayed_work(afs_wq, &afs_server_reaper,
+                                               delay)) {
                                cancel_delayed_work(&afs_server_reaper);
-                               schedule_delayed_work(&afs_server_reaper,
-                                                     delay);
+                               queue_delayed_work(afs_wq, &afs_server_reaper,
+                                                  delay);
                        }
                        break;
                }
@@ -323,5 +324,5 @@ void __exit afs_purge_servers(void)
 {
        afs_server_timeout = 0;
        cancel_delayed_work(&afs_server_reaper);
-       schedule_delayed_work(&afs_server_reaper, 0);
+       queue_delayed_work(afs_wq, &afs_server_reaper, 0);
 }
index 9ac260d1361de8e3b50f1bd6f9abad13b8b97594..431984d2e372cfcb18984e46366011b12f72e9ee 100644 (file)
@@ -507,8 +507,8 @@ void afs_put_vlocation(struct afs_vlocation *vl)
                _debug("buried");
                list_move_tail(&vl->grave, &afs_vlocation_graveyard);
                vl->time_of_death = get_seconds();
-               schedule_delayed_work(&afs_vlocation_reap,
-                                     afs_vlocation_timeout * HZ);
+               queue_delayed_work(afs_wq, &afs_vlocation_reap,
+                                  afs_vlocation_timeout * HZ);
 
                /* suspend updates on this record */
                if (!list_empty(&vl->update)) {
@@ -561,11 +561,11 @@ static void afs_vlocation_reaper(struct work_struct *work)
                if (expiry > now) {
                        delay = (expiry - now) * HZ;
                        _debug("delay %lu", delay);
-                       if (!schedule_delayed_work(&afs_vlocation_reap,
-                                                  delay)) {
+                       if (!queue_delayed_work(afs_wq, &afs_vlocation_reap,
+                                               delay)) {
                                cancel_delayed_work(&afs_vlocation_reap);
-                               schedule_delayed_work(&afs_vlocation_reap,
-                                                     delay);
+                               queue_delayed_work(afs_wq, &afs_vlocation_reap,
+                                                  delay);
                        }
                        break;
                }
@@ -620,7 +620,7 @@ void afs_vlocation_purge(void)
        destroy_workqueue(afs_vlocation_update_worker);
 
        cancel_delayed_work(&afs_vlocation_reap);
-       schedule_delayed_work(&afs_vlocation_reap, 0);
+       queue_delayed_work(afs_wq, &afs_vlocation_reap, 0);
 }
 
 /*
index fe3f59c14a02bb523aaaffc4f668b785fed06f01..333a7bb4cb9c0865543bc210c6df2613662950c9 100644 (file)
@@ -432,6 +432,9 @@ static void init_once(void *foo)
        mutex_init(&bdev->bd_mutex);
        INIT_LIST_HEAD(&bdev->bd_inodes);
        INIT_LIST_HEAD(&bdev->bd_list);
+#ifdef CONFIG_SYSFS
+       INIT_LIST_HEAD(&bdev->bd_holder_disks);
+#endif
        inode_init_once(&ei->vfs_inode);
        /* Initialize mutex for freeze. */
        mutex_init(&bdev->bd_fsfreeze_mutex);
@@ -779,6 +782,23 @@ static struct block_device *bd_start_claiming(struct block_device *bdev,
 }
 
 #ifdef CONFIG_SYSFS
+struct bd_holder_disk {
+       struct list_head        list;
+       struct gendisk          *disk;
+       int                     refcnt;
+};
+
+static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
+                                                 struct gendisk *disk)
+{
+       struct bd_holder_disk *holder;
+
+       list_for_each_entry(holder, &bdev->bd_holder_disks, list)
+               if (holder->disk == disk)
+                       return holder;
+       return NULL;
+}
+
 static int add_symlink(struct kobject *from, struct kobject *to)
 {
        return sysfs_create_link(from, to, kobject_name(to));
@@ -794,6 +814,8 @@ static void del_symlink(struct kobject *from, struct kobject *to)
  * @bdev: the claimed slave bdev
  * @disk: the holding disk
  *
+ * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
+ *
  * This functions creates the following sysfs symlinks.
  *
  * - from "slaves" directory of the holder @disk to the claimed @bdev
@@ -817,47 +839,83 @@ static void del_symlink(struct kobject *from, struct kobject *to)
  */
 int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
 {
+       struct bd_holder_disk *holder;
        int ret = 0;
 
        mutex_lock(&bdev->bd_mutex);
 
-       WARN_ON_ONCE(!bdev->bd_holder || bdev->bd_holder_disk);
+       WARN_ON_ONCE(!bdev->bd_holder);
 
        /* FIXME: remove the following once add_disk() handles errors */
        if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir))
                goto out_unlock;
 
-       ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
-       if (ret)
+       holder = bd_find_holder_disk(bdev, disk);
+       if (holder) {
+               holder->refcnt++;
                goto out_unlock;
+       }
 
-       ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
-       if (ret) {
-               del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
+       holder = kzalloc(sizeof(*holder), GFP_KERNEL);
+       if (!holder) {
+               ret = -ENOMEM;
                goto out_unlock;
        }
 
-       bdev->bd_holder_disk = disk;
+       INIT_LIST_HEAD(&holder->list);
+       holder->disk = disk;
+       holder->refcnt = 1;
+
+       ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
+       if (ret)
+               goto out_free;
+
+       ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
+       if (ret)
+               goto out_del;
+
+       list_add(&holder->list, &bdev->bd_holder_disks);
+       goto out_unlock;
+
+out_del:
+       del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
+out_free:
+       kfree(holder);
 out_unlock:
        mutex_unlock(&bdev->bd_mutex);
        return ret;
 }
 EXPORT_SYMBOL_GPL(bd_link_disk_holder);
 
-static void bd_unlink_disk_holder(struct block_device *bdev)
+/**
+ * bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder()
+ * @bdev: the calimed slave bdev
+ * @disk: the holding disk
+ *
+ * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
+ *
+ * CONTEXT:
+ * Might sleep.
+ */
+void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
 {
-       struct gendisk *disk = bdev->bd_holder_disk;
+       struct bd_holder_disk *holder;
 
-       bdev->bd_holder_disk = NULL;
-       if (!disk)
-               return;
+       mutex_lock(&bdev->bd_mutex);
 
-       del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
-       del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
+       holder = bd_find_holder_disk(bdev, disk);
+
+       if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) {
+               del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
+               del_symlink(bdev->bd_part->holder_dir,
+                           &disk_to_dev(disk)->kobj);
+               list_del_init(&holder->list);
+               kfree(holder);
+       }
+
+       mutex_unlock(&bdev->bd_mutex);
 }
-#else
-static inline void bd_unlink_disk_holder(struct block_device *bdev)
-{ }
+EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
 #endif
 
 /**
@@ -1380,7 +1438,6 @@ int blkdev_put(struct block_device *bdev, fmode_t mode)
                 * unblock evpoll if it was a write holder.
                 */
                if (bdev_free) {
-                       bd_unlink_disk_holder(bdev);
                        if (bdev->bd_write_holder) {
                                disk_unblock_events(bdev->bd_disk);
                                bdev->bd_write_holder = false;
index 0c6d5c549d840008b4dfff4e45e1aa6cbdcb88f8..274a2225038073ae92664113e31f0b2fc18040ab 100644 (file)
@@ -1357,8 +1357,8 @@ EXPORT_SYMBOL(d_alloc_name);
 
 void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
 {
-       BUG_ON(dentry->d_op);
-       BUG_ON(dentry->d_flags & (DCACHE_OP_HASH        |
+       WARN_ON_ONCE(dentry->d_op);
+       WARN_ON_ONCE(dentry->d_flags & (DCACHE_OP_HASH  |
                                DCACHE_OP_COMPARE       |
                                DCACHE_OP_REVALIDATE    |
                                DCACHE_OP_DELETE ));
index b9f34eaede09a95a24723e0a0f79151065c03fb9..48a18f184d5041b9f4909137898fe0fd51bc45d8 100644 (file)
@@ -101,7 +101,7 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
                object->n_ops++;
                object->n_exclusive++;  /* reads and writes must wait */
 
-               if (object->n_ops > 0) {
+               if (object->n_ops > 1) {
                        atomic_inc(&op->usage);
                        list_add_tail(&op->pend_link, &object->pending_ops);
                        fscache_stat(&fscache_n_op_pend);
index 08415b2a6d36f321bf67b5a697c4db676cb15f78..0f3998291f78e4fa08b5d3c102f6d8dcc120247a 100644 (file)
@@ -444,15 +444,9 @@ static void lease_release_private_callback(struct file_lock *fl)
        fl->fl_file->f_owner.signum = 0;
 }
 
-static int lease_mylease_callback(struct file_lock *fl, struct file_lock *try)
-{
-       return fl->fl_file == try->fl_file;
-}
-
 static const struct lock_manager_operations lease_manager_ops = {
        .fl_break = lease_break_callback,
        .fl_release_private = lease_release_private_callback,
-       .fl_mylease = lease_mylease_callback,
        .fl_change = lease_modify,
 };
 
@@ -1405,7 +1399,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
        for (before = &inode->i_flock;
                        ((fl = *before) != NULL) && IS_LEASE(fl);
                        before = &fl->fl_next) {
-               if (lease->fl_lmops->fl_mylease(fl, lease))
+               if (fl->fl_file == filp)
                        my_before = before;
                else if (fl->fl_type == (F_INPROGRESS | F_UNLCK))
                        /*
index 86643302079e33e010d29ae18d2fb392723c57bb..8df7a78ace58e3885adfcd824c5411da84957b73 100644 (file)
@@ -779,7 +779,8 @@ static void path_put_conditional(struct path *path, struct nameidata *nd)
                mntput(path->mnt);
 }
 
-static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
+static inline void path_to_nameidata(const struct path *path,
+                                       struct nameidata *nd)
 {
        if (!(nd->flags & LOOKUP_RCU)) {
                dput(nd->path.dentry);
@@ -791,20 +792,20 @@ static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
 }
 
 static __always_inline int
-__do_follow_link(struct path *path, struct nameidata *nd, void **p)
+__do_follow_link(const struct path *link, struct nameidata *nd, void **p)
 {
        int error;
-       struct dentry *dentry = path->dentry;
+       struct dentry *dentry = link->dentry;
 
-       touch_atime(path->mnt, dentry);
+       touch_atime(link->mnt, dentry);
        nd_set_link(nd, NULL);
 
-       if (path->mnt != nd->path.mnt) {
-               path_to_nameidata(path, nd);
+       if (link->mnt != nd->path.mnt) {
+               path_to_nameidata(link, nd);
                nd->inode = nd->path.dentry->d_inode;
                dget(dentry);
        }
-       mntget(path->mnt);
+       mntget(link->mnt);
 
        nd->last_type = LAST_BIND;
        *p = dentry->d_inode->i_op->follow_link(dentry, nd);
@@ -2348,11 +2349,12 @@ reval:
        nd.flags = flags;
        filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
        while (unlikely(!filp)) { /* trailing symlink */
-               struct path holder;
+               struct path link = path;
+               struct inode *linki = link.dentry->d_inode;
                void *cookie;
                error = -ELOOP;
                /* S_ISDIR part is a temporary automount kludge */
-               if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(nd.inode->i_mode))
+               if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(linki->i_mode))
                        goto exit_dput;
                if (count++ == 32)
                        goto exit_dput;
@@ -2368,23 +2370,22 @@ reval:
                 * just set LAST_BIND.
                 */
                nd.flags |= LOOKUP_PARENT;
-               error = security_inode_follow_link(path.dentry, &nd);
+               error = security_inode_follow_link(link.dentry, &nd);
                if (error)
                        goto exit_dput;
-               error = __do_follow_link(&path, &nd, &cookie);
+               error = __do_follow_link(&link, &nd, &cookie);
                if (unlikely(error)) {
-                       if (!IS_ERR(cookie) && nd.inode->i_op->put_link)
-                               nd.inode->i_op->put_link(path.dentry, &nd, cookie);
+                       if (!IS_ERR(cookie) && linki->i_op->put_link)
+                               linki->i_op->put_link(link.dentry, &nd, cookie);
                        /* nd.path had been dropped */
-                       nd.path = path;
+                       nd.path = link;
                        goto out_path;
                }
-               holder = path;
                nd.flags &= ~LOOKUP_PARENT;
                filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
-               if (nd.inode->i_op->put_link)
-                       nd.inode->i_op->put_link(holder.dentry, &nd, cookie);
-               path_put(&holder);
+               if (linki->i_op->put_link)
+                       linki->i_op->put_link(link.dentry, &nd, cookie);
+               path_put(&link);
        }
 out:
        if (nd.root.mnt)
similarity index 98%
rename from include/linux/nfs4_acl.h
rename to fs/nfsd/acl.h
index c9c05a78e9bb32438f866b9d99564cf87ff02287..34e5c40af5ef60d44673f992bfd186acab2e1d26 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  include/linux/nfs4_acl.c
- *
  *  Common NFSv4 ACL handling definitions.
  *
  *  Copyright (c) 2002 The Regents of the University of Michigan.
index c0fcb7ab7f6db42b9793dd2b59f853f92728db35..8b31e5f8795de8fb520e5f1a0676b60c93530c01 100644 (file)
@@ -1,4 +1,3 @@
-#define MSNFS  /* HACK HACK */
 /*
  * NFS exporting and validation.
  *
@@ -1444,9 +1443,6 @@ static struct flags {
        { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
        { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
        { NFSEXP_V4ROOT, {"v4root", ""}},
-#ifdef MSNFS
-       { NFSEXP_MSNFS, {"msnfs", ""}},
-#endif
        { 0, {"", ""}}
 };
 
similarity index 92%
rename from include/linux/nfsd_idmap.h
rename to fs/nfsd/idmap.h
index d4a2ac18bd4cfba2a6713aa6a492660264b94782..2f3be1321534375b65cac5705806edda29c6088d 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  include/linux/nfsd_idmap.h
- *
  *  Mapping of UID to name and vice versa.
  *
  *  Copyright (c) 2002, 2003 The Regents of the University of
@@ -56,8 +54,8 @@ static inline void nfsd_idmap_shutdown(void)
 }
 #endif
 
-int nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *);
-int nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *);
+__be32 nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *);
+__be32 nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *);
 int nfsd_map_uid_to_name(struct svc_rqst *, __u32, char *);
 int nfsd_map_gid_to_name(struct svc_rqst *, __u32, char *);
 
index 5b7e3021e06b874e6d4e802dae08164b39906485..2247fc91d5e9728e0796d45bb63c8784fb2da96e 100644 (file)
@@ -151,10 +151,10 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
        __be32  nfserr;
        u32     max_blocksize = svc_max_payload(rqstp);
 
-       dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
+       dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
                                SVCFH_fmt(&argp->fh),
                                (unsigned long) argp->count,
-                               (unsigned long) argp->offset);
+                               (unsigned long long) argp->offset);
 
        /* Obtain buffer pointer for payload.
         * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
@@ -191,10 +191,10 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
        __be32  nfserr;
        unsigned long cnt = argp->len;
 
-       dprintk("nfsd: WRITE(3)    %s %d bytes at %ld%s\n",
+       dprintk("nfsd: WRITE(3)    %s %d bytes at %Lu%s\n",
                                SVCFH_fmt(&argp->fh),
                                argp->len,
-                               (unsigned long) argp->offset,
+                               (unsigned long long) argp->offset,
                                argp->stable? " stable" : "");
 
        fh_copy(&resp->fh, &argp->fh);
index e48052615159c24689989b5ebe0a803e0946755f..ad88f1c0a4c3f5d5f05173aafba65f143e6ec0f2 100644 (file)
@@ -36,7 +36,7 @@
 
 #include <linux/slab.h>
 #include <linux/nfs_fs.h>
-#include <linux/nfs4_acl.h>
+#include "acl.h"
 
 
 /* mode bit translations: */
index 21a63da305ffaf23e65b57a9a90ad5a5ea81a84c..3be975e189195daa59e76b5abb70d630d48361b7 100644 (file)
@@ -628,10 +628,8 @@ static int max_cb_time(void)
        return max(nfsd4_lease/10, (time_t)1) * HZ;
 }
 
-/* Reference counting, callback cleanup, etc., all look racy as heck.
- * And why is cl_cb_set an atomic? */
 
-int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
+static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
 {
        struct rpc_timeout      timeparms = {
                .to_initval     = max_cb_time(),
@@ -641,6 +639,7 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
                .net            = &init_net,
                .address        = (struct sockaddr *) &conn->cb_addr,
                .addrsize       = conn->cb_addrlen,
+               .saddress       = (struct sockaddr *) &conn->cb_saddr,
                .timeout        = &timeparms,
                .program        = &cb_program,
                .version        = 0,
@@ -657,6 +656,10 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
                args.protocol = XPRT_TRANSPORT_TCP;
                clp->cl_cb_ident = conn->cb_ident;
        } else {
+               if (!conn->cb_xprt)
+                       return -EINVAL;
+               clp->cl_cb_conn.cb_xprt = conn->cb_xprt;
+               clp->cl_cb_session = ses;
                args.bc_xprt = conn->cb_xprt;
                args.prognumber = clp->cl_cb_session->se_cb_prog;
                args.protocol = XPRT_TRANSPORT_BC_TCP;
@@ -679,14 +682,20 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason)
                (int)clp->cl_name.len, clp->cl_name.data, reason);
 }
 
+static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
+{
+       clp->cl_cb_state = NFSD4_CB_DOWN;
+       warn_no_callback_path(clp, reason);
+}
+
 static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
 {
        struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);
 
        if (task->tk_status)
-               warn_no_callback_path(clp, task->tk_status);
+               nfsd4_mark_cb_down(clp, task->tk_status);
        else
-               atomic_set(&clp->cl_cb_set, 1);
+               clp->cl_cb_state = NFSD4_CB_UP;
 }
 
 static const struct rpc_call_ops nfsd4_cb_probe_ops = {
@@ -709,6 +718,11 @@ int set_callback_cred(void)
 
 static struct workqueue_struct *callback_wq;
 
+static void run_nfsd4_cb(struct nfsd4_callback *cb)
+{
+       queue_work(callback_wq, &cb->cb_work);
+}
+
 static void do_probe_callback(struct nfs4_client *clp)
 {
        struct nfsd4_callback *cb = &clp->cl_cb_null;
@@ -723,7 +737,7 @@ static void do_probe_callback(struct nfs4_client *clp)
 
        cb->cb_ops = &nfsd4_cb_probe_ops;
 
-       queue_work(callback_wq, &cb->cb_work);
+       run_nfsd4_cb(cb);
 }
 
 /*
@@ -732,14 +746,21 @@ static void do_probe_callback(struct nfs4_client *clp)
  */
 void nfsd4_probe_callback(struct nfs4_client *clp)
 {
+       /* XXX: atomicity?  Also, should we be using cl_cb_flags? */
+       clp->cl_cb_state = NFSD4_CB_UNKNOWN;
        set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
        do_probe_callback(clp);
 }
 
-void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
+void nfsd4_probe_callback_sync(struct nfs4_client *clp)
 {
-       BUG_ON(atomic_read(&clp->cl_cb_set));
+       nfsd4_probe_callback(clp);
+       flush_workqueue(callback_wq);
+}
 
+void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
+{
+       clp->cl_cb_state = NFSD4_CB_UNKNOWN;
        spin_lock(&clp->cl_lock);
        memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn));
        spin_unlock(&clp->cl_lock);
@@ -750,24 +771,14 @@ void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
  * If the slot is available, then mark it busy.  Otherwise, set the
  * thread for sleeping on the callback RPC wait queue.
  */
-static int nfsd41_cb_setup_sequence(struct nfs4_client *clp,
-               struct rpc_task *task)
+static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task)
 {
-       u32 *ptr = (u32 *)clp->cl_cb_session->se_sessionid.data;
-       int status = 0;
-
-       dprintk("%s: %u:%u:%u:%u\n", __func__,
-               ptr[0], ptr[1], ptr[2], ptr[3]);
-
        if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
                rpc_sleep_on(&clp->cl_cb_waitq, task, NULL);
                dprintk("%s slot is busy\n", __func__);
-               status = -EAGAIN;
-               goto out;
+               return false;
        }
-out:
-       dprintk("%s status=%d\n", __func__, status);
-       return status;
+       return true;
 }
 
 /*
@@ -780,20 +791,19 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
        struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
        struct nfs4_client *clp = dp->dl_client;
        u32 minorversion = clp->cl_minorversion;
-       int status = 0;
 
        cb->cb_minorversion = minorversion;
        if (minorversion) {
-               status = nfsd41_cb_setup_sequence(clp, task);
-               if (status) {
-                       if (status != -EAGAIN) {
-                               /* terminate rpc task */
-                               task->tk_status = status;
-                               task->tk_action = NULL;
-                       }
+               if (!nfsd41_cb_get_slot(clp, task))
                        return;
-               }
        }
+       spin_lock(&clp->cl_lock);
+       if (list_empty(&cb->cb_per_client)) {
+               /* This is the first call, not a restart */
+               cb->cb_done = false;
+               list_add(&cb->cb_per_client, &clp->cl_callbacks);
+       }
+       spin_unlock(&clp->cl_lock);
        rpc_call_start(task);
 }
 
@@ -829,15 +839,18 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
 
        nfsd4_cb_done(task, calldata);
 
-       if (current_rpc_client == NULL) {
-               /* We're shutting down; give up. */
-               /* XXX: err, or is it ok just to fall through
-                * and rpc_restart_call? */
+       if (current_rpc_client != task->tk_client) {
+               /* We're shutting down or changing cl_cb_client; leave
+                * it to nfsd4_process_cb_update to restart the call if
+                * necessary. */
                return;
        }
 
+       if (cb->cb_done)
+               return;
        switch (task->tk_status) {
        case 0:
+               cb->cb_done = true;
                return;
        case -EBADHANDLE:
        case -NFS4ERR_BAD_STATEID:
@@ -846,32 +859,30 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
                break;
        default:
                /* Network partition? */
-               atomic_set(&clp->cl_cb_set, 0);
-               warn_no_callback_path(clp, task->tk_status);
-               if (current_rpc_client != task->tk_client) {
-                       /* queue a callback on the new connection: */
-                       atomic_inc(&dp->dl_count);
-                       nfsd4_cb_recall(dp);
-                       return;
-               }
+               nfsd4_mark_cb_down(clp, task->tk_status);
        }
        if (dp->dl_retries--) {
                rpc_delay(task, 2*HZ);
                task->tk_status = 0;
                rpc_restart_call_prepare(task);
                return;
-       } else {
-               atomic_set(&clp->cl_cb_set, 0);
-               warn_no_callback_path(clp, task->tk_status);
        }
+       nfsd4_mark_cb_down(clp, task->tk_status);
+       cb->cb_done = true;
 }
 
 static void nfsd4_cb_recall_release(void *calldata)
 {
        struct nfsd4_callback *cb = calldata;
+       struct nfs4_client *clp = cb->cb_clp;
        struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
 
-       nfs4_put_delegation(dp);
+       if (cb->cb_done) {
+               spin_lock(&clp->cl_lock);
+               list_del(&cb->cb_per_client);
+               spin_unlock(&clp->cl_lock);
+               nfs4_put_delegation(dp);
+       }
 }
 
 static const struct rpc_call_ops nfsd4_cb_recall_ops = {
@@ -906,16 +917,33 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp)
        flush_workqueue(callback_wq);
 }
 
-void nfsd4_release_cb(struct nfsd4_callback *cb)
+static void nfsd4_release_cb(struct nfsd4_callback *cb)
 {
        if (cb->cb_ops->rpc_release)
                cb->cb_ops->rpc_release(cb);
 }
 
-void nfsd4_process_cb_update(struct nfsd4_callback *cb)
+/* requires cl_lock: */
+static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp)
+{
+       struct nfsd4_session *s;
+       struct nfsd4_conn *c;
+
+       list_for_each_entry(s, &clp->cl_sessions, se_perclnt) {
+               list_for_each_entry(c, &s->se_conns, cn_persession) {
+                       if (c->cn_flags & NFS4_CDFC4_BACK)
+                               return c;
+               }
+       }
+       return NULL;
+}
+
+static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
 {
        struct nfs4_cb_conn conn;
        struct nfs4_client *clp = cb->cb_clp;
+       struct nfsd4_session *ses = NULL;
+       struct nfsd4_conn *c;
        int err;
 
        /*
@@ -926,6 +954,10 @@ void nfsd4_process_cb_update(struct nfsd4_callback *cb)
                rpc_shutdown_client(clp->cl_cb_client);
                clp->cl_cb_client = NULL;
        }
+       if (clp->cl_cb_conn.cb_xprt) {
+               svc_xprt_put(clp->cl_cb_conn.cb_xprt);
+               clp->cl_cb_conn.cb_xprt = NULL;
+       }
        if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
                return;
        spin_lock(&clp->cl_lock);
@@ -936,11 +968,22 @@ void nfsd4_process_cb_update(struct nfsd4_callback *cb)
        BUG_ON(!clp->cl_cb_flags);
        clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
        memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
+       c = __nfsd4_find_backchannel(clp);
+       if (c) {
+               svc_xprt_get(c->cn_xprt);
+               conn.cb_xprt = c->cn_xprt;
+               ses = c->cn_session;
+       }
        spin_unlock(&clp->cl_lock);
 
-       err = setup_callback_client(clp, &conn);
-       if (err)
+       err = setup_callback_client(clp, &conn, ses);
+       if (err) {
                warn_no_callback_path(clp, err);
+               return;
+       }
+       /* Yay, the callback channel's back! Restart any callbacks: */
+       list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client)
+               run_nfsd4_cb(cb);
 }
 
 void nfsd4_do_callback_rpc(struct work_struct *w)
@@ -965,10 +1008,11 @@ void nfsd4_do_callback_rpc(struct work_struct *w)
 void nfsd4_cb_recall(struct nfs4_delegation *dp)
 {
        struct nfsd4_callback *cb = &dp->dl_recall;
+       struct nfs4_client *clp = dp->dl_client;
 
        dp->dl_retries = 1;
        cb->cb_op = dp;
-       cb->cb_clp = dp->dl_client;
+       cb->cb_clp = clp;
        cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
        cb->cb_msg.rpc_argp = cb;
        cb->cb_msg.rpc_resp = cb;
@@ -977,5 +1021,8 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
        cb->cb_ops = &nfsd4_cb_recall_ops;
        dp->dl_retries = 1;
 
-       queue_work(callback_wq, &dp->dl_recall.cb_work);
+       INIT_LIST_HEAD(&cb->cb_per_client);
+       cb->cb_done = true;
+
+       run_nfsd4_cb(&dp->dl_recall);
 }
index f0695e815f0ec9e53a2e9934392ac820d36e442e..6d2c397d458b6c9481998711ad1bb406fd6fd79c 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/nfsd_idmap.h>
 #include <linux/seq_file.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include "idmap.h"
+#include "nfsd.h"
 
 /*
  * Cache entry
@@ -514,7 +515,7 @@ rqst_authname(struct svc_rqst *rqstp)
        return clp->name;
 }
 
-static int
+static __be32
 idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen,
                uid_t *id)
 {
@@ -524,15 +525,15 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
        int ret;
 
        if (namelen + 1 > sizeof(key.name))
-               return -EINVAL;
+               return nfserr_badowner;
        memcpy(key.name, name, namelen);
        key.name[namelen] = '\0';
        strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
        ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item);
        if (ret == -ENOENT)
-               ret = -ESRCH; /* nfserr_badname */
+               return nfserr_badowner;
        if (ret)
-               return ret;
+               return nfserrno(ret);
        *id = item->id;
        cache_put(&item->h, &nametoid_cache);
        return 0;
@@ -560,14 +561,14 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
        return ret;
 }
 
-int
+__be32
 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
                __u32 *id)
 {
        return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id);
 }
 
-int
+__be32
 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
                __u32 *id)
 {
index 0cdfd022bb7b307d344989f493b9873b903dd22d..db52546143d1290ba8f1510a94b8db0054b45200 100644 (file)
@@ -604,9 +604,7 @@ nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        return status;
 }
 
-static __be32
-nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-             void *arg)
+static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
 {
        struct svc_fh tmp_fh;
        __be32 ret;
@@ -615,13 +613,19 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        ret = exp_pseudoroot(rqstp, &tmp_fh);
        if (ret)
                return ret;
-       if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) {
+       if (tmp_fh.fh_dentry == fh->fh_dentry) {
                fh_put(&tmp_fh);
                return nfserr_noent;
        }
        fh_put(&tmp_fh);
-       return nfsd_lookup(rqstp, &cstate->current_fh,
-                          "..", 2, &cstate->current_fh);
+       return nfsd_lookup(rqstp, fh, "..", 2, fh);
+}
+
+static __be32
+nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+             void *arg)
+{
+       return nfsd4_do_lookupp(rqstp, &cstate->current_fh);
 }
 
 static __be32
@@ -769,9 +773,35 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        } else
                secinfo->si_exp = exp;
        dput(dentry);
+       if (cstate->minorversion)
+               /* See rfc 5661 section 2.6.3.1.1.8 */
+               fh_put(&cstate->current_fh);
        return err;
 }
 
+static __be32
+nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+             struct nfsd4_secinfo_no_name *sin)
+{
+       __be32 err;
+
+       switch (sin->sin_style) {
+       case NFS4_SECINFO_STYLE4_CURRENT_FH:
+               break;
+       case NFS4_SECINFO_STYLE4_PARENT:
+               err = nfsd4_do_lookupp(rqstp, &cstate->current_fh);
+               if (err)
+                       return err;
+               break;
+       default:
+               return nfserr_inval;
+       }
+       exp_get(cstate->current_fh.fh_export);
+       sin->sin_exp = cstate->current_fh.fh_export;
+       fh_put(&cstate->current_fh);
+       return nfs_ok;
+}
+
 static __be32
 nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
              struct nfsd4_setattr *setattr)
@@ -974,8 +1004,8 @@ static const char *nfsd4_op_name(unsigned opnum);
  * Also note, enforced elsewhere:
  *     - SEQUENCE other than as first op results in
  *       NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().)
- *     - BIND_CONN_TO_SESSION must be the only op in its compound
- *       (Will be enforced in nfsd4_bind_conn_to_session().)
+ *     - BIND_CONN_TO_SESSION must be the only op in its compound.
+ *       (Enforced in nfsd4_bind_conn_to_session().)
  *     - DESTROY_SESSION must be the final operation in a compound, if
  *       sessionid's in SEQUENCE and DESTROY_SESSION are the same.
  *       (Enforced in nfsd4_destroy_session().)
@@ -1126,10 +1156,6 @@ encode_op:
 
                nfsd4_increment_op_stats(op->opnum);
        }
-       if (!rqstp->rq_usedeferral && status == nfserr_dropit) {
-               dprintk("%s Dropit - send NFS4ERR_DELAY\n", __func__);
-               status = nfserr_jukebox;
-       }
 
        resp->cstate.status = status;
        fh_put(&resp->cstate.current_fh);
@@ -1300,6 +1326,11 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
                .op_name = "OP_EXCHANGE_ID",
        },
+       [OP_BIND_CONN_TO_SESSION] = {
+               .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session,
+               .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
+               .op_name = "OP_BIND_CONN_TO_SESSION",
+       },
        [OP_CREATE_SESSION] = {
                .op_func = (nfsd4op_func)nfsd4_create_session,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
@@ -1320,6 +1351,10 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_flags = ALLOWED_WITHOUT_FH,
                .op_name = "OP_RECLAIM_COMPLETE",
        },
+       [OP_SECINFO_NO_NAME] = {
+               .op_func = (nfsd4op_func)nfsd4_secinfo_no_name,
+               .op_name = "OP_SECINFO_NO_NAME",
+       },
 };
 
 static const char *nfsd4_op_name(unsigned opnum)
index 7e26caab2a262befd2c74af594d076e0ebb40121..ffb59ef6f82f71a3813139bde209f53bccd54aca 100644 (file)
@@ -302,7 +302,6 @@ purge_old(struct dentry *parent, struct dentry *child)
 {
        int status;
 
-       /* note: we currently use this path only for minorversion 0 */
        if (nfs4_has_reclaimed_state(child->d_name.name, false))
                return 0;
 
index fbd18c3074bbb54aad024e08024b31fac9fc7d53..d98d0213285d8dfa2a4b178c6ae8972318f171fc 100644 (file)
@@ -230,7 +230,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        dp->dl_client = clp;
        get_nfs4_file(fp);
        dp->dl_file = fp;
-       nfs4_file_get_access(fp, O_RDONLY);
+       dp->dl_vfs_file = find_readable_file(fp);
+       get_file(dp->dl_vfs_file);
        dp->dl_flock = NULL;
        dp->dl_type = type;
        dp->dl_stateid.si_boot = boot_time;
@@ -252,6 +253,7 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
        if (atomic_dec_and_test(&dp->dl_count)) {
                dprintk("NFSD: freeing dp %p\n",dp);
                put_nfs4_file(dp->dl_file);
+               fput(dp->dl_vfs_file);
                kmem_cache_free(deleg_slab, dp);
                num_delegations--;
        }
@@ -265,12 +267,10 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
 static void
 nfs4_close_delegation(struct nfs4_delegation *dp)
 {
-       struct file *filp = find_readable_file(dp->dl_file);
-
        dprintk("NFSD: close_delegation dp %p\n",dp);
+       /* XXX: do we even need this check?: */
        if (dp->dl_flock)
-               vfs_setlease(filp, F_UNLCK, &dp->dl_flock);
-       nfs4_file_put_access(dp->dl_file, O_RDONLY);
+               vfs_setlease(dp->dl_vfs_file, F_UNLCK, &dp->dl_flock);
 }
 
 /* Called under the state lock. */
@@ -642,6 +642,7 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u)
                free_conn(c);
        }
        spin_unlock(&clp->cl_lock);
+       nfsd4_probe_callback(clp);
 }
 
 static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
@@ -679,15 +680,12 @@ static int nfsd4_register_conn(struct nfsd4_conn *conn)
        return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
 }
 
-static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
+static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir)
 {
        struct nfsd4_conn *conn;
-       u32 flags = NFS4_CDFC4_FORE;
        int ret;
 
-       if (ses->se_flags & SESSION4_BACK_CHAN)
-               flags |= NFS4_CDFC4_BACK;
-       conn = alloc_conn(rqstp, flags);
+       conn = alloc_conn(rqstp, dir);
        if (!conn)
                return nfserr_jukebox;
        nfsd4_hash_conn(conn, ses);
@@ -698,6 +696,17 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
        return nfs_ok;
 }
 
+static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses)
+{
+       u32 dir = NFS4_CDFC4_FORE;
+
+       if (ses->se_flags & SESSION4_BACK_CHAN)
+               dir |= NFS4_CDFC4_BACK;
+
+       return nfsd4_new_conn(rqstp, ses, dir);
+}
+
+/* must be called under client_lock */
 static void nfsd4_del_conns(struct nfsd4_session *s)
 {
        struct nfs4_client *clp = s->se_client;
@@ -749,6 +758,8 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
         */
        slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached);
        numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs);
+       if (numslots < 1)
+               return NULL;
 
        new = alloc_session(slotsize, numslots);
        if (!new) {
@@ -769,25 +780,30 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
        idx = hash_sessionid(&new->se_sessionid);
        spin_lock(&client_lock);
        list_add(&new->se_hash, &sessionid_hashtbl[idx]);
+       spin_lock(&clp->cl_lock);
        list_add(&new->se_perclnt, &clp->cl_sessions);
+       spin_unlock(&clp->cl_lock);
        spin_unlock(&client_lock);
 
-       status = nfsd4_new_conn(rqstp, new);
+       status = nfsd4_new_conn_from_crses(rqstp, new);
        /* whoops: benny points out, status is ignored! (err, or bogus) */
        if (status) {
                free_session(&new->se_ref);
                return NULL;
        }
-       if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) {
+       if (cses->flags & SESSION4_BACK_CHAN) {
                struct sockaddr *sa = svc_addr(rqstp);
-
-               clp->cl_cb_session = new;
-               clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
-               svc_xprt_get(rqstp->rq_xprt);
+               /*
+                * This is a little silly; with sessions there's no real
+                * use for the callback address.  Use the peer address
+                * as a reasonable default for now, but consider fixing
+                * the rpc client not to require an address in the
+                * future:
+                */
                rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
                clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
-               nfsd4_probe_callback(clp);
        }
+       nfsd4_probe_callback(clp);
        return new;
 }
 
@@ -817,7 +833,9 @@ static void
 unhash_session(struct nfsd4_session *ses)
 {
        list_del(&ses->se_hash);
+       spin_lock(&ses->se_client->cl_lock);
        list_del(&ses->se_perclnt);
+       spin_unlock(&ses->se_client->cl_lock);
 }
 
 /* must be called under the client_lock */
@@ -923,8 +941,10 @@ unhash_client_locked(struct nfs4_client *clp)
 
        mark_client_expired(clp);
        list_del(&clp->cl_lru);
+       spin_lock(&clp->cl_lock);
        list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
                list_del_init(&ses->se_hash);
+       spin_unlock(&clp->cl_lock);
 }
 
 static void
@@ -1051,12 +1071,13 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
 
        memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
        atomic_set(&clp->cl_refcount, 0);
-       atomic_set(&clp->cl_cb_set, 0);
+       clp->cl_cb_state = NFSD4_CB_UNKNOWN;
        INIT_LIST_HEAD(&clp->cl_idhash);
        INIT_LIST_HEAD(&clp->cl_strhash);
        INIT_LIST_HEAD(&clp->cl_openowners);
        INIT_LIST_HEAD(&clp->cl_delegations);
        INIT_LIST_HEAD(&clp->cl_lru);
+       INIT_LIST_HEAD(&clp->cl_callbacks);
        spin_lock_init(&clp->cl_lock);
        INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
        clp->cl_time = get_seconds();
@@ -1132,54 +1153,55 @@ find_unconfirmed_client(clientid_t *clid)
        return NULL;
 }
 
-/*
- * Return 1 iff clp's clientid establishment method matches the use_exchange_id
- * parameter. Matching is based on the fact the at least one of the
- * EXCHGID4_FLAG_USE_{NON_PNFS,PNFS_MDS,PNFS_DS} flags must be set for v4.1
- *
- * FIXME: we need to unify the clientid namespaces for nfsv4.x
- * and correctly deal with client upgrade/downgrade in EXCHANGE_ID
- * and SET_CLIENTID{,_CONFIRM}
- */
-static inline int
-match_clientid_establishment(struct nfs4_client *clp, bool use_exchange_id)
+static bool clp_used_exchangeid(struct nfs4_client *clp)
 {
-       bool has_exchange_flags = (clp->cl_exchange_flags != 0);
-       return use_exchange_id == has_exchange_flags;
-}
+       return clp->cl_exchange_flags != 0;
+} 
 
 static struct nfs4_client *
-find_confirmed_client_by_str(const char *dname, unsigned int hashval,
-                            bool use_exchange_id)
+find_confirmed_client_by_str(const char *dname, unsigned int hashval)
 {
        struct nfs4_client *clp;
 
        list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {
-               if (same_name(clp->cl_recdir, dname) &&
-                   match_clientid_establishment(clp, use_exchange_id))
+               if (same_name(clp->cl_recdir, dname))
                        return clp;
        }
        return NULL;
 }
 
 static struct nfs4_client *
-find_unconfirmed_client_by_str(const char *dname, unsigned int hashval,
-                              bool use_exchange_id)
+find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
 {
        struct nfs4_client *clp;
 
        list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {
-               if (same_name(clp->cl_recdir, dname) &&
-                   match_clientid_establishment(clp, use_exchange_id))
+               if (same_name(clp->cl_recdir, dname))
                        return clp;
        }
        return NULL;
 }
 
+static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr)
+{
+       switch (family) {
+       case AF_INET:
+               ((struct sockaddr_in *)sa)->sin_family = AF_INET;
+               ((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr;
+               return;
+       case AF_INET6:
+               ((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6;
+               ((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6;
+               return;
+       }
+}
+
 static void
-gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
+gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
 {
        struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
+       struct sockaddr *sa = svc_addr(rqstp);
+       u32 scopeid = rpc_get_scope_id(sa);
        unsigned short expected_family;
 
        /* Currently, we only support tcp and tcp6 for the callback channel */
@@ -1205,6 +1227,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
 
        conn->cb_prog = se->se_callback_prog;
        conn->cb_ident = se->se_callback_ident;
+       rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr);
        return;
 out_err:
        conn->cb_addr.ss_family = AF_UNSPEC;
@@ -1344,7 +1367,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
        case SP4_NONE:
                break;
        case SP4_SSV:
-               return nfserr_encr_alg_unsupp;
+               return nfserr_serverfault;
        default:
                BUG();                          /* checked by xdr code */
        case SP4_MACH_CRED:
@@ -1361,8 +1384,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
        nfs4_lock_state();
        status = nfs_ok;
 
-       conf = find_confirmed_client_by_str(dname, strhashval, true);
+       conf = find_confirmed_client_by_str(dname, strhashval);
        if (conf) {
+               if (!clp_used_exchangeid(conf)) {
+                       status = nfserr_clid_inuse; /* XXX: ? */
+                       goto out;
+               }
                if (!same_verf(&verf, &conf->cl_verifier)) {
                        /* 18.35.4 case 8 */
                        if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
@@ -1403,7 +1430,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
                goto out;
        }
 
-       unconf  = find_unconfirmed_client_by_str(dname, strhashval, true);
+       unconf  = find_unconfirmed_client_by_str(dname, strhashval);
        if (unconf) {
                /*
                 * Possible retry or client restart.  Per 18.35.4 case 4,
@@ -1560,6 +1587,8 @@ nfsd4_create_session(struct svc_rqst *rqstp,
        status = nfs_ok;
        memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
               NFS4_MAX_SESSIONID_LEN);
+       memcpy(&cr_ses->fore_channel, &new->se_fchannel,
+               sizeof(struct nfsd4_channel_attrs));
        cs_slot->sl_seqid++;
        cr_ses->seqid = cs_slot->sl_seqid;
 
@@ -1581,6 +1610,45 @@ static bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
        return argp->opcnt == resp->opcnt;
 }
 
+static __be32 nfsd4_map_bcts_dir(u32 *dir)
+{
+       switch (*dir) {
+       case NFS4_CDFC4_FORE:
+       case NFS4_CDFC4_BACK:
+               return nfs_ok;
+       case NFS4_CDFC4_FORE_OR_BOTH:
+       case NFS4_CDFC4_BACK_OR_BOTH:
+               *dir = NFS4_CDFC4_BOTH;
+               return nfs_ok;
+       };
+       return nfserr_inval;
+}
+
+__be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
+                    struct nfsd4_compound_state *cstate,
+                    struct nfsd4_bind_conn_to_session *bcts)
+{
+       __be32 status;
+
+       if (!nfsd4_last_compound_op(rqstp))
+               return nfserr_not_only_op;
+       spin_lock(&client_lock);
+       cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid);
+       /* Sorta weird: we only need the refcnt'ing because new_conn acquires
+        * client_lock iself: */
+       if (cstate->session) {
+               nfsd4_get_session(cstate->session);
+               atomic_inc(&cstate->session->se_client->cl_refcount);
+       }
+       spin_unlock(&client_lock);
+       if (!cstate->session)
+               return nfserr_badsession;
+
+       status = nfsd4_map_bcts_dir(&bcts->dir);
+       nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
+       return nfs_ok;
+}
+
 static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
 {
        if (!session)
@@ -1619,8 +1687,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
        spin_unlock(&client_lock);
 
        nfs4_lock_state();
-       /* wait for callbacks */
-       nfsd4_shutdown_callback(ses->se_client);
+       nfsd4_probe_callback_sync(ses->se_client);
        nfs4_unlock_state();
 
        nfsd4_del_conns(ses);
@@ -1733,8 +1800,12 @@ nfsd4_sequence(struct svc_rqst *rqstp,
 out:
        /* Hold a session reference until done processing the compound. */
        if (cstate->session) {
+               struct nfs4_client *clp = session->se_client;
+
                nfsd4_get_session(cstate->session);
-               atomic_inc(&session->se_client->cl_refcount);
+               atomic_inc(&clp->cl_refcount);
+               if (clp->cl_cb_state == NFSD4_CB_DOWN)
+                       seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN;
        }
        kfree(conn);
        spin_unlock(&client_lock);
@@ -1775,7 +1846,6 @@ __be32
 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                  struct nfsd4_setclientid *setclid)
 {
-       struct sockaddr         *sa = svc_addr(rqstp);
        struct xdr_netobj       clname = { 
                .len = setclid->se_namelen,
                .data = setclid->se_name,
@@ -1801,10 +1871,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        strhashval = clientstr_hashval(dname);
 
        nfs4_lock_state();
-       conf = find_confirmed_client_by_str(dname, strhashval, false);
+       conf = find_confirmed_client_by_str(dname, strhashval);
        if (conf) {
                /* RFC 3530 14.2.33 CASE 0: */
                status = nfserr_clid_inuse;
+               if (clp_used_exchangeid(conf))
+                       goto out;
                if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
                        char addr_str[INET6_ADDRSTRLEN];
                        rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
@@ -1819,7 +1891,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
         * has a description of SETCLIENTID request processing consisting
         * of 5 bullet points, labeled as CASE0 - CASE4 below.
         */
-       unconf = find_unconfirmed_client_by_str(dname, strhashval, false);
+       unconf = find_unconfirmed_client_by_str(dname, strhashval);
        status = nfserr_resource;
        if (!conf) {
                /*
@@ -1876,7 +1948,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
         * for consistent minorversion use throughout:
         */
        new->cl_minorversion = 0;
-       gen_callback(new, setclid, rpc_get_scope_id(sa));
+       gen_callback(new, setclid, rqstp);
        add_to_unconfirmed(new, strhashval);
        setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
        setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
@@ -1935,7 +2007,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
                        status = nfserr_clid_inuse;
                else {
-                       atomic_set(&conf->cl_cb_set, 0);
                        nfsd4_change_callback(conf, &unconf->cl_cb_conn);
                        nfsd4_probe_callback(conf);
                        expire_client(unconf);
@@ -1964,7 +2035,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        unsigned int hash =
                                clientstr_hashval(unconf->cl_recdir);
                        conf = find_confirmed_client_by_str(unconf->cl_recdir,
-                                                           hash, false);
+                                                           hash);
                        if (conf) {
                                nfsd4_remove_clid_dir(conf);
                                expire_client(conf);
@@ -2300,41 +2371,6 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
        nfsd4_cb_recall(dp);
 }
 
-/*
- * The file_lock is being reapd.
- *
- * Called by locks_free_lock() with lock_flocks() held.
- */
-static
-void nfsd_release_deleg_cb(struct file_lock *fl)
-{
-       struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
-
-       dprintk("NFSD nfsd_release_deleg_cb: fl %p dp %p dl_count %d\n", fl,dp, atomic_read(&dp->dl_count));
-
-       if (!(fl->fl_flags & FL_LEASE) || !dp)
-               return;
-       dp->dl_flock = NULL;
-}
-
-/*
- * Called from setlease() with lock_flocks() held
- */
-static
-int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try)
-{
-       struct nfs4_delegation *onlistd =
-               (struct nfs4_delegation *)onlist->fl_owner;
-       struct nfs4_delegation *tryd =
-               (struct nfs4_delegation *)try->fl_owner;
-
-       if (onlist->fl_lmops != try->fl_lmops)
-               return 0;
-
-       return onlistd->dl_client == tryd->dl_client;
-}
-
-
 static
 int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
 {
@@ -2346,8 +2382,6 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
 
 static const struct lock_manager_operations nfsd_lease_mng_ops = {
        .fl_break = nfsd_break_deleg_cb,
-       .fl_release_private = nfsd_release_deleg_cb,
-       .fl_mylease = nfsd_same_client_deleg_cb,
        .fl_change = nfsd_change_deleg_cb,
 };
 
@@ -2514,8 +2548,6 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file
        if (!fp->fi_fds[oflag]) {
                status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
                        &fp->fi_fds[oflag]);
-               if (status == nfserr_dropit)
-                       status = nfserr_jukebox;
                if (status)
                        return status;
        }
@@ -2596,6 +2628,19 @@ nfs4_set_claim_prev(struct nfsd4_open *open)
        open->op_stateowner->so_client->cl_firststate = 1;
 }
 
+/* Should we give out recallable state?: */
+static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
+{
+       if (clp->cl_cb_state == NFSD4_CB_UP)
+               return true;
+       /*
+        * In the sessions case, since we don't have to establish a
+        * separate connection for callbacks, we assume it's OK
+        * until we hear otherwise:
+        */
+       return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
+}
+
 /*
  * Attempt to hand out a delegation.
  */
@@ -2604,10 +2649,11 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
 {
        struct nfs4_delegation *dp;
        struct nfs4_stateowner *sop = stp->st_stateowner;
-       int cb_up = atomic_read(&sop->so_client->cl_cb_set);
+       int cb_up;
        struct file_lock *fl;
        int status, flag = 0;
 
+       cb_up = nfsd4_cb_channel_good(sop->so_client);
        flag = NFS4_OPEN_DELEGATE_NONE;
        open->op_recall = 0;
        switch (open->op_claim_type) {
@@ -2655,7 +2701,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        dp->dl_flock = fl;
 
        /* vfs_setlease checks to see if delegation should be handed out.
-        * the lock_manager callbacks fl_mylease and fl_change are used
+        * the lock_manager callback fl_change is used
         */
        if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) {
                dprintk("NFSD: setlease failed [%d], no delegation\n", status);
@@ -2794,7 +2840,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        renew_client(clp);
        status = nfserr_cb_path_down;
        if (!list_empty(&clp->cl_delegations)
-                       && !atomic_read(&clp->cl_cb_set))
+                       && clp->cl_cb_state != NFSD4_CB_UP)
                goto out;
        status = nfs_ok;
 out:
@@ -3081,9 +3127,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
                if (status)
                        goto out;
                renew_client(dp->dl_client);
-               if (filpp)
+               if (filpp) {
                        *filpp = find_readable_file(dp->dl_file);
-               BUG_ON(!*filpp);
+                       BUG_ON(!*filpp);
+               }
        } else { /* open or lock stateid */
                stp = find_stateid(stateid, flags);
                if (!stp)
@@ -4107,7 +4154,7 @@ nfs4_has_reclaimed_state(const char *name, bool use_exchange_id)
        unsigned int strhashval = clientstr_hashval(name);
        struct nfs4_client *clp;
 
-       clp = find_confirmed_client_by_str(name, strhashval, use_exchange_id);
+       clp = find_confirmed_client_by_str(name, strhashval);
        return clp ? 1 : 0;
 }
 
index f35a94a0402677d36193c9fcb57992edcc061e9d..956629b9cdc9c841a0f428ad12e9687cec21295f 100644 (file)
 #include <linux/namei.h>
 #include <linux/statfs.h>
 #include <linux/utsname.h>
-#include <linux/nfsd_idmap.h>
-#include <linux/nfs4_acl.h>
 #include <linux/sunrpc/svcauth_gss.h>
 
+#include "idmap.h"
+#include "acl.h"
 #include "xdr4.h"
 #include "vfs.h"
 
+
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
 /*
@@ -288,17 +289,17 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                        len += XDR_QUADLEN(dummy32) << 2;
                        READMEM(buf, dummy32);
                        ace->whotype = nfs4_acl_get_whotype(buf, dummy32);
-                       host_err = 0;
+                       status = nfs_ok;
                        if (ace->whotype != NFS4_ACL_WHO_NAMED)
                                ace->who = 0;
                        else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
-                               host_err = nfsd_map_name_to_gid(argp->rqstp,
+                               status = nfsd_map_name_to_gid(argp->rqstp,
                                                buf, dummy32, &ace->who);
                        else
-                               host_err = nfsd_map_name_to_uid(argp->rqstp,
+                               status = nfsd_map_name_to_uid(argp->rqstp,
                                                buf, dummy32, &ace->who);
-                       if (host_err)
-                               goto out_nfserr;
+                       if (status)
+                               return status;
                }
        } else
                *acl = NULL;
@@ -420,6 +421,21 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access
        DECODE_TAIL;
 }
 
+static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts)
+{
+       DECODE_HEAD;
+       u32 dummy;
+
+       READ_BUF(NFS4_MAX_SESSIONID_LEN + 8);
+       COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
+       READ32(bcts->dir);
+       /* XXX: Perhaps Tom Tucker could help us figure out how we
+        * should be using ctsa_use_conn_in_rdma_mode: */
+       READ32(dummy);
+
+       DECODE_TAIL;
+}
+
 static __be32
 nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
 {
@@ -846,6 +862,17 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
        DECODE_TAIL;
 }
 
+static __be32
+nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp,
+                    struct nfsd4_secinfo_no_name *sin)
+{
+       DECODE_HEAD;
+
+       READ_BUF(4);
+       READ32(sin->sin_style);
+       DECODE_TAIL;
+}
+
 static __be32
 nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
 {
@@ -1005,7 +1032,7 @@ static __be32
 nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
                         struct nfsd4_exchange_id *exid)
 {
-       int dummy;
+       int dummy, tmp;
        DECODE_HEAD;
 
        READ_BUF(NFS4_VERIFIER_SIZE);
@@ -1053,15 +1080,23 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
 
                /* ssp_hash_algs<> */
                READ_BUF(4);
-               READ32(dummy);
-               READ_BUF(dummy);
-               p += XDR_QUADLEN(dummy);
+               READ32(tmp);
+               while (tmp--) {
+                       READ_BUF(4);
+                       READ32(dummy);
+                       READ_BUF(dummy);
+                       p += XDR_QUADLEN(dummy);
+               }
 
                /* ssp_encr_algs<> */
                READ_BUF(4);
-               READ32(dummy);
-               READ_BUF(dummy);
-               p += XDR_QUADLEN(dummy);
+               READ32(tmp);
+               while (tmp--) {
+                       READ_BUF(4);
+                       READ32(dummy);
+                       READ_BUF(dummy);
+                       p += XDR_QUADLEN(dummy);
+               }
 
                /* ssp_window and ssp_num_gss_handles */
                READ_BUF(8);
@@ -1339,7 +1374,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
 
        /* new operations for NFSv4.1 */
        [OP_BACKCHANNEL_CTL]    = (nfsd4_dec)nfsd4_decode_notsupp,
-       [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_notsupp,
+       [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session,
        [OP_EXCHANGE_ID]        = (nfsd4_dec)nfsd4_decode_exchange_id,
        [OP_CREATE_SESSION]     = (nfsd4_dec)nfsd4_decode_create_session,
        [OP_DESTROY_SESSION]    = (nfsd4_dec)nfsd4_decode_destroy_session,
@@ -1350,7 +1385,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
        [OP_LAYOUTCOMMIT]       = (nfsd4_dec)nfsd4_decode_notsupp,
        [OP_LAYOUTGET]          = (nfsd4_dec)nfsd4_decode_notsupp,
        [OP_LAYOUTRETURN]       = (nfsd4_dec)nfsd4_decode_notsupp,
-       [OP_SECINFO_NO_NAME]    = (nfsd4_dec)nfsd4_decode_notsupp,
+       [OP_SECINFO_NO_NAME]    = (nfsd4_dec)nfsd4_decode_secinfo_no_name,
        [OP_SEQUENCE]           = (nfsd4_dec)nfsd4_decode_sequence,
        [OP_SET_SSV]            = (nfsd4_dec)nfsd4_decode_notsupp,
        [OP_TEST_STATEID]       = (nfsd4_dec)nfsd4_decode_notsupp,
@@ -2309,8 +2344,6 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
        case nfserr_resource:
                nfserr = nfserr_toosmall;
                goto fail;
-       case nfserr_dropit:
-               goto fail;
        case nfserr_noent:
                goto skip_entry;
        default:
@@ -2365,6 +2398,21 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
        return nfserr;
 }
 
+static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts)
+{
+       __be32 *p;
+
+       if (!nfserr) {
+               RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8);
+               WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
+               WRITE32(bcts->dir);
+               /* XXX: ? */
+               WRITE32(0);
+               ADJUST_ARGS();
+       }
+       return nfserr;
+}
+
 static __be32
 nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
 {
@@ -2826,11 +2874,10 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
 }
 
 static __be32
-nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
-                    struct nfsd4_secinfo *secinfo)
+nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
+                        __be32 nfserr,struct svc_export *exp)
 {
        int i = 0;
-       struct svc_export *exp = secinfo->si_exp;
        u32 nflavs;
        struct exp_flavor_info *flavs;
        struct exp_flavor_info def_flavs[2];
@@ -2892,6 +2939,20 @@ out:
        return nfserr;
 }
 
+static __be32
+nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
+                    struct nfsd4_secinfo *secinfo)
+{
+       return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->si_exp);
+}
+
+static __be32
+nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
+                    struct nfsd4_secinfo_no_name *secinfo)
+{
+       return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->sin_exp);
+}
+
 /*
  * The SETATTR encode routine is special -- it always encodes a bitmap,
  * regardless of the error status.
@@ -3076,13 +3137,9 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
        WRITE32(seq->seqid);
        WRITE32(seq->slotid);
        WRITE32(seq->maxslots);
-       /*
-        * FIXME: for now:
-        *   target_maxslots = maxslots
-        *   status_flags = 0
-        */
+       /* For now: target_maxslots = maxslots */
        WRITE32(seq->maxslots);
-       WRITE32(0);
+       WRITE32(seq->status_flags);
 
        ADJUST_ARGS();
        resp->cstate.datap = p; /* DRC cache data pointer */
@@ -3143,7 +3200,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
 
        /* NFSv4.1 operations */
        [OP_BACKCHANNEL_CTL]    = (nfsd4_enc)nfsd4_encode_noop,
-       [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_noop,
+       [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session,
        [OP_EXCHANGE_ID]        = (nfsd4_enc)nfsd4_encode_exchange_id,
        [OP_CREATE_SESSION]     = (nfsd4_enc)nfsd4_encode_create_session,
        [OP_DESTROY_SESSION]    = (nfsd4_enc)nfsd4_encode_destroy_session,
@@ -3154,7 +3211,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
        [OP_LAYOUTCOMMIT]       = (nfsd4_enc)nfsd4_encode_noop,
        [OP_LAYOUTGET]          = (nfsd4_enc)nfsd4_encode_noop,
        [OP_LAYOUTRETURN]       = (nfsd4_enc)nfsd4_encode_noop,
-       [OP_SECINFO_NO_NAME]    = (nfsd4_enc)nfsd4_encode_noop,
+       [OP_SECINFO_NO_NAME]    = (nfsd4_enc)nfsd4_encode_secinfo_no_name,
        [OP_SEQUENCE]           = (nfsd4_enc)nfsd4_encode_sequence,
        [OP_SET_SSV]            = (nfsd4_enc)nfsd4_encode_noop,
        [OP_TEST_STATEID]       = (nfsd4_enc)nfsd4_encode_noop,
index 4514ebbee4d6246aac28086ecbb90a0568a01d16..33b3e2b06779da530630fbb43800b3587c2728d9 100644 (file)
@@ -8,12 +8,12 @@
 #include <linux/namei.h>
 #include <linux/ctype.h>
 
-#include <linux/nfsd_idmap.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/nfsd/syscall.h>
 #include <linux/lockd/lockd.h>
 #include <linux/sunrpc/clnt.h>
 
+#include "idmap.h"
 #include "nfsd.h"
 #include "cache.h"
 
@@ -127,6 +127,7 @@ static ssize_t nfsctl_transaction_write(struct file *file, const char __user *bu
 
 static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
 {
+#ifdef CONFIG_NFSD_DEPRECATED
        static int warned;
        if (file->f_dentry->d_name.name[0] == '.' && !warned) {
                printk(KERN_INFO
@@ -135,6 +136,7 @@ static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size
                       current->comm, file->f_dentry->d_name.name);
                warned = 1;
        }
+#endif
        if (! file->private_data) {
                /* An attempt to read a transaction file without writing
                 * causes a 0-byte write so that the file can return
index 6b641cf2c19ac59a6f65326c40038e2549c6df83..7ecfa2420307c24c1e2331189b2e1ff534928c87 100644 (file)
@@ -158,6 +158,7 @@ void                nfsd_lockd_shutdown(void);
 #define        nfserr_attrnotsupp      cpu_to_be32(NFSERR_ATTRNOTSUPP)
 #define        nfserr_bad_xdr          cpu_to_be32(NFSERR_BAD_XDR)
 #define        nfserr_openmode         cpu_to_be32(NFSERR_OPENMODE)
+#define        nfserr_badowner         cpu_to_be32(NFSERR_BADOWNER)
 #define        nfserr_locks_held       cpu_to_be32(NFSERR_LOCKS_HELD)
 #define        nfserr_op_illegal       cpu_to_be32(NFSERR_OP_ILLEGAL)
 #define        nfserr_grace            cpu_to_be32(NFSERR_GRACE)
index 08e17264784b7f4dd2d5822cbb7c59a52a58f369..e15dc45fc5ec01c09a05d42b8ac600ed39e3892f 100644 (file)
@@ -735,9 +735,9 @@ nfserrno (int errno)
                { nfserr_stale, -ESTALE },
                { nfserr_jukebox, -ETIMEDOUT },
                { nfserr_jukebox, -ERESTARTSYS },
-               { nfserr_dropit, -EAGAIN },
-               { nfserr_dropit, -ENOMEM },
-               { nfserr_badname, -ESRCH },
+               { nfserr_jukebox, -EAGAIN },
+               { nfserr_jukebox, -EWOULDBLOCK },
+               { nfserr_jukebox, -ENOMEM },
                { nfserr_io, -ETXTBSY },
                { nfserr_notsupp, -EOPNOTSUPP },
                { nfserr_toosmall, -ETOOSMALL },
index 2bae1d86f5f241b8d62a61bf9ed8b5a0bcfc9c8e..18743c4d8bca848d493829f6385127f8e89508eb 100644 (file)
@@ -608,7 +608,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
        /* Now call the procedure handler, and encode NFS status. */
        nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
        nfserr = map_new_errors(rqstp->rq_vers, nfserr);
-       if (nfserr == nfserr_dropit) {
+       if (nfserr == nfserr_dropit || rqstp->rq_dropme) {
                dprintk("nfsd: Dropping request; may be revisited later\n");
                nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
                return 0;
index 39adc27b06853c37a40a1e951ff5027625a15b52..3074656ba7bf96cc23c024bc7b9ec35256b5cd80 100644 (file)
@@ -68,10 +68,12 @@ typedef struct {
 struct nfsd4_callback {
        void *cb_op;
        struct nfs4_client *cb_clp;
+       struct list_head cb_per_client;
        u32 cb_minorversion;
        struct rpc_message cb_msg;
        const struct rpc_call_ops *cb_ops;
        struct work_struct cb_work;
+       bool cb_done;
 };
 
 struct nfs4_delegation {
@@ -81,6 +83,7 @@ struct nfs4_delegation {
        atomic_t                dl_count;       /* ref count */
        struct nfs4_client      *dl_client;
        struct nfs4_file        *dl_file;
+       struct file             *dl_vfs_file;
        struct file_lock        *dl_flock;
        u32                     dl_type;
        time_t                  dl_time;
@@ -95,6 +98,7 @@ struct nfs4_delegation {
 struct nfs4_cb_conn {
        /* SETCLIENTID info */
        struct sockaddr_storage cb_addr;
+       struct sockaddr_storage cb_saddr;
        size_t                  cb_addrlen;
        u32                     cb_prog; /* used only in 4.0 case;
                                            per-session otherwise */
@@ -146,6 +150,11 @@ struct nfsd4_create_session {
        u32                             gid;
 };
 
+struct nfsd4_bind_conn_to_session {
+       struct nfs4_sessionid           sessionid;
+       u32                             dir;
+};
+
 /* The single slot clientid cache structure */
 struct nfsd4_clid_slot {
        u32                             sl_seqid;
@@ -235,9 +244,13 @@ struct nfs4_client {
        unsigned long           cl_cb_flags;
        struct rpc_clnt         *cl_cb_client;
        u32                     cl_cb_ident;
-       atomic_t                cl_cb_set;
+#define NFSD4_CB_UP            0
+#define NFSD4_CB_UNKNOWN       1
+#define NFSD4_CB_DOWN          2
+       int                     cl_cb_state;
        struct nfsd4_callback   cl_cb_null;
        struct nfsd4_session    *cl_cb_session;
+       struct list_head        cl_callbacks; /* list of in-progress callbacks */
 
        /* for all client information that callback code might need: */
        spinlock_t              cl_lock;
@@ -454,6 +467,7 @@ extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
 extern void nfs4_free_stateowner(struct kref *kref);
 extern int set_callback_cred(void);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
+extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
 extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
 extern void nfsd4_do_callback_rpc(struct work_struct *);
 extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
index 230b79fbf0051be98df5bc5067a2f6f8f18b3b8a..a3c7f701395a4f7fc3ffc02305b9b5e628de8704 100644 (file)
@@ -1,4 +1,3 @@
-#define MSNFS  /* HACK HACK */
 /*
  * File operations used by nfsd. Some of these have been ripped from
  * other parts of the kernel because they weren't exported, others
@@ -35,8 +34,8 @@
 #endif /* CONFIG_NFSD_V3 */
 
 #ifdef CONFIG_NFSD_V4
-#include <linux/nfs4_acl.h>
-#include <linux/nfsd_idmap.h>
+#include "acl.h"
+#include "idmap.h"
 #endif /* CONFIG_NFSD_V4 */
 
 #include "nfsd.h"
@@ -273,6 +272,13 @@ out:
        return err;
 }
 
+static int nfsd_break_lease(struct inode *inode)
+{
+       if (!S_ISREG(inode->i_mode))
+               return 0;
+       return break_lease(inode, O_WRONLY | O_NONBLOCK);
+}
+
 /*
  * Commit metadata changes to stable storage.
  */
@@ -375,16 +381,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
                                goto out;
                }
 
-               /*
-                * If we are changing the size of the file, then
-                * we need to break all leases.
-                */
-               host_err = break_lease(inode, O_WRONLY | O_NONBLOCK);
-               if (host_err == -EWOULDBLOCK)
-                       host_err = -ETIMEDOUT;
-               if (host_err) /* ENOMEM or EWOULDBLOCK */
-                       goto out_nfserr;
-
                host_err = get_write_access(inode);
                if (host_err)
                        goto out_nfserr;
@@ -425,7 +421,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
 
        err = nfserr_notsync;
        if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
+               host_err = nfsd_break_lease(inode);
+               if (host_err)
+                       goto out_nfserr;
                fh_lock(fhp);
+
                host_err = notify_change(dentry, iap);
                err = nfserrno(host_err);
                fh_unlock(fhp);
@@ -752,8 +752,6 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
         */
        if (!(access & NFSD_MAY_NOT_BREAK_LEASE))
                host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0));
-       if (host_err == -EWOULDBLOCK)
-               host_err = -ETIMEDOUT;
        if (host_err) /* NOMEM or WOULDBLOCK */
                goto out_nfserr;
 
@@ -874,15 +872,6 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
        return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
 }
 
-static inline int svc_msnfs(struct svc_fh *ffhp)
-{
-#ifdef MSNFS
-       return (ffhp->fh_export->ex_flags & NFSEXP_MSNFS);
-#else
-       return 0;
-#endif
-}
-
 static __be32
 nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
               loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
@@ -895,9 +884,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
        err = nfserr_perm;
        inode = file->f_path.dentry->d_inode;
 
-       if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count))
-               goto out;
-
        if (file->f_op->splice_read && rqstp->rq_splice_ok) {
                struct splice_desc sd = {
                        .len            = 0,
@@ -922,7 +908,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
                fsnotify_access(file);
        } else 
                err = nfserrno(host_err);
-out:
        return err;
 }
 
@@ -987,14 +972,6 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
        int                     stable = *stablep;
        int                     use_wgather;
 
-#ifdef MSNFS
-       err = nfserr_perm;
-
-       if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
-               (!lock_may_write(file->f_path.dentry->d_inode, offset, *cnt)))
-               goto out;
-#endif
-
        dentry = file->f_path.dentry;
        inode = dentry->d_inode;
        exp   = fhp->fh_export;
@@ -1045,7 +1022,6 @@ out_nfserr:
                err = 0;
        else
                err = nfserrno(host_err);
-out:
        return err;
 }
 
@@ -1665,6 +1641,12 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
                err = nfserrno(host_err);
                goto out_dput;
        }
+       err = nfserr_noent;
+       if (!dold->d_inode)
+               goto out_drop_write;
+       host_err = nfsd_break_lease(dold->d_inode);
+       if (host_err)
+               goto out_drop_write;
        host_err = vfs_link(dold, dirp, dnew);
        if (!host_err) {
                err = nfserrno(commit_metadata(ffhp));
@@ -1676,6 +1658,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
                else
                        err = nfserrno(host_err);
        }
+out_drop_write:
        mnt_drop_write(tfhp->fh_export->ex_path.mnt);
 out_dput:
        dput(dnew);
@@ -1750,12 +1733,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
        if (ndentry == trap)
                goto out_dput_new;
 
-       if (svc_msnfs(ffhp) &&
-               ((odentry->d_count > 1) || (ndentry->d_count > 1))) {
-                       host_err = -EPERM;
-                       goto out_dput_new;
-       }
-
        host_err = -EXDEV;
        if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt)
                goto out_dput_new;
@@ -1763,15 +1740,17 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
        if (host_err)
                goto out_dput_new;
 
+       host_err = nfsd_break_lease(odentry->d_inode);
+       if (host_err)
+               goto out_drop_write;
        host_err = vfs_rename(fdir, odentry, tdir, ndentry);
        if (!host_err) {
                host_err = commit_metadata(tfhp);
                if (!host_err)
                        host_err = commit_metadata(ffhp);
        }
-
+out_drop_write:
        mnt_drop_write(ffhp->fh_export->ex_path.mnt);
-
  out_dput_new:
        dput(ndentry);
  out_dput_old:
@@ -1834,18 +1813,14 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        if (host_err)
                goto out_nfserr;
 
-       if (type != S_IFDIR) { /* It's UNLINK */
-#ifdef MSNFS
-               if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
-                       (rdentry->d_count > 1)) {
-                       host_err = -EPERM;
-               } else
-#endif
+       host_err = nfsd_break_lease(rdentry->d_inode);
+       if (host_err)
+               goto out_put;
+       if (type != S_IFDIR)
                host_err = vfs_unlink(dirp, rdentry);
-       } else { /* It's RMDIR */
+       else
                host_err = vfs_rmdir(dirp, rdentry);
-       }
-
+out_put:
        dput(rdentry);
 
        if (!host_err)
index 60fce3dc5cb5d9f90d22b9f9c91ddc7ddeb9ff1d..366401e1a536430f5314e2fe1496a777fd0dc31b 100644 (file)
@@ -311,6 +311,11 @@ struct nfsd4_secinfo {
        struct svc_export *si_exp;                      /* response */
 };
 
+struct nfsd4_secinfo_no_name {
+       u32 sin_style;                                  /* request */
+       struct svc_export *sin_exp;                     /* response */
+};
+
 struct nfsd4_setattr {
        stateid_t       sa_stateid;         /* request */
        u32             sa_bmval[3];        /* request */
@@ -373,8 +378,8 @@ struct nfsd4_sequence {
        u32                     cachethis;              /* request */
 #if 0
        u32                     target_maxslots;        /* response */
-       u32                     status_flags;           /* response */
 #endif /* not yet */
+       u32                     status_flags;           /* response */
 };
 
 struct nfsd4_destroy_session {
@@ -422,6 +427,7 @@ struct nfsd4_op {
 
                /* NFSv4.1 */
                struct nfsd4_exchange_id        exchange_id;
+               struct nfsd4_bind_conn_to_session bind_conn_to_session;
                struct nfsd4_create_session     create_session;
                struct nfsd4_destroy_session    destroy_session;
                struct nfsd4_sequence           sequence;
@@ -518,6 +524,7 @@ extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
                struct nfsd4_sequence *seq);
 extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp,
                struct nfsd4_compound_state *, struct nfsd4_exchange_id *);
+extern __be32 nfsd4_bind_conn_to_session(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_bind_conn_to_session *);
 extern __be32 nfsd4_create_session(struct svc_rqst *,
                struct nfsd4_compound_state *,
                struct nfsd4_create_session *);
index 0dce969d6cad61840430a40f3972de64a48bfdb0..faca449970995ab41a8fc9117efeceac63cf1991 100644 (file)
@@ -98,6 +98,7 @@ xfs-y                         += $(addprefix $(XFS_LINUX)/, \
                                   kmem.o \
                                   xfs_aops.o \
                                   xfs_buf.o \
+                                  xfs_discard.o \
                                   xfs_export.o \
                                   xfs_file.o \
                                   xfs_fs_subr.o \
index 92f1f2acc6ab1db0ca894621ab86fcdd0e125d93..ac1c7e8378ddd0a63cd33c5dfbcecd2fcfe0e74d 100644 (file)
@@ -896,7 +896,6 @@ xfs_buf_rele(
        trace_xfs_buf_rele(bp, _RET_IP_);
 
        if (!pag) {
-               ASSERT(!bp->b_relse);
                ASSERT(list_empty(&bp->b_lru));
                ASSERT(RB_EMPTY_NODE(&bp->b_rbnode));
                if (atomic_dec_and_test(&bp->b_hold))
@@ -908,11 +907,7 @@ xfs_buf_rele(
 
        ASSERT(atomic_read(&bp->b_hold) > 0);
        if (atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock)) {
-               if (bp->b_relse) {
-                       atomic_inc(&bp->b_hold);
-                       spin_unlock(&pag->pag_buf_lock);
-                       bp->b_relse(bp);
-               } else if (!(bp->b_flags & XBF_STALE) &&
+               if (!(bp->b_flags & XBF_STALE) &&
                           atomic_read(&bp->b_lru_ref)) {
                        xfs_buf_lru_add(bp);
                        spin_unlock(&pag->pag_buf_lock);
index a76c2428faff877e73353959a07093f281e5ce87..cbe65950e5244bbf750482b0cf9f709032eeb1c0 100644 (file)
@@ -152,8 +152,6 @@ typedef struct xfs_buftarg {
 
 struct xfs_buf;
 typedef void (*xfs_buf_iodone_t)(struct xfs_buf *);
-typedef void (*xfs_buf_relse_t)(struct xfs_buf *);
-typedef int (*xfs_buf_bdstrat_t)(struct xfs_buf *);
 
 #define XB_PAGES       2
 
@@ -183,7 +181,6 @@ typedef struct xfs_buf {
        void                    *b_addr;        /* virtual address of buffer */
        struct work_struct      b_iodone_work;
        xfs_buf_iodone_t        b_iodone;       /* I/O completion function */
-       xfs_buf_relse_t         b_relse;        /* releasing function */
        struct completion       b_iowait;       /* queue for I/O waiters */
        void                    *b_fspriv;
        void                    *b_fspriv2;
@@ -323,7 +320,6 @@ void xfs_buf_stale(struct xfs_buf *bp);
 #define XFS_BUF_FSPRIVATE2(bp, type)           ((type)(bp)->b_fspriv2)
 #define XFS_BUF_SET_FSPRIVATE2(bp, val)                ((bp)->b_fspriv2 = (void*)(val))
 #define XFS_BUF_SET_START(bp)                  do { } while (0)
-#define XFS_BUF_SET_BRELSE_FUNC(bp, func)      ((bp)->b_relse = (func))
 
 #define XFS_BUF_PTR(bp)                        (xfs_caddr_t)((bp)->b_addr)
 #define XFS_BUF_SET_PTR(bp, val, cnt)  xfs_buf_associate_memory(bp, val, cnt)
@@ -360,8 +356,7 @@ xfs_buf_set_ref(
 
 static inline void xfs_buf_relse(xfs_buf_t *bp)
 {
-       if (!bp->b_relse)
-               xfs_buf_unlock(bp);
+       xfs_buf_unlock(bp);
        xfs_buf_rele(bp);
 }
 
diff --git a/fs/xfs/linux-2.6/xfs_discard.c b/fs/xfs/linux-2.6/xfs_discard.c
new file mode 100644 (file)
index 0000000..05201ae
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include "xfs.h"
+#include "xfs_sb.h"
+#include "xfs_inum.h"
+#include "xfs_log.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+#include "xfs_quota.h"
+#include "xfs_trans.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_btree.h"
+#include "xfs_inode.h"
+#include "xfs_alloc.h"
+#include "xfs_error.h"
+#include "xfs_discard.h"
+#include "xfs_trace.h"
+
+STATIC int
+xfs_trim_extents(
+       struct xfs_mount        *mp,
+       xfs_agnumber_t          agno,
+       xfs_fsblock_t           start,
+       xfs_fsblock_t           len,
+       xfs_fsblock_t           minlen,
+       __uint64_t              *blocks_trimmed)
+{
+       struct block_device     *bdev = mp->m_ddev_targp->bt_bdev;
+       struct xfs_btree_cur    *cur;
+       struct xfs_buf          *agbp;
+       struct xfs_perag        *pag;
+       int                     error;
+       int                     i;
+
+       pag = xfs_perag_get(mp, agno);
+
+       error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
+       if (error || !agbp)
+               goto out_put_perag;
+
+       cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT);
+
+       /*
+        * Force out the log.  This means any transactions that might have freed
+        * space before we took the AGF buffer lock are now on disk, and the
+        * volatile disk cache is flushed.
+        */
+       xfs_log_force(mp, XFS_LOG_SYNC);
+
+       /*
+        * Look up the longest btree in the AGF and start with it.
+        */
+       error = xfs_alloc_lookup_le(cur, 0,
+                                   XFS_BUF_TO_AGF(agbp)->agf_longest, &i);
+       if (error)
+               goto out_del_cursor;
+
+       /*
+        * Loop until we are done with all extents that are large
+        * enough to be worth discarding.
+        */
+       while (i) {
+               xfs_agblock_t fbno;
+               xfs_extlen_t flen;
+
+               error = xfs_alloc_get_rec(cur, &fbno, &flen, &i);
+               if (error)
+                       goto out_del_cursor;
+               XFS_WANT_CORRUPTED_GOTO(i == 1, out_del_cursor);
+               ASSERT(flen <= XFS_BUF_TO_AGF(agbp)->agf_longest);
+
+               /*
+                * Too small?  Give up.
+                */
+               if (flen < minlen) {
+                       trace_xfs_discard_toosmall(mp, agno, fbno, flen);
+                       goto out_del_cursor;
+               }
+
+               /*
+                * If the extent is entirely outside of the range we are
+                * supposed to discard skip it.  Do not bother to trim
+                * down partially overlapping ranges for now.
+                */
+               if (XFS_AGB_TO_FSB(mp, agno, fbno) + flen < start ||
+                   XFS_AGB_TO_FSB(mp, agno, fbno) >= start + len) {
+                       trace_xfs_discard_exclude(mp, agno, fbno, flen);
+                       goto next_extent;
+               }
+
+               /*
+                * If any blocks in the range are still busy, skip the
+                * discard and try again the next time.
+                */
+               if (xfs_alloc_busy_search(mp, agno, fbno, flen)) {
+                       trace_xfs_discard_busy(mp, agno, fbno, flen);
+                       goto next_extent;
+               }
+
+               trace_xfs_discard_extent(mp, agno, fbno, flen);
+               error = -blkdev_issue_discard(bdev,
+                               XFS_AGB_TO_DADDR(mp, agno, fbno),
+                               XFS_FSB_TO_BB(mp, flen),
+                               GFP_NOFS, 0);
+               if (error)
+                       goto out_del_cursor;
+               *blocks_trimmed += flen;
+
+next_extent:
+               error = xfs_btree_decrement(cur, 0, &i);
+               if (error)
+                       goto out_del_cursor;
+       }
+
+out_del_cursor:
+       xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+       xfs_buf_relse(agbp);
+out_put_perag:
+       xfs_perag_put(pag);
+       return error;
+}
+
+int
+xfs_ioc_trim(
+       struct xfs_mount                *mp,
+       struct fstrim_range __user      *urange)
+{
+       struct request_queue    *q = mp->m_ddev_targp->bt_bdev->bd_disk->queue;
+       unsigned int            granularity = q->limits.discard_granularity;
+       struct fstrim_range     range;
+       xfs_fsblock_t           start, len, minlen;
+       xfs_agnumber_t          start_agno, end_agno, agno;
+       __uint64_t              blocks_trimmed = 0;
+       int                     error, last_error = 0;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -XFS_ERROR(EPERM);
+       if (copy_from_user(&range, urange, sizeof(range)))
+               return -XFS_ERROR(EFAULT);
+
+       /*
+        * Truncating down the len isn't actually quite correct, but using
+        * XFS_B_TO_FSB would mean we trivially get overflows for values
+        * of ULLONG_MAX or slightly lower.  And ULLONG_MAX is the default
+        * used by the fstrim application.  In the end it really doesn't
+        * matter as trimming blocks is an advisory interface.
+        */
+       start = XFS_B_TO_FSBT(mp, range.start);
+       len = XFS_B_TO_FSBT(mp, range.len);
+       minlen = XFS_B_TO_FSB(mp, max_t(u64, granularity, range.minlen));
+
+       start_agno = XFS_FSB_TO_AGNO(mp, start);
+       if (start_agno >= mp->m_sb.sb_agcount)
+               return -XFS_ERROR(EINVAL);
+
+       end_agno = XFS_FSB_TO_AGNO(mp, start + len);
+       if (end_agno >= mp->m_sb.sb_agcount)
+               end_agno = mp->m_sb.sb_agcount - 1;
+
+       for (agno = start_agno; agno <= end_agno; agno++) {
+               error = -xfs_trim_extents(mp, agno, start, len, minlen,
+                                         &blocks_trimmed);
+               if (error)
+                       last_error = error;
+       }
+
+       if (last_error)
+               return last_error;
+
+       range.len = XFS_FSB_TO_B(mp, blocks_trimmed);
+       if (copy_to_user(urange, &range, sizeof(range)))
+               return -XFS_ERROR(EFAULT);
+       return 0;
+}
diff --git a/fs/xfs/linux-2.6/xfs_discard.h b/fs/xfs/linux-2.6/xfs_discard.h
new file mode 100644 (file)
index 0000000..e82b6dd
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef XFS_DISCARD_H
+#define XFS_DISCARD_H 1
+
+struct fstrim_range;
+
+extern int     xfs_ioc_trim(struct xfs_mount *, struct fstrim_range __user *);
+
+#endif /* XFS_DISCARD_H */
index ba8ad422a16506fdea605c7a215e572b3b3a8f6a..ef51eb43e1377469deb52a2a48813dd3073f2037 100644 (file)
 
 static const struct vm_operations_struct xfs_file_vm_ops;
 
+/*
+ * Locking primitives for read and write IO paths to ensure we consistently use
+ * and order the inode->i_mutex, ip->i_lock and ip->i_iolock.
+ */
+static inline void
+xfs_rw_ilock(
+       struct xfs_inode        *ip,
+       int                     type)
+{
+       if (type & XFS_IOLOCK_EXCL)
+               mutex_lock(&VFS_I(ip)->i_mutex);
+       xfs_ilock(ip, type);
+}
+
+static inline void
+xfs_rw_iunlock(
+       struct xfs_inode        *ip,
+       int                     type)
+{
+       xfs_iunlock(ip, type);
+       if (type & XFS_IOLOCK_EXCL)
+               mutex_unlock(&VFS_I(ip)->i_mutex);
+}
+
+static inline void
+xfs_rw_ilock_demote(
+       struct xfs_inode        *ip,
+       int                     type)
+{
+       xfs_ilock_demote(ip, type);
+       if (type & XFS_IOLOCK_EXCL)
+               mutex_unlock(&VFS_I(ip)->i_mutex);
+}
+
 /*
  *     xfs_iozero
  *
@@ -262,22 +296,21 @@ xfs_file_aio_read(
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
 
-       if (unlikely(ioflags & IO_ISDIRECT))
-               mutex_lock(&inode->i_mutex);
-       xfs_ilock(ip, XFS_IOLOCK_SHARED);
-
        if (unlikely(ioflags & IO_ISDIRECT)) {
+               xfs_rw_ilock(ip, XFS_IOLOCK_EXCL);
+
                if (inode->i_mapping->nrpages) {
                        ret = -xfs_flushinval_pages(ip,
                                        (iocb->ki_pos & PAGE_CACHE_MASK),
                                        -1, FI_REMAPF_LOCKED);
+                       if (ret) {
+                               xfs_rw_iunlock(ip, XFS_IOLOCK_EXCL);
+                               return ret;
+                       }
                }
-               mutex_unlock(&inode->i_mutex);
-               if (ret) {
-                       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-                       return ret;
-               }
-       }
+               xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL);
+       } else
+               xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
 
        trace_xfs_file_read(ip, size, iocb->ki_pos, ioflags);
 
@@ -285,7 +318,7 @@ xfs_file_aio_read(
        if (ret > 0)
                XFS_STATS_ADD(xs_read_bytes, ret);
 
-       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+       xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
        return ret;
 }
 
@@ -309,7 +342,7 @@ xfs_file_splice_read(
        if (XFS_FORCED_SHUTDOWN(ip->i_mount))
                return -EIO;
 
-       xfs_ilock(ip, XFS_IOLOCK_SHARED);
+       xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
 
        trace_xfs_file_splice_read(ip, count, *ppos, ioflags);
 
@@ -317,10 +350,61 @@ xfs_file_splice_read(
        if (ret > 0)
                XFS_STATS_ADD(xs_read_bytes, ret);
 
-       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+       xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
        return ret;
 }
 
+STATIC void
+xfs_aio_write_isize_update(
+       struct inode    *inode,
+       loff_t          *ppos,
+       ssize_t         bytes_written)
+{
+       struct xfs_inode        *ip = XFS_I(inode);
+       xfs_fsize_t             isize = i_size_read(inode);
+
+       if (bytes_written > 0)
+               XFS_STATS_ADD(xs_write_bytes, bytes_written);
+
+       if (unlikely(bytes_written < 0 && bytes_written != -EFAULT &&
+                                       *ppos > isize))
+               *ppos = isize;
+
+       if (*ppos > ip->i_size) {
+               xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
+               if (*ppos > ip->i_size)
+                       ip->i_size = *ppos;
+               xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
+       }
+}
+
+/*
+ * If this was a direct or synchronous I/O that failed (such as ENOSPC) then
+ * part of the I/O may have been written to disk before the error occured.  In
+ * this case the on-disk file size may have been adjusted beyond the in-memory
+ * file size and now needs to be truncated back.
+ */
+STATIC void
+xfs_aio_write_newsize_update(
+       struct xfs_inode        *ip)
+{
+       if (ip->i_new_size) {
+               xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
+               ip->i_new_size = 0;
+               if (ip->i_d.di_size > ip->i_size)
+                       ip->i_d.di_size = ip->i_size;
+               xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
+       }
+}
+
+/*
+ * xfs_file_splice_write() does not use xfs_rw_ilock() because
+ * generic_file_splice_write() takes the i_mutex itself. This, in theory,
+ * couuld cause lock inversions between the aio_write path and the splice path
+ * if someone is doing concurrent splice(2) based writes and write(2) based
+ * writes to the same inode. The only real way to fix this is to re-implement
+ * the generic code here with correct locking orders.
+ */
 STATIC ssize_t
 xfs_file_splice_write(
        struct pipe_inode_info  *pipe,
@@ -331,7 +415,7 @@ xfs_file_splice_write(
 {
        struct inode            *inode = outfilp->f_mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
-       xfs_fsize_t             isize, new_size;
+       xfs_fsize_t             new_size;
        int                     ioflags = 0;
        ssize_t                 ret;
 
@@ -355,27 +439,9 @@ xfs_file_splice_write(
        trace_xfs_file_splice_write(ip, count, *ppos, ioflags);
 
        ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags);
-       if (ret > 0)
-               XFS_STATS_ADD(xs_write_bytes, ret);
-
-       isize = i_size_read(inode);
-       if (unlikely(ret < 0 && ret != -EFAULT && *ppos > isize))
-               *ppos = isize;
 
-       if (*ppos > ip->i_size) {
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               if (*ppos > ip->i_size)
-                       ip->i_size = *ppos;
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       }
-
-       if (ip->i_new_size) {
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               ip->i_new_size = 0;
-               if (ip->i_d.di_size > ip->i_size)
-                       ip->i_d.di_size = ip->i_size;
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       }
+       xfs_aio_write_isize_update(inode, ppos, ret);
+       xfs_aio_write_newsize_update(ip);
        xfs_iunlock(ip, XFS_IOLOCK_EXCL);
        return ret;
 }
@@ -562,245 +628,258 @@ out_lock:
        return error;
 }
 
+/*
+ * Common pre-write limit and setup checks.
+ *
+ * Returns with iolock held according to @iolock.
+ */
 STATIC ssize_t
-xfs_file_aio_write(
-       struct kiocb            *iocb,
-       const struct iovec      *iovp,
-       unsigned long           nr_segs,
-       loff_t                  pos)
+xfs_file_aio_write_checks(
+       struct file             *file,
+       loff_t                  *pos,
+       size_t                  *count,
+       int                     *iolock)
 {
-       struct file             *file = iocb->ki_filp;
-       struct address_space    *mapping = file->f_mapping;
-       struct inode            *inode = mapping->host;
+       struct inode            *inode = file->f_mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
-       struct xfs_mount        *mp = ip->i_mount;
-       ssize_t                 ret = 0, error = 0;
-       int                     ioflags = 0;
-       xfs_fsize_t             isize, new_size;
-       int                     iolock;
-       size_t                  ocount = 0, count;
-       int                     need_i_mutex;
+       xfs_fsize_t             new_size;
+       int                     error = 0;
 
-       XFS_STATS_INC(xs_write_calls);
+       error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode));
+       if (error) {
+               xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock);
+               *iolock = 0;
+               return error;
+       }
 
-       BUG_ON(iocb->ki_pos != pos);
+       new_size = *pos + *count;
+       if (new_size > ip->i_size)
+               ip->i_new_size = new_size;
 
-       if (unlikely(file->f_flags & O_DIRECT))
-               ioflags |= IO_ISDIRECT;
-       if (file->f_mode & FMODE_NOCMTIME)
-               ioflags |= IO_INVIS;
+       if (likely(!(file->f_mode & FMODE_NOCMTIME)))
+               file_update_time(file);
 
-       error = generic_segment_checks(iovp, &nr_segs, &ocount, VERIFY_READ);
+       /*
+        * If the offset is beyond the size of the file, we need to zero any
+        * blocks that fall between the existing EOF and the start of this
+        * write.
+        */
+       if (*pos > ip->i_size)
+               error = -xfs_zero_eof(ip, *pos, ip->i_size);
+
+       xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
        if (error)
                return error;
 
-       count = ocount;
-       if (count == 0)
-               return 0;
-
-       xfs_wait_for_freeze(mp, SB_FREEZE_WRITE);
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return -EIO;
-
-relock:
-       if (ioflags & IO_ISDIRECT) {
-               iolock = XFS_IOLOCK_SHARED;
-               need_i_mutex = 0;
-       } else {
-               iolock = XFS_IOLOCK_EXCL;
-               need_i_mutex = 1;
-               mutex_lock(&inode->i_mutex);
-       }
+       /*
+        * If we're writing the file then make sure to clear the setuid and
+        * setgid bits if the process is not being run by root.  This keeps
+        * people from modifying setuid and setgid binaries.
+        */
+       return file_remove_suid(file);
 
-       xfs_ilock(ip, XFS_ILOCK_EXCL|iolock);
+}
 
-start:
-       error = -generic_write_checks(file, &pos, &count,
-                                       S_ISBLK(inode->i_mode));
-       if (error) {
-               xfs_iunlock(ip, XFS_ILOCK_EXCL|iolock);
-               goto out_unlock_mutex;
+/*
+ * xfs_file_dio_aio_write - handle direct IO writes
+ *
+ * Lock the inode appropriately to prepare for and issue a direct IO write.
+ * By separating it from the buffered write path we remove all the tricky to
+ * follow locking changes and looping.
+ *
+ * If there are cached pages or we're extending the file, we need IOLOCK_EXCL
+ * until we're sure the bytes at the new EOF have been zeroed and/or the cached
+ * pages are flushed out.
+ *
+ * In most cases the direct IO writes will be done holding IOLOCK_SHARED
+ * allowing them to be done in parallel with reads and other direct IO writes.
+ * However, if the IO is not aligned to filesystem blocks, the direct IO layer
+ * needs to do sub-block zeroing and that requires serialisation against other
+ * direct IOs to the same block. In this case we need to serialise the
+ * submission of the unaligned IOs so that we don't get racing block zeroing in
+ * the dio layer.  To avoid the problem with aio, we also need to wait for
+ * outstanding IOs to complete so that unwritten extent conversion is completed
+ * before we try to map the overlapping block. This is currently implemented by
+ * hitting it with a big hammer (i.e. xfs_ioend_wait()).
+ *
+ * Returns with locks held indicated by @iolock and errors indicated by
+ * negative return values.
+ */
+STATIC ssize_t
+xfs_file_dio_aio_write(
+       struct kiocb            *iocb,
+       const struct iovec      *iovp,
+       unsigned long           nr_segs,
+       loff_t                  pos,
+       size_t                  ocount,
+       int                     *iolock)
+{
+       struct file             *file = iocb->ki_filp;
+       struct address_space    *mapping = file->f_mapping;
+       struct inode            *inode = mapping->host;
+       struct xfs_inode        *ip = XFS_I(inode);
+       struct xfs_mount        *mp = ip->i_mount;
+       ssize_t                 ret = 0;
+       size_t                  count = ocount;
+       int                     unaligned_io = 0;
+       struct xfs_buftarg      *target = XFS_IS_REALTIME_INODE(ip) ?
+                                       mp->m_rtdev_targp : mp->m_ddev_targp;
+
+       *iolock = 0;
+       if ((pos & target->bt_smask) || (count & target->bt_smask))
+               return -XFS_ERROR(EINVAL);
+
+       if ((pos & mp->m_blockmask) || ((pos + count) & mp->m_blockmask))
+               unaligned_io = 1;
+
+       if (unaligned_io || mapping->nrpages || pos > ip->i_size)
+               *iolock = XFS_IOLOCK_EXCL;
+       else
+               *iolock = XFS_IOLOCK_SHARED;
+       xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock);
+
+       ret = xfs_file_aio_write_checks(file, &pos, &count, iolock);
+       if (ret)
+               return ret;
+
+       if (mapping->nrpages) {
+               WARN_ON(*iolock != XFS_IOLOCK_EXCL);
+               ret = -xfs_flushinval_pages(ip, (pos & PAGE_CACHE_MASK), -1,
+                                                       FI_REMAPF_LOCKED);
+               if (ret)
+                       return ret;
        }
 
-       if (ioflags & IO_ISDIRECT) {
-               xfs_buftarg_t   *target =
-                       XFS_IS_REALTIME_INODE(ip) ?
-                               mp->m_rtdev_targp : mp->m_ddev_targp;
-
-               if ((pos & target->bt_smask) || (count & target->bt_smask)) {
-                       xfs_iunlock(ip, XFS_ILOCK_EXCL|iolock);
-                       return XFS_ERROR(-EINVAL);
-               }
-
-               if (!need_i_mutex && (mapping->nrpages || pos > ip->i_size)) {
-                       xfs_iunlock(ip, XFS_ILOCK_EXCL|iolock);
-                       iolock = XFS_IOLOCK_EXCL;
-                       need_i_mutex = 1;
-                       mutex_lock(&inode->i_mutex);
-                       xfs_ilock(ip, XFS_ILOCK_EXCL|iolock);
-                       goto start;
-               }
+       /*
+        * If we are doing unaligned IO, wait for all other IO to drain,
+        * otherwise demote the lock if we had to flush cached pages
+        */
+       if (unaligned_io)
+               xfs_ioend_wait(ip);
+       else if (*iolock == XFS_IOLOCK_EXCL) {
+               xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL);
+               *iolock = XFS_IOLOCK_SHARED;
        }
 
-       new_size = pos + count;
-       if (new_size > ip->i_size)
-               ip->i_new_size = new_size;
+       trace_xfs_file_direct_write(ip, count, iocb->ki_pos, 0);
+       ret = generic_file_direct_write(iocb, iovp,
+                       &nr_segs, pos, &iocb->ki_pos, count, ocount);
 
-       if (likely(!(ioflags & IO_INVIS)))
-               file_update_time(file);
+       /* No fallback to buffered IO on errors for XFS. */
+       ASSERT(ret < 0 || ret == count);
+       return ret;
+}
 
-       /*
-        * If the offset is beyond the size of the file, we have a couple
-        * of things to do. First, if there is already space allocated
-        * we need to either create holes or zero the disk or ...
-        *
-        * If there is a page where the previous size lands, we need
-        * to zero it out up to the new size.
-        */
+STATIC ssize_t
+xfs_file_buffered_aio_write(
+       struct kiocb            *iocb,
+       const struct iovec      *iovp,
+       unsigned long           nr_segs,
+       loff_t                  pos,
+       size_t                  ocount,
+       int                     *iolock)
+{
+       struct file             *file = iocb->ki_filp;
+       struct address_space    *mapping = file->f_mapping;
+       struct inode            *inode = mapping->host;
+       struct xfs_inode        *ip = XFS_I(inode);
+       ssize_t                 ret;
+       int                     enospc = 0;
+       size_t                  count = ocount;
 
-       if (pos > ip->i_size) {
-               error = xfs_zero_eof(ip, pos, ip->i_size);
-               if (error) {
-                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-                       goto out_unlock_internal;
-               }
-       }
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+       *iolock = XFS_IOLOCK_EXCL;
+       xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock);
 
-       /*
-        * If we're writing the file then make sure to clear the
-        * setuid and setgid bits if the process is not being run
-        * by root.  This keeps people from modifying setuid and
-        * setgid binaries.
-        */
-       error = -file_remove_suid(file);
-       if (unlikely(error))
-               goto out_unlock_internal;
+       ret = xfs_file_aio_write_checks(file, &pos, &count, iolock);
+       if (ret)
+               return ret;
 
        /* We can write back this queue in page reclaim */
        current->backing_dev_info = mapping->backing_dev_info;
 
-       if ((ioflags & IO_ISDIRECT)) {
-               if (mapping->nrpages) {
-                       WARN_ON(need_i_mutex == 0);
-                       error = xfs_flushinval_pages(ip,
-                                       (pos & PAGE_CACHE_MASK),
-                                       -1, FI_REMAPF_LOCKED);
-                       if (error)
-                               goto out_unlock_internal;
-               }
-
-               if (need_i_mutex) {
-                       /* demote the lock now the cached pages are gone */
-                       xfs_ilock_demote(ip, XFS_IOLOCK_EXCL);
-                       mutex_unlock(&inode->i_mutex);
+write_retry:
+       trace_xfs_file_buffered_write(ip, count, iocb->ki_pos, 0);
+       ret = generic_file_buffered_write(iocb, iovp, nr_segs,
+                       pos, &iocb->ki_pos, count, ret);
+       /*
+        * if we just got an ENOSPC, flush the inode now we aren't holding any
+        * page locks and retry *once*
+        */
+       if (ret == -ENOSPC && !enospc) {
+               ret = -xfs_flush_pages(ip, 0, -1, 0, FI_NONE);
+               if (ret)
+                       return ret;
+               enospc = 1;
+               goto write_retry;
+       }
+       current->backing_dev_info = NULL;
+       return ret;
+}
 
-                       iolock = XFS_IOLOCK_SHARED;
-                       need_i_mutex = 0;
-               }
+STATIC ssize_t
+xfs_file_aio_write(
+       struct kiocb            *iocb,
+       const struct iovec      *iovp,
+       unsigned long           nr_segs,
+       loff_t                  pos)
+{
+       struct file             *file = iocb->ki_filp;
+       struct address_space    *mapping = file->f_mapping;
+       struct inode            *inode = mapping->host;
+       struct xfs_inode        *ip = XFS_I(inode);
+       ssize_t                 ret;
+       int                     iolock;
+       size_t                  ocount = 0;
 
-               trace_xfs_file_direct_write(ip, count, iocb->ki_pos, ioflags);
-               ret = generic_file_direct_write(iocb, iovp,
-                               &nr_segs, pos, &iocb->ki_pos, count, ocount);
+       XFS_STATS_INC(xs_write_calls);
 
-               /*
-                * direct-io write to a hole: fall through to buffered I/O
-                * for completing the rest of the request.
-                */
-               if (ret >= 0 && ret != count) {
-                       XFS_STATS_ADD(xs_write_bytes, ret);
+       BUG_ON(iocb->ki_pos != pos);
 
-                       pos += ret;
-                       count -= ret;
+       ret = generic_segment_checks(iovp, &nr_segs, &ocount, VERIFY_READ);
+       if (ret)
+               return ret;
 
-                       ioflags &= ~IO_ISDIRECT;
-                       xfs_iunlock(ip, iolock);
-                       goto relock;
-               }
-       } else {
-               int enospc = 0;
-               ssize_t ret2 = 0;
+       if (ocount == 0)
+               return 0;
 
-write_retry:
-               trace_xfs_file_buffered_write(ip, count, iocb->ki_pos, ioflags);
-               ret2 = generic_file_buffered_write(iocb, iovp, nr_segs,
-                               pos, &iocb->ki_pos, count, ret);
-               /*
-                * if we just got an ENOSPC, flush the inode now we
-                * aren't holding any page locks and retry *once*
-                */
-               if (ret2 == -ENOSPC && !enospc) {
-                       error = xfs_flush_pages(ip, 0, -1, 0, FI_NONE);
-                       if (error)
-                               goto out_unlock_internal;
-                       enospc = 1;
-                       goto write_retry;
-               }
-               ret = ret2;
-       }
+       xfs_wait_for_freeze(ip->i_mount, SB_FREEZE_WRITE);
 
-       current->backing_dev_info = NULL;
+       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+               return -EIO;
 
-       isize = i_size_read(inode);
-       if (unlikely(ret < 0 && ret != -EFAULT && iocb->ki_pos > isize))
-               iocb->ki_pos = isize;
+       if (unlikely(file->f_flags & O_DIRECT))
+               ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos,
+                                               ocount, &iolock);
+       else
+               ret = xfs_file_buffered_aio_write(iocb, iovp, nr_segs, pos,
+                                               ocount, &iolock);
 
-       if (iocb->ki_pos > ip->i_size) {
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               if (iocb->ki_pos > ip->i_size)
-                       ip->i_size = iocb->ki_pos;
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       }
+       xfs_aio_write_isize_update(inode, &iocb->ki_pos, ret);
 
-       error = -ret;
        if (ret <= 0)
-               goto out_unlock_internal;
-
-       XFS_STATS_ADD(xs_write_bytes, ret);
+               goto out_unlock;
 
        /* Handle various SYNC-type writes */
        if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
                loff_t end = pos + ret - 1;
-               int error2;
-
-               xfs_iunlock(ip, iolock);
-               if (need_i_mutex)
-                       mutex_unlock(&inode->i_mutex);
+               int error, error2;
 
-               error2 = filemap_write_and_wait_range(mapping, pos, end);
-               if (!error)
-                       error = error2;
-               if (need_i_mutex)
-                       mutex_lock(&inode->i_mutex);
-               xfs_ilock(ip, iolock);
+               xfs_rw_iunlock(ip, iolock);
+               error = filemap_write_and_wait_range(mapping, pos, end);
+               xfs_rw_ilock(ip, iolock);
 
                error2 = -xfs_file_fsync(file,
                                         (file->f_flags & __O_SYNC) ? 0 : 1);
-               if (!error)
-                       error = error2;
+               if (error)
+                       ret = error;
+               else if (error2)
+                       ret = error2;
        }
 
- out_unlock_internal:
-       if (ip->i_new_size) {
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               ip->i_new_size = 0;
-               /*
-                * If this was a direct or synchronous I/O that failed (such
-                * as ENOSPC) then part of the I/O may have been written to
-                * disk before the error occured.  In this case the on-disk
-                * file size may have been adjusted beyond the in-memory file
-                * size and now needs to be truncated back.
-                */
-               if (ip->i_d.di_size > ip->i_size)
-                       ip->i_d.di_size = ip->i_size;
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       }
-       xfs_iunlock(ip, iolock);
- out_unlock_mutex:
-       if (need_i_mutex)
-               mutex_unlock(&inode->i_mutex);
-       return -error;
+out_unlock:
+       xfs_aio_write_newsize_update(ip);
+       xfs_rw_iunlock(ip, iolock);
+       return ret;
 }
 
 STATIC int
index ad442d9e392e480ab242f5d13922ee3ec0feab2e..b06ede1d0bed4562e60e4067e729b9209de65e1d 100644 (file)
@@ -39,6 +39,7 @@
 #include "xfs_dfrag.h"
 #include "xfs_fsops.h"
 #include "xfs_vnodeops.h"
+#include "xfs_discard.h"
 #include "xfs_quota.h"
 #include "xfs_inode_item.h"
 #include "xfs_export.h"
@@ -1294,6 +1295,8 @@ xfs_file_ioctl(
        trace_xfs_file_ioctl(ip);
 
        switch (cmd) {
+       case FITRIM:
+               return xfs_ioc_trim(mp, arg);
        case XFS_IOC_ALLOCSP:
        case XFS_IOC_FREESP:
        case XFS_IOC_RESVSP:
index bd07f73393663bbe94909dbdeedabd987955d32e..9731898083ae86ee79f546f372684ab5d03dbcc8 100644 (file)
@@ -1414,7 +1414,7 @@ xfs_fs_freeze(
 
        xfs_save_resvblks(mp);
        xfs_quiesce_attr(mp);
-       return -xfs_fs_log_dummy(mp, SYNC_WAIT);
+       return -xfs_fs_log_dummy(mp);
 }
 
 STATIC int
index a02480de97599936e21389dae8e6e98a51883740..e22f0057d21fa8d2d3e04c11a2e62438ac17a3e9 100644 (file)
@@ -362,7 +362,7 @@ xfs_quiesce_data(
 
        /* mark the log as covered if needed */
        if (xfs_log_need_covered(mp))
-               error2 = xfs_fs_log_dummy(mp, SYNC_WAIT);
+               error2 = xfs_fs_log_dummy(mp);
 
        /* flush data-only devices */
        if (mp->m_rtdev_targp)
@@ -503,13 +503,14 @@ xfs_sync_worker(
        int             error;
 
        if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
-               xfs_log_force(mp, 0);
-               xfs_reclaim_inodes(mp, 0);
                /* dgc: errors ignored here */
-               error = xfs_qm_sync(mp, SYNC_TRYLOCK);
                if (mp->m_super->s_frozen == SB_UNFROZEN &&
                    xfs_log_need_covered(mp))
-                       error = xfs_fs_log_dummy(mp, 0);
+                       error = xfs_fs_log_dummy(mp);
+               else
+                       xfs_log_force(mp, 0);
+               xfs_reclaim_inodes(mp, 0);
+               error = xfs_qm_sync(mp, SYNC_TRYLOCK);
        }
        mp->m_sync_seq++;
        wake_up(&mp->m_wait_single_sync_task);
index 7bb5092d6ae40796f5669eee25db1a1e04841dc5..ee3cee097e7eba33b7139987b6c201ef44c82f64 100644 (file)
@@ -18,6 +18,7 @@
 #include "xfs.h"
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
+#include "xfs_error.h"
 
 static struct ctl_table_header *xfs_table_header;
 
@@ -51,6 +52,26 @@ xfs_stats_clear_proc_handler(
 
        return ret;
 }
+
+STATIC int
+xfs_panic_mask_proc_handler(
+       ctl_table       *ctl,
+       int             write,
+       void            __user *buffer,
+       size_t          *lenp,
+       loff_t          *ppos)
+{
+       int             ret, *valp = ctl->data;
+
+       ret = proc_dointvec_minmax(ctl, write, buffer, lenp, ppos);
+       if (!ret && write) {
+               xfs_panic_mask = *valp;
+#ifdef DEBUG
+               xfs_panic_mask |= (XFS_PTAG_SHUTDOWN_CORRUPT | XFS_PTAG_LOGRES);
+#endif
+       }
+       return ret;
+}
 #endif /* CONFIG_PROC_FS */
 
 static ctl_table xfs_table[] = {
@@ -77,7 +98,7 @@ static ctl_table xfs_table[] = {
                .data           = &xfs_params.panic_mask.val,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
+               .proc_handler   = xfs_panic_mask_proc_handler,
                .extra1         = &xfs_params.panic_mask.min,
                .extra2         = &xfs_params.panic_mask.max
        },
index 647af2a2e7aa8af2d14910e32beecfc00dbab515..2d0bcb479075fac542b176bbfb5a38ebc757a5dd 100644 (file)
@@ -1759,6 +1759,39 @@ DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_recover);
 DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_cancel);
 DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_skip);
 
+DECLARE_EVENT_CLASS(xfs_discard_class,
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
+                xfs_agblock_t agbno, xfs_extlen_t len),
+       TP_ARGS(mp, agno, agbno, len),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_agnumber_t, agno)
+               __field(xfs_agblock_t, agbno)
+               __field(xfs_extlen_t, len)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp->m_super->s_dev;
+               __entry->agno = agno;
+               __entry->agbno = agbno;
+               __entry->len = len;
+       ),
+       TP_printk("dev %d:%d agno %u agbno %u len %u\n",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->agno,
+                 __entry->agbno,
+                 __entry->len)
+)
+
+#define DEFINE_DISCARD_EVENT(name) \
+DEFINE_EVENT(xfs_discard_class, name, \
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \
+                xfs_agblock_t agbno, xfs_extlen_t len), \
+       TP_ARGS(mp, agno, agbno, len))
+DEFINE_DISCARD_EVENT(xfs_discard_extent);
+DEFINE_DISCARD_EVENT(xfs_discard_toosmall);
+DEFINE_DISCARD_EVENT(xfs_discard_exclude);
+DEFINE_DISCARD_EVENT(xfs_discard_busy);
+
 #endif /* _TRACE_XFS_H */
 
 #undef TRACE_INCLUDE_PATH
index 975aa10e1a47a3536499b035947ed0c5ac5098a5..e6cf955ec0fca16f714812e9edef6c6c150a7762 100644 (file)
 #include "xfs_mount.h"
 #include "xfs_error.h"
 
-static char            message[1024];  /* keep it off the stack */
-static DEFINE_SPINLOCK(xfs_err_lock);
-
-/* Translate from CE_FOO to KERN_FOO, err_level(CE_FOO) == KERN_FOO */
-#define XFS_MAX_ERR_LEVEL      7
-#define XFS_ERR_MASK           ((1 << 3) - 1)
-static const char * const      err_level[XFS_MAX_ERR_LEVEL+1] =
-                                       {KERN_EMERG, KERN_ALERT, KERN_CRIT,
-                                        KERN_ERR, KERN_WARNING, KERN_NOTICE,
-                                        KERN_INFO, KERN_DEBUG};
-
 void
-cmn_err(register int level, char *fmt, ...)
+cmn_err(
+       const char      *lvl,
+       const char      *fmt,
+       ...)
 {
-       char    *fp = fmt;
-       int     len;
-       ulong   flags;
-       va_list ap;
-
-       level &= XFS_ERR_MASK;
-       if (level > XFS_MAX_ERR_LEVEL)
-               level = XFS_MAX_ERR_LEVEL;
-       spin_lock_irqsave(&xfs_err_lock,flags);
-       va_start(ap, fmt);
-       if (*fmt == '!') fp++;
-       len = vsnprintf(message, sizeof(message), fp, ap);
-       if (len >= sizeof(message))
-               len = sizeof(message) - 1;
-       if (message[len-1] == '\n')
-               message[len-1] = 0;
-       printk("%s%s\n", err_level[level], message);
-       va_end(ap);
-       spin_unlock_irqrestore(&xfs_err_lock,flags);
-       BUG_ON(level == CE_PANIC);
+       struct va_format vaf;
+       va_list         args;
+
+       va_start(args, fmt);
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       printk("%s%pV", lvl, &vaf);
+       va_end(args);
+
+       BUG_ON(strncmp(lvl, KERN_EMERG, strlen(KERN_EMERG)) == 0);
 }
 
 void
-xfs_fs_vcmn_err(
-       int                     level,
+xfs_fs_cmn_err(
+       const char              *lvl,
        struct xfs_mount        *mp,
-       char                    *fmt,
-       va_list                 ap)
+       const char              *fmt,
+       ...)
 {
-       unsigned long           flags;
-       int                     len = 0;
+       struct va_format        vaf;
+       va_list                 args;
 
-       level &= XFS_ERR_MASK;
-       if (level > XFS_MAX_ERR_LEVEL)
-               level = XFS_MAX_ERR_LEVEL;
+       va_start(args, fmt);
+       vaf.fmt = fmt;
+       vaf.va = &args;
 
-       spin_lock_irqsave(&xfs_err_lock,flags);
+       printk("%sFilesystem %s: %pV", lvl, mp->m_fsname, &vaf);
+       va_end(args);
 
-       if (mp) {
-               len = sprintf(message, "Filesystem \"%s\": ", mp->m_fsname);
+       BUG_ON(strncmp(lvl, KERN_EMERG, strlen(KERN_EMERG)) == 0);
+}
+
+/* All callers to xfs_cmn_err use CE_ALERT, so don't bother testing lvl */
+void
+xfs_cmn_err(
+       int                     panic_tag,
+       const char              *lvl,
+       struct xfs_mount        *mp,
+       const char              *fmt,
+       ...)
+{
+       struct va_format        vaf;
+       va_list                 args;
+       int                     panic = 0;
 
-               /*
-                * Skip the printk if we can't print anything useful
-                * due to an over-long device name.
-                */
-               if (len >= sizeof(message))
-                       goto out;
+       if (xfs_panic_mask && (xfs_panic_mask & panic_tag)) {
+               printk(KERN_ALERT "XFS: Transforming an alert into a BUG.");
+               panic = 1;
        }
 
-       len = vsnprintf(message + len, sizeof(message) - len, fmt, ap);
-       if (len >= sizeof(message))
-               len = sizeof(message) - 1;
-       if (message[len-1] == '\n')
-               message[len-1] = 0;
+       va_start(args, fmt);
+       vaf.fmt = fmt;
+       vaf.va = &args;
 
-       printk("%s%s\n", err_level[level], message);
- out:
-       spin_unlock_irqrestore(&xfs_err_lock,flags);
+       printk(KERN_ALERT "Filesystem %s: %pV", mp->m_fsname, &vaf);
+       va_end(args);
 
-       BUG_ON(level == CE_PANIC);
+       BUG_ON(panic);
 }
 
 void
 assfail(char *expr, char *file, int line)
 {
-       printk("Assertion failed: %s, file: %s, line: %d\n", expr, file, line);
+       printk(KERN_CRIT "Assertion failed: %s, file: %s, line: %d\n", expr,
+              file, line);
        BUG();
 }
 
index d2d20462fd4fd823b850f61918e3e2e28fd53655..05699f67d47521f9eb3c78a8007b6fcc0ad16473 100644 (file)
 
 #include <stdarg.h>
 
-#define CE_DEBUG        7               /* debug        */
-#define CE_CONT         6               /* continuation */
-#define CE_NOTE         5               /* notice       */
-#define CE_WARN         4               /* warning      */
-#define CE_ALERT        1               /* alert        */
-#define CE_PANIC        0               /* panic        */
-
-extern void cmn_err(int, char *, ...)
-       __attribute__ ((format (printf, 2, 3)));
+struct xfs_mount;
+
+#define CE_DEBUG        KERN_DEBUG
+#define CE_CONT         KERN_INFO
+#define CE_NOTE         KERN_NOTICE
+#define CE_WARN         KERN_WARNING
+#define CE_ALERT        KERN_ALERT
+#define CE_PANIC        KERN_EMERG
+
+void cmn_err(const char *lvl, const char *fmt, ...)
+               __attribute__ ((format (printf, 2, 3)));
+void xfs_fs_cmn_err( const char *lvl, struct xfs_mount *mp,
+               const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
+void xfs_cmn_err( int panic_tag, const char *lvl, struct xfs_mount *mp,
+               const char *fmt, ...) __attribute__ ((format (printf, 4, 5)));
+
 extern void assfail(char *expr, char *f, int l);
 
 #define ASSERT_ALWAYS(expr)    \
index fa8723f5870a113358b3bcd67214eba281b50b1f..f3227984a9bf815d554034ec4661bdcc37d6db36 100644 (file)
 #define        XFSA_FIXUP_BNO_OK       1
 #define        XFSA_FIXUP_CNT_OK       2
 
-static int
-xfs_alloc_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno,
-                   xfs_agblock_t bno, xfs_extlen_t len);
-
 /*
  * Prototypes for per-ag allocation routines
  */
@@ -94,7 +90,7 @@ xfs_alloc_lookup_ge(
  * Lookup the first record less than or equal to [bno, len]
  * in the btree given by cur.
  */
-STATIC int                             /* error */
+int                                    /* error */
 xfs_alloc_lookup_le(
        struct xfs_btree_cur    *cur,   /* btree cursor */
        xfs_agblock_t           bno,    /* starting block of extent */
@@ -127,7 +123,7 @@ xfs_alloc_update(
 /*
  * Get the data from the pointed-to record.
  */
-STATIC int                             /* error */
+int                                    /* error */
 xfs_alloc_get_rec(
        struct xfs_btree_cur    *cur,   /* btree cursor */
        xfs_agblock_t           *bno,   /* output: starting block of extent */
@@ -2615,7 +2611,7 @@ restart:
  * will require a synchronous transaction, but it can still be
  * used to distinguish between a partial or exact match.
  */
-static int
+int
 xfs_alloc_busy_search(
        struct xfs_mount        *mp,
        xfs_agnumber_t          agno,
index 895009a97271fbbd27fcb63b97b9546f375a8778..0ab56b32c7eb70484ed4a7fdcfdbac3595c1ecab 100644 (file)
@@ -19,6 +19,7 @@
 #define        __XFS_ALLOC_H__
 
 struct xfs_buf;
+struct xfs_btree_cur;
 struct xfs_mount;
 struct xfs_perag;
 struct xfs_trans;
@@ -118,16 +119,16 @@ xfs_alloc_longest_free_extent(struct xfs_mount *mp,
                struct xfs_perag *pag);
 
 #ifdef __KERNEL__
-
 void
-xfs_alloc_busy_insert(xfs_trans_t *tp,
-               xfs_agnumber_t agno,
-               xfs_agblock_t bno,
-               xfs_extlen_t len);
+xfs_alloc_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno,
+       xfs_agblock_t bno, xfs_extlen_t len);
 
 void
 xfs_alloc_busy_clear(struct xfs_mount *mp, struct xfs_busy_extent *busyp);
 
+int
+xfs_alloc_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno,
+       xfs_agblock_t bno, xfs_extlen_t len);
 #endif /* __KERNEL__ */
 
 /*
@@ -205,4 +206,18 @@ xfs_free_extent(
        xfs_fsblock_t   bno,    /* starting block number of extent */
        xfs_extlen_t    len);   /* length of extent */
 
+int                                    /* error */
+xfs_alloc_lookup_le(
+       struct xfs_btree_cur    *cur,   /* btree cursor */
+       xfs_agblock_t           bno,    /* starting block of extent */
+       xfs_extlen_t            len,    /* length of extent */
+       int                     *stat); /* success/failure */
+
+int                                    /* error */
+xfs_alloc_get_rec(
+       struct xfs_btree_cur    *cur,   /* btree cursor */
+       xfs_agblock_t           *bno,   /* output: starting block of extent */
+       xfs_extlen_t            *len,   /* output: length of extent */
+       int                     *stat); /* output: success/failure */
+
 #endif /* __XFS_ALLOC_H__ */
index ed2b65f3f8b9945f6fffd07c359ddda6654ea712..98c6f73b675218bded1a6b326ecdf349cb241a07 100644 (file)
@@ -141,7 +141,6 @@ xfs_buf_item_log_check(
 #define                xfs_buf_item_log_check(x)
 #endif
 
-STATIC void    xfs_buf_error_relse(xfs_buf_t *bp);
 STATIC void    xfs_buf_do_callbacks(struct xfs_buf *bp);
 
 /*
@@ -959,128 +958,76 @@ xfs_buf_do_callbacks(
  */
 void
 xfs_buf_iodone_callbacks(
-       xfs_buf_t       *bp)
+       struct xfs_buf          *bp)
 {
-       xfs_log_item_t  *lip;
-       static ulong    lasttime;
-       static xfs_buftarg_t *lasttarg;
-       xfs_mount_t     *mp;
+       struct xfs_log_item     *lip = bp->b_fspriv;
+       struct xfs_mount        *mp = lip->li_mountp;
+       static ulong            lasttime;
+       static xfs_buftarg_t    *lasttarg;
 
-       ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
-       lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
+       if (likely(!XFS_BUF_GETERROR(bp)))
+               goto do_callbacks;
 
-       if (XFS_BUF_GETERROR(bp) != 0) {
-               /*
-                * If we've already decided to shutdown the filesystem
-                * because of IO errors, there's no point in giving this
-                * a retry.
-                */
-               mp = lip->li_mountp;
-               if (XFS_FORCED_SHUTDOWN(mp)) {
-                       ASSERT(XFS_BUF_TARGET(bp) == mp->m_ddev_targp);
-                       XFS_BUF_SUPER_STALE(bp);
-                       trace_xfs_buf_item_iodone(bp, _RET_IP_);
-                       xfs_buf_do_callbacks(bp);
-                       XFS_BUF_SET_FSPRIVATE(bp, NULL);
-                       XFS_BUF_CLR_IODONE_FUNC(bp);
-                       xfs_buf_ioend(bp, 0);
-                       return;
-               }
+       /*
+        * If we've already decided to shutdown the filesystem because of
+        * I/O errors, there's no point in giving this a retry.
+        */
+       if (XFS_FORCED_SHUTDOWN(mp)) {
+               XFS_BUF_SUPER_STALE(bp);
+               trace_xfs_buf_item_iodone(bp, _RET_IP_);
+               goto do_callbacks;
+       }
 
-               if ((XFS_BUF_TARGET(bp) != lasttarg) ||
-                   (time_after(jiffies, (lasttime + 5*HZ)))) {
-                       lasttime = jiffies;
-                       cmn_err(CE_ALERT, "Device %s, XFS metadata write error"
-                                       " block 0x%llx in %s",
-                               XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)),
-                             (__uint64_t)XFS_BUF_ADDR(bp), mp->m_fsname);
-               }
-               lasttarg = XFS_BUF_TARGET(bp);
+       if (XFS_BUF_TARGET(bp) != lasttarg ||
+           time_after(jiffies, (lasttime + 5*HZ))) {
+               lasttime = jiffies;
+               cmn_err(CE_ALERT, "Device %s, XFS metadata write error"
+                               " block 0x%llx in %s",
+                       XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)),
+                     (__uint64_t)XFS_BUF_ADDR(bp), mp->m_fsname);
+       }
+       lasttarg = XFS_BUF_TARGET(bp);
 
-               if (XFS_BUF_ISASYNC(bp)) {
-                       /*
-                        * If the write was asynchronous then noone will be
-                        * looking for the error.  Clear the error state
-                        * and write the buffer out again delayed write.
-                        *
-                        * XXXsup This is OK, so long as we catch these
-                        * before we start the umount; we don't want these
-                        * DELWRI metadata bufs to be hanging around.
-                        */
-                       XFS_BUF_ERROR(bp,0); /* errno of 0 unsets the flag */
-
-                       if (!(XFS_BUF_ISSTALE(bp))) {
-                               XFS_BUF_DELAYWRITE(bp);
-                               XFS_BUF_DONE(bp);
-                               XFS_BUF_SET_START(bp);
-                       }
-                       ASSERT(XFS_BUF_IODONE_FUNC(bp));
-                       trace_xfs_buf_item_iodone_async(bp, _RET_IP_);
-                       xfs_buf_relse(bp);
-               } else {
-                       /*
-                        * If the write of the buffer was not asynchronous,
-                        * then we want to make sure to return the error
-                        * to the caller of bwrite().  Because of this we
-                        * cannot clear the B_ERROR state at this point.
-                        * Instead we install a callback function that
-                        * will be called when the buffer is released, and
-                        * that routine will clear the error state and
-                        * set the buffer to be written out again after
-                        * some delay.
-                        */
-                       /* We actually overwrite the existing b-relse
-                          function at times, but we're gonna be shutting down
-                          anyway. */
-                       XFS_BUF_SET_BRELSE_FUNC(bp,xfs_buf_error_relse);
+       /*
+        * If the write was asynchronous then noone will be looking for the
+        * error.  Clear the error state and write the buffer out again.
+        *
+        * During sync or umount we'll write all pending buffers again
+        * synchronous, which will catch these errors if they keep hanging
+        * around.
+        */
+       if (XFS_BUF_ISASYNC(bp)) {
+               XFS_BUF_ERROR(bp, 0); /* errno of 0 unsets the flag */
+
+               if (!XFS_BUF_ISSTALE(bp)) {
+                       XFS_BUF_DELAYWRITE(bp);
                        XFS_BUF_DONE(bp);
-                       XFS_BUF_FINISH_IOWAIT(bp);
+                       XFS_BUF_SET_START(bp);
                }
+               ASSERT(XFS_BUF_IODONE_FUNC(bp));
+               trace_xfs_buf_item_iodone_async(bp, _RET_IP_);
+               xfs_buf_relse(bp);
                return;
        }
 
-       xfs_buf_do_callbacks(bp);
-       XFS_BUF_SET_FSPRIVATE(bp, NULL);
-       XFS_BUF_CLR_IODONE_FUNC(bp);
-       xfs_buf_ioend(bp, 0);
-}
-
-/*
- * This is a callback routine attached to a buffer which gets an error
- * when being written out synchronously.
- */
-STATIC void
-xfs_buf_error_relse(
-       xfs_buf_t       *bp)
-{
-       xfs_log_item_t  *lip;
-       xfs_mount_t     *mp;
-
-       lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
-       mp = (xfs_mount_t *)lip->li_mountp;
-       ASSERT(XFS_BUF_TARGET(bp) == mp->m_ddev_targp);
-
+       /*
+        * If the write of the buffer was synchronous, we want to make
+        * sure to return the error to the caller of xfs_bwrite().
+        */
        XFS_BUF_STALE(bp);
        XFS_BUF_DONE(bp);
        XFS_BUF_UNDELAYWRITE(bp);
-       XFS_BUF_ERROR(bp,0);
 
        trace_xfs_buf_error_relse(bp, _RET_IP_);
+       xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
 
-       if (! XFS_FORCED_SHUTDOWN(mp))
-               xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
-       /*
-        * We have to unpin the pinned buffers so do the
-        * callbacks.
-        */
+do_callbacks:
        xfs_buf_do_callbacks(bp);
        XFS_BUF_SET_FSPRIVATE(bp, NULL);
        XFS_BUF_CLR_IODONE_FUNC(bp);
-       XFS_BUF_SET_BRELSE_FUNC(bp,NULL);
-       xfs_buf_relse(bp);
+       xfs_buf_ioend(bp, 0);
 }
 
-
 /*
  * This is the iodone() function for buffers which have been
  * logged.  It is called when they are eventually flushed out.
index c78cc6a3d87c0bb061092564c9f27c52d48519fa..4c7db74a05f70ba5359c81ad6480c1d34c86ca01 100644 (file)
@@ -152,37 +152,6 @@ xfs_errortag_clearall(xfs_mount_t *mp, int loud)
 }
 #endif /* DEBUG */
 
-
-void
-xfs_fs_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...)
-{
-       va_list ap;
-
-       va_start(ap, fmt);
-       xfs_fs_vcmn_err(level, mp, fmt, ap);
-       va_end(ap);
-}
-
-void
-xfs_cmn_err(int panic_tag, int level, xfs_mount_t *mp, char *fmt, ...)
-{
-       va_list ap;
-
-#ifdef DEBUG
-       xfs_panic_mask |= (XFS_PTAG_SHUTDOWN_CORRUPT | XFS_PTAG_LOGRES);
-#endif
-
-       if (xfs_panic_mask && (xfs_panic_mask & panic_tag)
-           && (level & CE_ALERT)) {
-               level &= ~CE_ALERT;
-               level |= CE_PANIC;
-               cmn_err(CE_ALERT, "XFS: Transforming an alert into a BUG.");
-       }
-       va_start(ap, fmt);
-       xfs_fs_vcmn_err(level, mp, fmt, ap);
-       va_end(ap);
-}
-
 void
 xfs_error_report(
        const char              *tag,
index f338847f80b8d36c5c017214ec9538dab795459b..10dce5475f022061ac95e863b98a07b6c715c21d 100644 (file)
@@ -136,8 +136,8 @@ extern int xfs_error_test(int, int *, char *, int, char *, unsigned long);
         xfs_error_test((tag), (mp)->m_fixedfsid, "expr", __LINE__, __FILE__, \
                        (rf))))
 
-extern int xfs_errortag_add(int error_tag, xfs_mount_t *mp);
-extern int xfs_errortag_clearall(xfs_mount_t *mp, int loud);
+extern int xfs_errortag_add(int error_tag, struct xfs_mount *mp);
+extern int xfs_errortag_clearall(struct xfs_mount *mp, int loud);
 #else
 #define XFS_TEST_ERROR(expr, mp, tag, rf)      (expr)
 #define xfs_errortag_add(tag, mp)              (ENOSYS)
@@ -162,21 +162,15 @@ extern int xfs_errortag_clearall(xfs_mount_t *mp, int loud);
 
 struct xfs_mount;
 
-extern void xfs_fs_vcmn_err(int level, struct xfs_mount *mp,
-               char *fmt, va_list ap)
-       __attribute__ ((format (printf, 3, 0)));
-extern void xfs_cmn_err(int panic_tag, int level, struct xfs_mount *mp,
-                       char *fmt, ...)
-       __attribute__ ((format (printf, 4, 5)));
-extern void xfs_fs_cmn_err(int level, struct xfs_mount *mp, char *fmt, ...)
-       __attribute__ ((format (printf, 3, 4)));
-
 extern void xfs_hex_dump(void *p, int length);
 
 #define xfs_fs_repair_cmn_err(level, mp, fmt, args...) \
        xfs_fs_cmn_err(level, mp, fmt "  Unmount and run xfs_repair.", ## args)
 
 #define xfs_fs_mount_cmn_err(f, fmt, args...) \
-       ((f & XFS_MFSI_QUIET)? (void)0 : cmn_err(CE_WARN, "XFS: " fmt, ## args))
+       do { \
+               if (!(f & XFS_MFSI_QUIET))      \
+                       cmn_err(CE_WARN, "XFS: " fmt, ## args); \
+       } while (0)
 
 #endif /* __XFS_ERROR_H__ */
index f56d30e8040cdef5120895a2499ed7c05e23b923..cec89dd5d7d28262ae064e257ec941a815cbb09f 100644 (file)
@@ -612,12 +612,13 @@ out:
  *
  * We cannot use an inode here for this - that will push dirty state back up
  * into the VFS and then periodic inode flushing will prevent log covering from
- * making progress. Hence we log a field in the superblock instead.
+ * making progress. Hence we log a field in the superblock instead and use a
+ * synchronous transaction to ensure the superblock is immediately unpinned
+ * and can be written back.
  */
 int
 xfs_fs_log_dummy(
-       xfs_mount_t     *mp,
-       int             flags)
+       xfs_mount_t     *mp)
 {
        xfs_trans_t     *tp;
        int             error;
@@ -632,8 +633,7 @@ xfs_fs_log_dummy(
 
        /* log the UUID because it is an unchanging field */
        xfs_mod_sb(tp, XFS_SB_UUID);
-       if (flags & SYNC_WAIT)
-               xfs_trans_set_sync(tp);
+       xfs_trans_set_sync(tp);
        return xfs_trans_commit(tp, 0);
 }
 
index a786c5212c1e478677e46f2725105a010ebd1262..1b6a98b66886c76d1fab032673ec88f4cb11afa0 100644 (file)
@@ -25,6 +25,6 @@ extern int xfs_fs_counts(xfs_mount_t *mp, xfs_fsop_counts_t *cnt);
 extern int xfs_reserve_blocks(xfs_mount_t *mp, __uint64_t *inval,
                                xfs_fsop_resblks_t *outval);
 extern int xfs_fs_goingdown(xfs_mount_t *mp, __uint32_t inflags);
-extern int xfs_fs_log_dummy(xfs_mount_t *mp, int flags);
+extern int xfs_fs_log_dummy(struct xfs_mount *mp);
 
 #endif /* __XFS_FSOPS_H__ */
index 0bf24b11d0c4a15d3514fabd2e5e64463369378d..ae6fef1ff563e19ceb6b97393ed3ec8804c110b5 100644 (file)
@@ -377,7 +377,7 @@ xfs_log_mount(
                cmn_err(CE_NOTE, "XFS mounting filesystem %s", mp->m_fsname);
        else {
                cmn_err(CE_NOTE,
-                       "!Mounting filesystem \"%s\" in no-recovery mode.  Filesystem will be inconsistent.",
+                       "Mounting filesystem \"%s\" in no-recovery mode.  Filesystem will be inconsistent.",
                        mp->m_fsname);
                ASSERT(mp->m_flags & XFS_MOUNT_RDONLY);
        }
index 204d8e5fa7faf63ada5fc2135fefc2b7330d34ec..aa0ebb776903317a8d29916396eb547c3ce296c9 100644 (file)
@@ -3800,7 +3800,7 @@ xlog_recover_finish(
                log->l_flags &= ~XLOG_RECOVERY_NEEDED;
        } else {
                cmn_err(CE_DEBUG,
-                       "!Ending clean XFS mount for filesystem: %s\n",
+                       "Ending clean XFS mount for filesystem: %s\n",
                        log->l_mp->m_fsname);
        }
        return 0;
index f80a067a46584005d4a1b8165fdef836c45fc6a0..33dbc4e0ad622a94dbbf8aa67b49e0eacef0cbbc 100644 (file)
@@ -1137,7 +1137,7 @@ out_undo_fdblocks:
        if (blkdelta)
                xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, -blkdelta, rsvd);
 out:
-       ASSERT(error = 0);
+       ASSERT(error == 0);
        return;
 }
 
index b3365025ff8d8733874b766866f2750b0dd36835..c4dbb132d902c0d2284473d30a954926c1745ac4 100644 (file)
 extern int hest_disable;
 extern int erst_disable;
 
+#ifdef CONFIG_ACPI_APEI
+void __init acpi_hest_init(void);
+#else
+static inline void acpi_hest_init(void) { return; }
+#endif
+
 typedef int (*apei_hest_func_t)(struct acpi_hest_header *hest_hdr, void *data);
 int apei_hest_parse(apei_hest_func_t func, void *data);
 
index aac27bd56e894008e1fb513efece592f92401455..f22e7fe4b6dbf25815580ad3625fd09f5aed3946 100644 (file)
@@ -121,6 +121,9 @@ int drm_fb_helper_setcolreg(unsigned regno,
 void drm_fb_helper_restore(void);
 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
                            uint32_t fb_width, uint32_t fb_height);
+void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
+                           uint32_t depth);
+
 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
 
 bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
index bec8b82889bfa7217952cdbb6a76f2a2fe8af041..ab68f785fd196fb73ef062a67b9ad195d84bcd13 100644 (file)
@@ -98,6 +98,17 @@ static inline int is_broadcast_ether_addr(const u8 *addr)
        return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff;
 }
 
+/**
+ * is_unicast_ether_addr - Determine if the Ethernet address is unicast
+ * @addr: Pointer to a six-byte array containing the Ethernet address
+ *
+ * Return true if the address is a unicast address.
+ */
+static inline int is_unicast_ether_addr(const u8 *addr)
+{
+       return !is_multicast_ether_addr(addr);
+}
+
 /**
  * is_valid_ether_addr - Determine if the given Ethernet address is valid
  * @addr: Pointer to a six-byte array containing the Ethernet address
index 3984f2358d1f56d98de234203ddec0cc9f20b538..08824e0ef381b3117c79f69a09a35891e8bd49fe 100644 (file)
@@ -666,7 +666,7 @@ struct block_device {
        int                     bd_holders;
        bool                    bd_write_holder;
 #ifdef CONFIG_SYSFS
-       struct gendisk *        bd_holder_disk; /* for sysfs slave linkng */
+       struct list_head        bd_holder_disks;
 #endif
        struct block_device *   bd_contains;
        unsigned                bd_block_size;
@@ -1066,7 +1066,6 @@ struct lock_manager_operations {
        int (*fl_grant)(struct file_lock *, struct file_lock *, int);
        void (*fl_release_private)(struct file_lock *);
        void (*fl_break)(struct file_lock *);
-       int (*fl_mylease)(struct file_lock *, struct file_lock *);
        int (*fl_change)(struct file_lock **, int);
 };
 
@@ -2058,12 +2057,18 @@ extern struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode,
 extern int blkdev_put(struct block_device *bdev, fmode_t mode);
 #ifdef CONFIG_SYSFS
 extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk);
+extern void bd_unlink_disk_holder(struct block_device *bdev,
+                                 struct gendisk *disk);
 #else
 static inline int bd_link_disk_holder(struct block_device *bdev,
                                      struct gendisk *disk)
 {
        return 0;
 }
+static inline void bd_unlink_disk_holder(struct block_device *bdev,
+                                        struct gendisk *disk)
+{
+}
 #endif
 #endif
 
index 4b47ed96f131b7273a5d3278bbceb22ed8f8b1ad..32720baf70f1c8f1e46741ff8006d44da82f6188 100644 (file)
@@ -35,13 +35,13 @@ static inline int gpio_request(unsigned gpio, const char *label)
        return -ENOSYS;
 }
 
-static inline int __must_check gpio_request_one(unsigned gpio,
+static inline int gpio_request_one(unsigned gpio,
                                        unsigned long flags, const char *label)
 {
        return -ENOSYS;
 }
 
-static inline int __must_check gpio_request_array(struct gpio *array, size_t num)
+static inline int gpio_request_array(struct gpio *array, size_t num)
 {
        return -ENOSYS;
 }
index b2adbb4b2f731f49d3b5f54918ef5b4a4508aa71..5bad17d1acdec6d386f6bf3d236c6900abb15ce8 100644 (file)
@@ -16,7 +16,7 @@
  * some fast and compact auxiliary data.
  */
 
-#if defined(CONFIG_SMP)
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
 #define LIST_BL_LOCKMASK       1UL
 #else
 #define LIST_BL_LOCKMASK       0UL
index 85cf2c28fac65b1901ef38d23fd627e3cc315c7c..37f56b7c4c15e164d7a1c74dccd333e0d6ed215f 100644 (file)
 #define AB8500_INT_ACC_DETECT_21DB_F   37
 #define AB8500_INT_ACC_DETECT_21DB_R   38
 #define AB8500_INT_GP_SW_ADC_CONV_END  39
-#define AB8500_INT_BTEMP_LOW           72
-#define AB8500_INT_BTEMP_LOW_MEDIUM    73
-#define AB8500_INT_BTEMP_MEDIUM_HIGH   74
-#define AB8500_INT_BTEMP_HIGH          75
-#define AB8500_INT_USB_CHARGER_NOT_OK  81
-#define AB8500_INT_ID_WAKEUP_R         82
-#define AB8500_INT_ID_DET_R1R          84
-#define AB8500_INT_ID_DET_R2R          85
-#define AB8500_INT_ID_DET_R3R          86
-#define AB8500_INT_ID_DET_R4R          87
-#define AB8500_INT_ID_WAKEUP_F         88
-#define AB8500_INT_ID_DET_R1F          90
-#define AB8500_INT_ID_DET_R2F          91
-#define AB8500_INT_ID_DET_R3F          92
-#define AB8500_INT_ID_DET_R4F          93
-#define AB8500_INT_USB_CHG_DET_DONE    94
-#define AB8500_INT_USB_CH_TH_PROT_F    96
-#define AB8500_INT_USB_CH_TH_PROP_R    97
-#define AB8500_INT_MAIN_CH_TH_PROP_F   98
-#define AB8500_INT_MAIN_CH_TH_PROT_R   99
-#define AB8500_INT_USB_CHARGER_NOT_OKF 103
+#define AB8500_INT_ADP_SOURCE_ERROR    72
+#define AB8500_INT_ADP_SINK_ERROR      73
+#define AB8500_INT_ADP_PROBE_PLUG      74
+#define AB8500_INT_ADP_PROBE_UNPLUG    75
+#define AB8500_INT_ADP_SENSE_OFF       76
+#define AB8500_INT_USB_PHY_POWER_ERR   78
+#define AB8500_INT_USB_LINK_STATUS     79
+#define AB8500_INT_BTEMP_LOW           80
+#define AB8500_INT_BTEMP_LOW_MEDIUM    81
+#define AB8500_INT_BTEMP_MEDIUM_HIGH   82
+#define AB8500_INT_BTEMP_HIGH          83
+#define AB8500_INT_USB_CHARGER_NOT_OK  89
+#define AB8500_INT_ID_WAKEUP_R         90
+#define AB8500_INT_ID_DET_R1R          92
+#define AB8500_INT_ID_DET_R2R          93
+#define AB8500_INT_ID_DET_R3R          94
+#define AB8500_INT_ID_DET_R4R          95
+#define AB8500_INT_ID_WAKEUP_F         96
+#define AB8500_INT_ID_DET_R1F          98
+#define AB8500_INT_ID_DET_R2F          99
+#define AB8500_INT_ID_DET_R3F          100
+#define AB8500_INT_ID_DET_R4F          101
+#define AB8500_INT_USB_CHG_DET_DONE    102
+#define AB8500_INT_USB_CH_TH_PROT_F    104
+#define AB8500_INT_USB_CH_TH_PROT_R    105
+#define AB8500_INT_MAIN_CH_TH_PROT_F   106
+#define AB8500_INT_MAIN_CH_TH_PROT_R   107
+#define AB8500_INT_USB_CHARGER_NOT_OKF 111
 
-#define AB8500_NR_IRQS                 104
-#define AB8500_NUM_IRQ_REGS            13
+#define AB8500_NR_IRQS                 112
+#define AB8500_NUM_IRQ_REGS            14
 
 /**
  * struct ab8500 - ab8500 internal structure
index 5582ab3d3e487e0f45365a84df8f0ef61455958a..835996e167e138560a69ffe107b3a46e49d67506 100644 (file)
@@ -47,6 +47,12 @@ struct mfd_cell {
 
        /* don't check for resource conflicts */
        bool                    ignore_resource_conflicts;
+
+       /*
+        * Disable runtime PM callbacks for this subdevice - see
+        * pm_runtime_no_callbacks().
+        */
+       bool                    pm_runtime_no_callbacks;
 };
 
 extern int mfd_add_devices(struct device *parent, int id,
index 7363dea6bbcdfcd8fd719426357346a043b266cd..effa5d3b96ae8f524d4fdce7b744ac8f4bd9f977 100644 (file)
@@ -159,10 +159,12 @@ struct max8998_dev {
        u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS];
        u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS];
        int type;
+       bool wakeup;
 };
 
 int max8998_irq_init(struct max8998_dev *max8998);
 void max8998_irq_exit(struct max8998_dev *max8998);
+int max8998_irq_resume(struct max8998_dev *max8998);
 
 extern int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest);
 extern int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count,
index f8c9f884aff2b0f246a1e258a4cb6e940021a875..61daa167b576908aa376c9a7eb2015e7634678a3 100644 (file)
@@ -70,24 +70,43 @@ struct max8998_regulator_data {
  * @num_regulators: number of regultors used
  * @irq_base: base IRQ number for max8998, required for IRQs
  * @ono: power onoff IRQ number for max8998
- * @buck1_max_voltage1: BUCK1 maximum alowed voltage register 1
- * @buck1_max_voltage2: BUCK1 maximum alowed voltage register 2
- * @buck2_max_voltage: BUCK2 maximum alowed voltage
+ * @buck_voltage_lock: Do NOT change the values of the following six
+ *   registers set by buck?_voltage?. The voltage of BUCK1/2 cannot
+ *   be other than the preset values.
+ * @buck1_voltage1: BUCK1 DVS mode 1 voltage register
+ * @buck1_voltage2: BUCK1 DVS mode 2 voltage register
+ * @buck1_voltage3: BUCK1 DVS mode 3 voltage register
+ * @buck1_voltage4: BUCK1 DVS mode 4 voltage register
+ * @buck2_voltage1: BUCK2 DVS mode 1 voltage register
+ * @buck2_voltage2: BUCK2 DVS mode 2 voltage register
  * @buck1_set1: BUCK1 gpio pin 1 to set output voltage
  * @buck1_set2: BUCK1 gpio pin 2 to set output voltage
+ * @buck1_default_idx: Default for BUCK1 gpio pin 1, 2
  * @buck2_set3: BUCK2 gpio pin to set output voltage
+ * @buck2_default_idx: Default for BUCK2 gpio pin.
+ * @wakeup: Allow to wake up from suspend
+ * @rtc_delay: LP3974 RTC chip bug that requires delay after a register
+ * write before reading it.
  */
 struct max8998_platform_data {
        struct max8998_regulator_data   *regulators;
        int                             num_regulators;
        int                             irq_base;
        int                             ono;
-       int                             buck1_max_voltage1;
-       int                             buck1_max_voltage2;
-       int                             buck2_max_voltage;
+       bool                            buck_voltage_lock;
+       int                             buck1_voltage1;
+       int                             buck1_voltage2;
+       int                             buck1_voltage3;
+       int                             buck1_voltage4;
+       int                             buck2_voltage1;
+       int                             buck2_voltage2;
        int                             buck1_set1;
        int                             buck1_set2;
+       int                             buck1_default_idx;
        int                             buck2_set3;
+       int                             buck2_default_idx;
+       bool                            wakeup;
+       bool                            rtc_delay;
 };
 
 #endif /*  __LINUX_MFD_MAX8998_H */
index a1239c48b41a0037341e3823868983ca4e5ef18f..903280d21866a9ae690c37bb7f57537a4d61ae95 100644 (file)
@@ -245,6 +245,7 @@ enum wm831x_parent {
        WM8320 = 0x8320,
        WM8321 = 0x8321,
        WM8325 = 0x8325,
+       WM8326 = 0x8326,
 };
 
 struct wm831x {
index be4957cf6511964c32b9ce87de0494308b952827..d971346b0340da50ae229f0dda8244f66c0eab2b 100644 (file)
@@ -520,9 +520,6 @@ struct netdev_queue {
         * please use this field instead of dev->trans_start
         */
        unsigned long           trans_start;
-       u64                     tx_bytes;
-       u64                     tx_packets;
-       u64                     tx_dropped;
 } ____cacheline_aligned_in_smp;
 
 static inline int netdev_queue_numa_node_read(const struct netdev_queue *q)
@@ -2265,8 +2262,6 @@ extern void               dev_load(struct net *net, const char *name);
 extern void            dev_mcast_init(void);
 extern struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
                                               struct rtnl_link_stats64 *storage);
-extern void            dev_txq_stats_fold(const struct net_device *dev,
-                                          struct rtnl_link_stats64 *stats);
 
 extern int             netdev_max_backlog;
 extern int             netdev_tstamp_prequeue;
index 9b46300b4305957f210d447bee436d3b9ae7ad06..134716e5e3509f9c56e11334137a9aefb41c4a21 100644 (file)
@@ -65,6 +65,9 @@
 
 #define NFS4_CDFC4_FORE        0x1
 #define NFS4_CDFC4_BACK 0x2
+#define NFS4_CDFC4_BOTH 0x3
+#define NFS4_CDFC4_FORE_OR_BOTH 0x3
+#define NFS4_CDFC4_BACK_OR_BOTH 0x7
 
 #define NFS4_SET_TO_SERVER_TIME        0
 #define NFS4_SET_TO_CLIENT_TIME        1
 #define SEQ4_STATUS_CB_PATH_DOWN_SESSION       0x00000200
 #define SEQ4_STATUS_BACKCHANNEL_FAULT          0x00000400
 
+#define NFS4_SECINFO_STYLE4_CURRENT_FH 0
+#define NFS4_SECINFO_STYLE4_PARENT     1
+
 #define NFS4_MAX_UINT64        (~(u64)0)
 
 /* An NFS4 sessions server must support at least NFS4_MAX_OPS operations.
index 8ae78a61eea4f2eaa8f0c137a1f77b27b3d880e8..bd316159278c57abdbfabe6205858c520ccf20bc 100644 (file)
@@ -35,7 +35,7 @@
 #define NFSEXP_NOHIDE          0x0200
 #define NFSEXP_NOSUBTREECHECK  0x0400
 #define        NFSEXP_NOAUTHNLM        0x0800          /* Don't authenticate NLM requests - just trust */
-#define NFSEXP_MSNFS           0x1000  /* do silly things that MS clients expect */
+#define NFSEXP_MSNFS           0x1000  /* do silly things that MS clients expect; no longer supported */
 #define NFSEXP_FSID            0x2000
 #define        NFSEXP_CROSSMOUNT       0x4000
 #define        NFSEXP_NOACL            0x8000  /* reserved for possible ACL related use */
index 2b89b712565b834ca3bb32a5bf5cdbe862b9326a..821ffb954f14738abf42439aedf5538cdffcd4ad 100644 (file)
  * @NL80211_CMD_SET_MPATH:  Set mesh path attributes for mesh path to
  *     destination %NL80211_ATTR_MAC on the interface identified by
  *     %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by
+ *     %NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP.
+ * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by
+ *     %NL80211_ATTR_MAC.
  * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
  *     the interface identified by %NL80211_ATTR_IFINDEX.
  * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
@@ -612,7 +616,7 @@ enum nl80211_commands {
  *     consisting of a nested array.
  *
  * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
- * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link.
  * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
  * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
  *     info given for %NL80211_CMD_GET_MPATH, nested attribute described at
@@ -879,7 +883,9 @@ enum nl80211_commands {
  *     See &enum nl80211_key_default_types.
  *
  * @NL80211_ATTR_MESH_SETUP: Optional mesh setup parameters.  These cannot be
- * changed once the mesh is active.
+ *     changed once the mesh is active.
+ * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute
+ *     containing attributes from &enum nl80211_meshconf_params.
  *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -1225,8 +1231,6 @@ enum nl80211_rate_info {
  * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
  * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
  * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
- * @__NL80211_STA_INFO_AFTER_LAST: internal
- * @NL80211_STA_INFO_MAX: highest possible station info attribute
  * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
  * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
  *     containing info as possible, see &enum nl80211_sta_info_txrate.
@@ -1236,6 +1240,11 @@ enum nl80211_rate_info {
  * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
  * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
  * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
+ * @NL80211_STA_INFO_LLID: the station's mesh LLID
+ * @NL80211_STA_INFO_PLID: the station's mesh PLID
+ * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
 enum nl80211_sta_info {
        __NL80211_STA_INFO_INVALID,
@@ -1626,7 +1635,7 @@ enum nl80211_mntr_flags {
  * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
  * that it takes for an HWMP information element to propagate across the mesh
  *
- * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not
+ * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not
  *
  * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
  * source mesh point for path selection elements.
@@ -1678,6 +1687,7 @@ enum nl80211_meshconf_params {
  * element that vendors will use to identify the path selection methods and
  * metrics in use.
  *
+ * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
  * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
  */
 enum nl80211_mesh_setup_params {
index 5b0c971d7cae5910b4547e486f97546a7201ce5f..6d6cb7a57bb3af7129baa644d7f3de0c24a58eab 100644 (file)
@@ -42,9 +42,6 @@ enum {
        /* flags for mem_cgroup and file and I/O status */
        PCG_MOVE_LOCK, /* For race between move_account v.s. following bits */
        PCG_FILE_MAPPED, /* page is accounted as "mapped" */
-       PCG_FILE_DIRTY, /* page is dirty */
-       PCG_FILE_WRITEBACK, /* page is under writeback */
-       PCG_FILE_UNSTABLE_NFS, /* page is NFS unstable */
        /* No lock in page_cgroup */
        PCG_ACCT_LRU, /* page has been accounted for (under lru_lock) */
 };
@@ -65,10 +62,6 @@ static inline void ClearPageCgroup##uname(struct page_cgroup *pc)    \
 static inline int TestClearPageCgroup##uname(struct page_cgroup *pc)   \
        { return test_and_clear_bit(PCG_##lname, &pc->flags);  }
 
-#define TESTSETPCGFLAG(uname, lname)                   \
-static inline int TestSetPageCgroup##uname(struct page_cgroup *pc)     \
-       { return test_and_set_bit(PCG_##lname, &pc->flags);  }
-
 /* Cache flag is set only once (at allocation) */
 TESTPCGFLAG(Cache, CACHE)
 CLEARPCGFLAG(Cache, CACHE)
@@ -88,22 +81,6 @@ SETPCGFLAG(FileMapped, FILE_MAPPED)
 CLEARPCGFLAG(FileMapped, FILE_MAPPED)
 TESTPCGFLAG(FileMapped, FILE_MAPPED)
 
-SETPCGFLAG(FileDirty, FILE_DIRTY)
-CLEARPCGFLAG(FileDirty, FILE_DIRTY)
-TESTPCGFLAG(FileDirty, FILE_DIRTY)
-TESTCLEARPCGFLAG(FileDirty, FILE_DIRTY)
-TESTSETPCGFLAG(FileDirty, FILE_DIRTY)
-
-SETPCGFLAG(FileWriteback, FILE_WRITEBACK)
-CLEARPCGFLAG(FileWriteback, FILE_WRITEBACK)
-TESTPCGFLAG(FileWriteback, FILE_WRITEBACK)
-
-SETPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-CLEARPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-TESTPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-TESTCLEARPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-TESTSETPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-
 SETPCGFLAG(Migration, MIGRATION)
 CLEARPCGFLAG(Migration, MIGRATION)
 TESTPCGFLAG(Migration, MIGRATION)
index c8b6473c5f42a74ef58913836c24b54f8500fd2a..479d9bb88e11761c4c440a5fe17ee64dc3076734 100644 (file)
@@ -40,4 +40,10 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
 { return NULL; }
 #endif
 
+#ifdef CONFIG_ACPI_APEI
+extern bool aer_acpi_firmware_first(void);
+#else
+static inline bool aer_acpi_firmware_first(void) { return false; }
+#endif
+
 #endif /* _PCI_ACPI_H_ */
index 91ba0b338b472905e05ca2ba7676a33bc2a6530d..ce6810512c6629598f99a25775663dc7f8fa24c4 100644 (file)
@@ -27,6 +27,7 @@ extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
 extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
 extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
 extern void pci_disable_link_state(struct pci_dev *pdev, int state);
+extern void pcie_clear_aspm(void);
 extern void pcie_no_aspm(void);
 #else
 static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
@@ -41,7 +42,9 @@ static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev)
 static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
 {
 }
-
+static inline void pcie_clear_aspm(void)
+{
+}
 static inline void pcie_no_aspm(void)
 {
 }
index 7454408c41b6fb57cf6f29913cb5be32374b377f..559d028970752672cc92260eb7b64c61276f5e89 100644 (file)
@@ -806,7 +806,7 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size);
 
 /* Power management related routines */
 int pci_save_state(struct pci_dev *dev);
-int pci_restore_state(struct pci_dev *dev);
+void pci_restore_state(struct pci_dev *dev);
 int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state);
 int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
 pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
@@ -820,7 +820,6 @@ int pci_prepare_to_sleep(struct pci_dev *dev);
 int pci_back_from_sleep(struct pci_dev *dev);
 bool pci_dev_run_wake(struct pci_dev *dev);
 bool pci_check_pme_status(struct pci_dev *dev);
-void pci_wakeup_event(struct pci_dev *dev);
 void pci_pme_wakeup_bus(struct pci_bus *bus);
 
 static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state,
@@ -994,6 +993,14 @@ extern void pci_restore_msi_state(struct pci_dev *dev);
 extern int pci_msi_enabled(void);
 #endif
 
+#ifdef CONFIG_PCIEPORTBUS
+extern bool pcie_ports_disabled;
+extern bool pcie_ports_auto;
+#else
+#define pcie_ports_disabled    true
+#define pcie_ports_auto                false
+#endif
+
 #ifndef CONFIG_PCIEASPM
 static inline int pcie_aspm_enabled(void)
 {
@@ -1003,6 +1010,14 @@ static inline int pcie_aspm_enabled(void)
 extern int pcie_aspm_enabled(void);
 #endif
 
+#ifdef CONFIG_PCIEAER
+void pci_no_aer(void);
+bool pci_aer_available(void);
+#else
+static inline void pci_no_aer(void) { }
+static inline bool pci_aer_available(void) { return false; }
+#endif
+
 #ifndef CONFIG_PCIE_ECRC
 static inline void pcie_set_ecrc_checking(struct pci_dev *dev)
 {
@@ -1168,10 +1183,8 @@ static inline int pci_save_state(struct pci_dev *dev)
        return 0;
 }
 
-static inline int pci_restore_state(struct pci_dev *dev)
-{
-       return 0;
-}
+static inline void pci_restore_state(struct pci_dev *dev)
+{ }
 
 static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 {
index ae0dc453e3e27565df1636e6b08f2c57707cb8e7..3adb06ebf8418aa0a886e474a9e3460ddb4cbe09 100644 (file)
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN        0x1c41
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX        0x1c5f
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS     0x1d22
-#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC       0x1d40
+#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0     0x1d40
+#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1     0x1d41
 #define PCI_DEVICE_ID_INTEL_82801AA_0  0x2410
 #define PCI_DEVICE_ID_INTEL_82801AA_1  0x2411
 #define PCI_DEVICE_ID_INTEL_82801AA_3  0x2413
index af83076c31a6ca082416362517c9cf1138673b4a..5b7e6b1ba54f4453deffe9291a0e4ab0ec412430 100644 (file)
 #define PCI_MSIX_PBA           8
 #define  PCI_MSIX_FLAGS_BIRMASK        (7 << 0)
 
+/* MSI-X entry's format */
+#define PCI_MSIX_ENTRY_SIZE            16
+#define  PCI_MSIX_ENTRY_LOWER_ADDR     0
+#define  PCI_MSIX_ENTRY_UPPER_ADDR     4
+#define  PCI_MSIX_ENTRY_DATA           8
+#define  PCI_MSIX_ENTRY_VECTOR_CTRL    12
+#define   PCI_MSIX_ENTRY_CTRL_MASKBIT  1
+
 /* CompactPCI Hotswap Register */
 
 #define PCI_CHSWP_CSR          2       /* Control and Status Register */
 #define  PCI_EXP_RTCTL_CRSSVE  0x10    /* CRS Software Visibility Enable */
 #define PCI_EXP_RTCAP          30      /* Root Capabilities */
 #define PCI_EXP_RTSTA          32      /* Root Status */
+#define PCI_EXP_RTSTA_PME      0x10000 /* PME status */
+#define PCI_EXP_RTSTA_PENDING  0x20000 /* PME pending */
 #define PCI_EXP_DEVCAP2                36      /* Device Capabilities 2 */
 #define  PCI_EXP_DEVCAP2_ARI   0x20    /* Alternative Routing-ID */
 #define PCI_EXP_DEVCTL2                40      /* Device Control 2 */
diff --git a/include/linux/power/gpio-charger.h b/include/linux/power/gpio-charger.h
new file mode 100644 (file)
index 0000000..de1dfe0
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_POWER_GPIO_CHARGER_H__
+#define __LINUX_POWER_GPIO_CHARGER_H__
+
+#include <linux/power_supply.h>
+#include <linux/types.h>
+
+/**
+ * struct gpio_charger_platform_data - platform_data for gpio_charger devices
+ * @name:              Name for the chargers power_supply device
+ * @type:              Type of the charger
+ * @gpio:              GPIO which is used to indicate the chargers status
+ * @gpio_active_low:   Should be set to 1 if the GPIO is active low otherwise 0
+ * @supplied_to:       Array of battery names to which this chargers supplies power
+ * @num_supplicants:   Number of entries in the supplied_to array
+ */
+struct gpio_charger_platform_data {
+       const char *name;
+       enum power_supply_type type;
+
+       int gpio;
+       int gpio_active_low;
+
+       char **supplied_to;
+       size_t num_supplicants;
+};
+
+#endif
diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h
new file mode 100644 (file)
index 0000000..7995deb
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Fuel gauge driver for Maxim 17042 / 8966 / 8997
+ *  Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MAX17042_BATTERY_H_
+#define __MAX17042_BATTERY_H_
+
+struct max17042_platform_data {
+       bool enable_current_sense;
+};
+
+#endif /* __MAX17042_BATTERY_H_ */
index dbce22faa6606f48e39faeb4685f0ebcb793fc57..fbe58b7e63eb3fd6a6b917f19d63048e6ee818de 100644 (file)
@@ -14,6 +14,7 @@ struct s3c_adc_bat_pdata {
        void (*disable_charger)(void);
 
        int gpio_charge_finished;
+       int gpio_inverted;
 
        const struct s3c_adc_bat_thresh *lut_noac;
        unsigned int lut_noac_cnt;
index 20ec0a64cb9ff0f8708a66ddaeb2ffd1d3ed72c9..bf221d65d9ad5d0c2878795021b2733012c4ef2f 100644 (file)
@@ -255,6 +255,11 @@ typedef unsigned int sk_buff_data_t;
 typedef unsigned char *sk_buff_data_t;
 #endif
 
+#if defined(CONFIG_NF_DEFRAG_IPV4) || defined(CONFIG_NF_DEFRAG_IPV4_MODULE) || \
+    defined(CONFIG_NF_DEFRAG_IPV6) || defined(CONFIG_NF_DEFRAG_IPV6_MODULE)
+#define NET_SKBUFF_NF_DEFRAG_NEEDED 1
+#endif
+
 /** 
  *     struct sk_buff - socket buffer
  *     @next: Next buffer in list
@@ -362,6 +367,8 @@ struct sk_buff {
        void                    (*destructor)(struct sk_buff *skb);
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        struct nf_conntrack     *nfct;
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
        struct sk_buff          *nfct_reasm;
 #endif
 #ifdef CONFIG_BRIDGE_NETFILTER
@@ -2057,6 +2064,8 @@ static inline void nf_conntrack_get(struct nf_conntrack *nfct)
        if (nfct)
                atomic_inc(&nfct->use);
 }
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
 static inline void nf_conntrack_get_reasm(struct sk_buff *skb)
 {
        if (skb)
@@ -2085,6 +2094,8 @@ static inline void nf_reset(struct sk_buff *skb)
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        nf_conntrack_put(skb->nfct);
        skb->nfct = NULL;
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
        nf_conntrack_put_reasm(skb->nfct_reasm);
        skb->nfct_reasm = NULL;
 #endif
@@ -2101,6 +2112,8 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
        dst->nfct = src->nfct;
        nf_conntrack_get(src->nfct);
        dst->nfctinfo = src->nfctinfo;
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
        dst->nfct_reasm = src->nfct_reasm;
        nf_conntrack_get_reasm(src->nfct_reasm);
 #endif
@@ -2114,6 +2127,8 @@ static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
 {
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        nf_conntrack_put(dst->nfct);
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
        nf_conntrack_put_reasm(dst->nfct_reasm);
 #endif
 #ifdef CONFIG_BRIDGE_NETFILTER
index 78aa104250b7b78755b570480353d66c304062cf..7898ea13de70a2233445c7e9deec48546c492efc 100644 (file)
@@ -256,10 +256,13 @@ static inline time_t get_expiry(char **bpp)
        return rv - boot.tv_sec;
 }
 
+#ifdef CONFIG_NFSD_DEPRECATED
 static inline void sunrpc_invalidate(struct cache_head *h,
                                     struct cache_detail *detail)
 {
        h->expiry_time = seconds_since_boot() - 1;
        detail->nextcheck = seconds_since_boot();
 }
+#endif /* CONFIG_NFSD_DEPRECATED */
+
 #endif /*  _LINUX_SUNRPC_CACHE_H_ */
index c81d4d8be3a99425729e0046c2d3683929b7a45a..ea29330b78bd002aa67b3091abd589a077318b91 100644 (file)
@@ -269,6 +269,7 @@ struct svc_rqst {
        struct cache_req        rq_chandle;     /* handle passed to caches for 
                                                 * request delaying 
                                                 */
+       bool                    rq_dropme;
        /* Catering to nfsd */
        struct auth_domain *    rq_client;      /* RPC peer info */
        struct auth_domain *    rq_gssclient;   /* "gss/"-style peer info */
index 357da5e0daa3308b0113009e0525f9a8cae3943d..059877b4d85b7c0734668bd9027745e0c10bea8b 100644 (file)
@@ -63,7 +63,6 @@ struct svc_xprt {
 #define XPT_LISTENER   11              /* listening endpoint */
 #define XPT_CACHE_AUTH 12              /* cache auth info */
 
-       struct svc_pool         *xpt_pool;      /* current pool iff queued */
        struct svc_serv         *xpt_server;    /* service for transport */
        atomic_t                xpt_reserved;   /* space on outq that is rsvd */
        struct mutex            xpt_mutex;      /* to serialize sending data */
@@ -81,6 +80,7 @@ struct svc_xprt {
        void                    *xpt_bc_sid;    /* back channel session ID */
 
        struct net              *xpt_net;
+       struct rpc_xprt         *xpt_bc_xprt;   /* NFSv4.1 backchannel */
 };
 
 static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
index 1b353a76c30492389bad8c12fb41ffcd901a2027..04dba23c59f2c4aead01ab313127368a63b93a05 100644 (file)
@@ -28,7 +28,6 @@ struct svc_sock {
        /* private TCP part */
        u32                     sk_reclen;      /* length of record */
        u32                     sk_tcplen;      /* current read length */
-       struct rpc_xprt         *sk_bc_xprt;    /* NFSv4.1 backchannel xprt */
 };
 
 /*
index 89d10d279a203d611bbc3f40760ab490c8eea098..bef0f535f7464608e4173c80d53d9c49a80384a4 100644 (file)
@@ -321,6 +321,7 @@ void                        xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie);
 #define XPRT_CLOSING           (6)
 #define XPRT_CONNECTION_ABORT  (7)
 #define XPRT_CONNECTION_CLOSE  (8)
+#define XPRT_INITIALIZED       (9)
 
 static inline void xprt_set_connected(struct rpc_xprt *xprt)
 {
index be7798dea6f45c5841c8806a4751995c3fc13374..ca95b98969ddf21860590e8252f7ad8a53f690b4 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/skbuff.h>
 
 /* This is the maximum truncated ICV length that we know of. */
-#define MAX_AH_AUTH_LEN        16
+#define MAX_AH_AUTH_LEN        64
 
 struct crypto_ahash;
 
index bcc9f448ec4e6d763504c31a5b02cf4c2514d59d..1322695beb52980e741b17473ed9906ba159895e 100644 (file)
@@ -1103,6 +1103,8 @@ struct cfg80211_pmksa {
  * @change_mpath: change a given mesh path
  * @get_mpath: get a mesh path for the given parameters
  * @dump_mpath: dump mesh path callback -- resume dump at index @idx
+ * @join_mesh: join the mesh network with the specified parameters
+ * @leave_mesh: leave the current mesh network
  *
  * @get_mesh_config: Get the current mesh configuration
  *
index 5b3fd5add7a4d27982105444a2dd2a300743f309..62c0ce2d1dc874a4480ad07a91639795b2c70f64 100644 (file)
@@ -337,6 +337,10 @@ struct ieee80211_bss_conf {
  * @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame
  * @IEEE80211_TX_CTL_STBC: Enables Space-Time Block Coding (STBC) for this
  *     frame and selects the maximum number of streams that it can use.
+ * @IEEE80211_TX_CTL_TX_OFFCHAN: Marks this packet to be transmitted on
+ *     the off-channel channel when a remain-on-channel offload is done
+ *     in hardware -- normal packets still flow and are expected to be
+ *     handled properly by the device.
  *
  * Note: If you have to add new flags to the enumeration, then don't
  *      forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -1753,6 +1757,16 @@ enum ieee80211_ampdu_mlme_action {
  *     (also see nl80211.h @NL80211_ATTR_WIPHY_ANTENNA_TX).
  *
  * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant).
+ *
+ * @remain_on_channel: Starts an off-channel period on the given channel, must
+ *     call back to ieee80211_ready_on_channel() when on that channel. Note
+ *     that normal channel traffic is not stopped as this is intended for hw
+ *     offload. Frames to transmit on the off-channel channel are transmitted
+ *     normally except for the %IEEE80211_TX_CTL_TX_OFFCHAN flag. When the
+ *     duration (which will always be non-zero) expires, the driver must call
+ *     ieee80211_remain_on_channel_expired(). This callback may sleep.
+ * @cancel_remain_on_channel: Requests that an ongoing off-channel period is
+ *     aborted before it expires. This callback may sleep.
  */
 struct ieee80211_ops {
        int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
index 1ee717eb5b099f6fa1fc782506c05e0dd59addb8..a4c99368579509387e6ae75eff33383db5e3f8a7 100644 (file)
@@ -7,16 +7,6 @@ extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6;
 extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6;
 extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6;
 
-extern int nf_ct_frag6_init(void);
-extern void nf_ct_frag6_cleanup(void);
-extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user);
-extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
-                              struct net_device *in,
-                              struct net_device *out,
-                              int (*okfn)(struct sk_buff *));
-
-struct inet_frags_ctl;
-
 #include <linux/sysctl.h>
 extern struct ctl_table nf_ct_ipv6_sysctl_table[];
 
index 94dd54d76b48d215729059d53b9e6a983070138a..fd79c9a1779d19d6a5dd54ef7380b990763a00ea 100644 (file)
@@ -3,4 +3,14 @@
 
 extern void nf_defrag_ipv6_enable(void);
 
+extern int nf_ct_frag6_init(void);
+extern void nf_ct_frag6_cleanup(void);
+extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user);
+extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
+                              struct net_device *in,
+                              struct net_device *out,
+                              int (*okfn)(struct sk_buff *));
+
+struct inet_frags_ctl;
+
 #endif /* _NF_DEFRAG_IPV6_H */
index 995108e54d9f0adde1344ff76daf821567ae9b83..3319f16b3beb899727c7a434e75fb1010d7ee139 100644 (file)
@@ -97,7 +97,6 @@ struct red_stats {
        u32             forced_mark;    /* Forced marks, qavg > max_thresh */
        u32             pdrop;          /* Drops due to queue limits */
        u32             other;          /* Drops due to drop() calls */
-       u32             backlog;
 };
 
 struct red_parms {
index 5c5f4cc2e99a8b36ea19f0841e10d80937e58b38..b24d7027b83c29b067bdc56f27ae28bf2d16c464 100644 (file)
@@ -764,6 +764,7 @@ EXPORT_SYMBOL_GPL(cgroup_unlock);
  */
 
 static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+static struct dentry *cgroup_lookup(struct inode *, struct dentry *, struct nameidata *);
 static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry);
 static int cgroup_populate_dir(struct cgroup *cgrp);
 static const struct inode_operations cgroup_dir_inode_operations;
@@ -860,6 +861,11 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
        iput(inode);
 }
 
+static int cgroup_delete(const struct dentry *d)
+{
+       return 1;
+}
+
 static void remove_dir(struct dentry *d)
 {
        struct dentry *parent = dget(d->d_parent);
@@ -910,7 +916,7 @@ static void cgroup_d_remove_dir(struct dentry *dentry)
 
        parent = dentry->d_parent;
        spin_lock(&parent->d_lock);
-       spin_lock(&dentry->d_lock);
+       spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
        list_del_init(&dentry->d_u.d_child);
        spin_unlock(&dentry->d_lock);
        spin_unlock(&parent->d_lock);
@@ -1451,6 +1457,7 @@ static int cgroup_get_rootdir(struct super_block *sb)
 {
        static const struct dentry_operations cgroup_dops = {
                .d_iput = cgroup_diput,
+               .d_delete = cgroup_delete,
        };
 
        struct inode *inode =
@@ -2195,12 +2202,20 @@ static const struct file_operations cgroup_file_operations = {
 };
 
 static const struct inode_operations cgroup_dir_inode_operations = {
-       .lookup = simple_lookup,
+       .lookup = cgroup_lookup,
        .mkdir = cgroup_mkdir,
        .rmdir = cgroup_rmdir,
        .rename = cgroup_rename,
 };
 
+static struct dentry *cgroup_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+{
+       if (dentry->d_name.len > NAME_MAX)
+               return ERR_PTR(-ENAMETOOLONG);
+       d_add(dentry, NULL);
+       return NULL;
+}
+
 /*
  * Check if a file is a control file
  */
index bb86d2932394aa9b1176ccfbba7a13102c0a3d20..6da5daeebab7266bbf5a1fa85fe3d7e1985475de 100644 (file)
@@ -1392,7 +1392,7 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,
        ax25_cb *ax25;
        int err = 0;
 
-       memset(fsa, 0, sizeof(fsa));
+       memset(fsa, 0, sizeof(*fsa));
        lock_sock(sk);
        ax25 = ax25_sk(sk);
 
index 06d0e7b253850d35fcf3b0bcc2fa6a7635d57986..54277df0f735abf601a44053fa29c9f85cc5c87b 100644 (file)
@@ -5523,34 +5523,6 @@ void netdev_run_todo(void)
        }
 }
 
-/**
- *     dev_txq_stats_fold - fold tx_queues stats
- *     @dev: device to get statistics from
- *     @stats: struct rtnl_link_stats64 to hold results
- */
-void dev_txq_stats_fold(const struct net_device *dev,
-                       struct rtnl_link_stats64 *stats)
-{
-       u64 tx_bytes = 0, tx_packets = 0, tx_dropped = 0;
-       unsigned int i;
-       struct netdev_queue *txq;
-
-       for (i = 0; i < dev->num_tx_queues; i++) {
-               txq = netdev_get_tx_queue(dev, i);
-               spin_lock_bh(&txq->_xmit_lock);
-               tx_bytes   += txq->tx_bytes;
-               tx_packets += txq->tx_packets;
-               tx_dropped += txq->tx_dropped;
-               spin_unlock_bh(&txq->_xmit_lock);
-       }
-       if (tx_bytes || tx_packets || tx_dropped) {
-               stats->tx_bytes   = tx_bytes;
-               stats->tx_packets = tx_packets;
-               stats->tx_dropped = tx_dropped;
-       }
-}
-EXPORT_SYMBOL(dev_txq_stats_fold);
-
 /* Convert net_device_stats to rtnl_link_stats64.  They have the same
  * fields in the same order, with only the type differing.
  */
@@ -5594,7 +5566,6 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
                netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev));
        } else {
                netdev_stats_to_stats64(storage, &dev->stats);
-               dev_txq_stats_fold(dev, storage);
        }
        storage->rx_dropped += atomic_long_read(&dev->rx_dropped);
        return storage;
index 19d6c21220fd47bb7141d8376a55c1785627a5e8..d31bb36ae0dc21cfdab61b90dd2f2fbfd665ce81 100644 (file)
@@ -380,6 +380,8 @@ static void skb_release_head_state(struct sk_buff *skb)
        }
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        nf_conntrack_put(skb->nfct);
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
        nf_conntrack_put_reasm(skb->nfct_reasm);
 #endif
 #ifdef CONFIG_BRIDGE_NETFILTER
index f9d7ac924f159db5d4ffb26f394021923bdf7065..44d2b42fda5616017c14f1db3caf23dd3a39935c 100644 (file)
@@ -351,7 +351,7 @@ EXPORT_SYMBOL(ether_setup);
  * @sizeof_priv: Size of additional driver-private structure to be allocated
  *     for this Ethernet device
  * @txqs: The number of TX queues this device has.
- * @txqs: The number of RX queues this device has.
+ * @rxqs: The number of RX queues this device has.
  *
  * Fill in the fields of the device structure with Ethernet-generic
  * values. Basically does everything except registering the device.
index 94b5bf132b2e33a467f662b8c0e402a459f00a3d..5f8d242be3f3016592678d09e9cf4654be9234a7 100644 (file)
@@ -401,6 +401,9 @@ int ip6_forward(struct sk_buff *skb)
                goto drop;
        }
 
+       if (skb->pkt_type != PACKET_HOST)
+               goto drop;
+
        skb_forward_csum(skb);
 
        /*
index 99abfb53bab91def61a8d7cdeaf2ee64ed8aa8f6..97c5b21b9674f3fb005da40235e78303f6323a9a 100644 (file)
 
 #include <linux/netfilter_ipv6.h>
 #include <linux/netfilter_bridge.h>
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_l4proto.h>
 #include <net/netfilter/nf_conntrack_l3proto.h>
 #include <net/netfilter/nf_conntrack_core.h>
-#include <net/netfilter/nf_conntrack_zones.h>
 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
+#endif
+#include <net/netfilter/nf_conntrack_zones.h>
 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
 
 static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
@@ -33,8 +35,10 @@ static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
 {
        u16 zone = NF_CT_DEFAULT_ZONE;
 
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        if (skb->nfct)
                zone = nf_ct_zone((struct nf_conn *)skb->nfct);
+#endif
 
 #ifdef CONFIG_BRIDGE_NETFILTER
        if (skb->nf_bridge &&
@@ -56,9 +60,11 @@ static unsigned int ipv6_defrag(unsigned int hooknum,
 {
        struct sk_buff *reasm;
 
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        /* Previously seen (loopback)?  */
        if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct))
                return NF_ACCEPT;
+#endif
 
        reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb));
        /* queued */
index 5cb8d3027b18b1cb990229a30db52a3e8004fe1a..2b7eef37875ccbdd8c59c5f8d845746e9f9609d7 100644 (file)
@@ -972,7 +972,8 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
 free:
        kfree_skb(skb2);
 out:
-       return err;
+       /* this avoids a loop in nfnetlink. */
+       return err == -EAGAIN ? -ENOBUFS : err;
 }
 
 #ifdef CONFIG_NF_NAT_NEEDED
index 0b9bb2085ce4ac5f8d22ada9ba0132235c02fbf9..74c064c0dfddca0c1aaf599ffaf66465b4259373 100644 (file)
@@ -808,7 +808,7 @@ static int __init af_rxrpc_init(void)
                goto error_call_jar;
        }
 
-       rxrpc_workqueue = create_workqueue("krxrpcd");
+       rxrpc_workqueue = alloc_workqueue("krxrpcd", 0, 1);
        if (!rxrpc_workqueue) {
                printk(KERN_NOTICE "RxRPC: Failed to allocate work queue\n");
                goto error_work_queue;
index af9360d1f6eb3b4c839bcfa2f623955c12a232a8..84ce48eadff4952e2552306fae3197858af86c59 100644 (file)
@@ -59,6 +59,10 @@ struct teql_master
        struct net_device *dev;
        struct Qdisc *slaves;
        struct list_head master_list;
+       unsigned long   tx_bytes;
+       unsigned long   tx_packets;
+       unsigned long   tx_errors;
+       unsigned long   tx_dropped;
 };
 
 struct teql_sched_data
@@ -274,7 +278,6 @@ static inline int teql_resolve(struct sk_buff *skb,
 static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct teql_master *master = netdev_priv(dev);
-       struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
        struct Qdisc *start, *q;
        int busy;
        int nores;
@@ -314,8 +317,8 @@ restart:
                                        __netif_tx_unlock(slave_txq);
                                        master->slaves = NEXT_SLAVE(q);
                                        netif_wake_queue(dev);
-                                       txq->tx_packets++;
-                                       txq->tx_bytes += length;
+                                       master->tx_packets++;
+                                       master->tx_bytes += length;
                                        return NETDEV_TX_OK;
                                }
                                __netif_tx_unlock(slave_txq);
@@ -342,10 +345,10 @@ restart:
                netif_stop_queue(dev);
                return NETDEV_TX_BUSY;
        }
-       dev->stats.tx_errors++;
+       master->tx_errors++;
 
 drop:
-       txq->tx_dropped++;
+       master->tx_dropped++;
        dev_kfree_skb(skb);
        return NETDEV_TX_OK;
 }
@@ -398,6 +401,18 @@ static int teql_master_close(struct net_device *dev)
        return 0;
 }
 
+static struct rtnl_link_stats64 *teql_master_stats64(struct net_device *dev,
+                                                    struct rtnl_link_stats64 *stats)
+{
+       struct teql_master *m = netdev_priv(dev);
+
+       stats->tx_packets       = m->tx_packets;
+       stats->tx_bytes         = m->tx_bytes;
+       stats->tx_errors        = m->tx_errors;
+       stats->tx_dropped       = m->tx_dropped;
+       return stats;
+}
+
 static int teql_master_mtu(struct net_device *dev, int new_mtu)
 {
        struct teql_master *m = netdev_priv(dev);
@@ -422,6 +437,7 @@ static const struct net_device_ops teql_netdev_ops = {
        .ndo_open       = teql_master_open,
        .ndo_stop       = teql_master_close,
        .ndo_start_xmit = teql_master_xmit,
+       .ndo_get_stats64 = teql_master_stats64,
        .ndo_change_mtu = teql_master_mtu,
 };
 
index 75ee993ea0573bb1fda3c403966a84d39a61e373..9576f35ab7014f2c506dfdd306d4201e3535b7a7 100644 (file)
@@ -137,7 +137,7 @@ arcfour_hmac_md5_usage_to_salt(unsigned int usage, u8 salt[4])
                ms_usage = 13;
                break;
        default:
-               return EINVAL;;
+               return -EINVAL;
        }
        salt[0] = (ms_usage >> 0) & 0xff;
        salt[1] = (ms_usage >> 8) & 0xff;
index dec2a6fc7c1277f15485011e52a7671eb3052574..bcdae78fdfc6b326c6918ec72de4530bbf8e2667 100644 (file)
@@ -67,7 +67,6 @@ static int netobj_equal(struct xdr_netobj *a, struct xdr_netobj *b)
 
 #define        RSI_HASHBITS    6
 #define        RSI_HASHMAX     (1<<RSI_HASHBITS)
-#define        RSI_HASHMASK    (RSI_HASHMAX-1)
 
 struct rsi {
        struct cache_head       h;
@@ -319,7 +318,6 @@ static struct rsi *rsi_update(struct rsi *new, struct rsi *old)
 
 #define        RSC_HASHBITS    10
 #define        RSC_HASHMAX     (1<<RSC_HASHBITS)
-#define        RSC_HASHMASK    (RSC_HASHMAX-1)
 
 #define GSS_SEQ_WIN    128
 
index e433e7580e27b221eff94d8b95ceaea703440618..72ad836e4fe05d7e5d9153918e5d8c1dacecc4a5 100644 (file)
@@ -37,7 +37,7 @@
 
 #define         RPCDBG_FACILITY RPCDBG_CACHE
 
-static void cache_defer_req(struct cache_req *req, struct cache_head *item);
+static bool cache_defer_req(struct cache_req *req, struct cache_head *item);
 static void cache_revisit_request(struct cache_head *item);
 
 static void cache_init(struct cache_head *h)
@@ -128,6 +128,7 @@ static void cache_fresh_locked(struct cache_head *head, time_t expiry)
 {
        head->expiry_time = expiry;
        head->last_refresh = seconds_since_boot();
+       smp_wmb(); /* paired with smp_rmb() in cache_is_valid() */
        set_bit(CACHE_VALID, &head->flags);
 }
 
@@ -208,11 +209,36 @@ static inline int cache_is_valid(struct cache_detail *detail, struct cache_head
                /* entry is valid */
                if (test_bit(CACHE_NEGATIVE, &h->flags))
                        return -ENOENT;
-               else
+               else {
+                       /*
+                        * In combination with write barrier in
+                        * sunrpc_cache_update, ensures that anyone
+                        * using the cache entry after this sees the
+                        * updated contents:
+                        */
+                       smp_rmb();
                        return 0;
+               }
        }
 }
 
+static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h)
+{
+       int rv;
+
+       write_lock(&detail->hash_lock);
+       rv = cache_is_valid(detail, h);
+       if (rv != -EAGAIN) {
+               write_unlock(&detail->hash_lock);
+               return rv;
+       }
+       set_bit(CACHE_NEGATIVE, &h->flags);
+       cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
+       write_unlock(&detail->hash_lock);
+       cache_fresh_unlocked(h, detail);
+       return -ENOENT;
+}
+
 /*
  * This is the generic cache management routine for all
  * the authentication caches.
@@ -251,14 +277,8 @@ int cache_check(struct cache_detail *detail,
                        case -EINVAL:
                                clear_bit(CACHE_PENDING, &h->flags);
                                cache_revisit_request(h);
-                               if (rv == -EAGAIN) {
-                                       set_bit(CACHE_NEGATIVE, &h->flags);
-                                       cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
-                                       cache_fresh_unlocked(h, detail);
-                                       rv = -ENOENT;
-                               }
+                               rv = try_to_negate_entry(detail, h);
                                break;
-
                        case -EAGAIN:
                                clear_bit(CACHE_PENDING, &h->flags);
                                cache_revisit_request(h);
@@ -268,9 +288,11 @@ int cache_check(struct cache_detail *detail,
        }
 
        if (rv == -EAGAIN) {
-               cache_defer_req(rqstp, h);
-               if (!test_bit(CACHE_PENDING, &h->flags)) {
-                       /* Request is not deferred */
+               if (!cache_defer_req(rqstp, h)) {
+                       /*
+                        * Request was not deferred; handle it as best
+                        * we can ourselves:
+                        */
                        rv = cache_is_valid(detail, h);
                        if (rv == -EAGAIN)
                                rv = -ETIMEDOUT;
@@ -618,18 +640,19 @@ static void cache_limit_defers(void)
                discard->revisit(discard, 1);
 }
 
-static void cache_defer_req(struct cache_req *req, struct cache_head *item)
+/* Return true if and only if a deferred request is queued. */
+static bool cache_defer_req(struct cache_req *req, struct cache_head *item)
 {
        struct cache_deferred_req *dreq;
 
        if (req->thread_wait) {
                cache_wait_req(req, item);
                if (!test_bit(CACHE_PENDING, &item->flags))
-                       return;
+                       return false;
        }
        dreq = req->defer(req);
        if (dreq == NULL)
-               return;
+               return false;
        setup_deferral(dreq, item, 1);
        if (!test_bit(CACHE_PENDING, &item->flags))
                /* Bit could have been cleared before we managed to
@@ -638,6 +661,7 @@ static void cache_defer_req(struct cache_req *req, struct cache_head *item)
                cache_revisit_request(item);
 
        cache_limit_defers();
+       return true;
 }
 
 static void cache_revisit_request(struct cache_head *item)
index 0e659c665a8d8013e4507224c1b3753158492925..08e05a8ce0255b338cc9c812006302a79e7ad4a9 100644 (file)
@@ -1001,6 +1001,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        rqstp->rq_splice_ok = 1;
        /* Will be turned off only when NFSv4 Sessions are used */
        rqstp->rq_usedeferral = 1;
+       rqstp->rq_dropme = false;
 
        /* Setup reply header */
        rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp);
@@ -1102,7 +1103,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
                *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
 
                /* Encode reply */
-               if (*statp == rpc_drop_reply) {
+               if (rqstp->rq_dropme) {
                        if (procp->pc_release)
                                procp->pc_release(rqstp, NULL, rqstp->rq_resp);
                        goto dropit;
index 3f2c5559ca1a49a496b9d531625c1e175fb029c8..ab86b7927f84594f188dadfa581271cf55b470cf 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/svc_xprt.h>
 #include <linux/sunrpc/svcsock.h>
+#include <linux/sunrpc/xprt.h>
 
 #define RPCDBG_FACILITY        RPCDBG_SVCXPRT
 
@@ -128,6 +129,9 @@ static void svc_xprt_free(struct kref *kref)
        if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags))
                svcauth_unix_info_release(xprt);
        put_net(xprt->xpt_net);
+       /* See comment on corresponding get in xs_setup_bc_tcp(): */
+       if (xprt->xpt_bc_xprt)
+               xprt_put(xprt->xpt_bc_xprt);
        xprt->xpt_ops->xpo_free(xprt);
        module_put(owner);
 }
@@ -303,6 +307,15 @@ static void svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
        list_del(&rqstp->rq_list);
 }
 
+static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt)
+{
+       if (xprt->xpt_flags & ((1<<XPT_CONN)|(1<<XPT_CLOSE)))
+               return true;
+       if (xprt->xpt_flags & ((1<<XPT_DATA)|(1<<XPT_DEFERRED)))
+               return xprt->xpt_ops->xpo_has_wspace(xprt);
+       return false;
+}
+
 /*
  * Queue up a transport with data pending. If there are idle nfsd
  * processes, wake 'em up.
@@ -315,8 +328,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
        struct svc_rqst *rqstp;
        int cpu;
 
-       if (!(xprt->xpt_flags &
-             ((1<<XPT_CONN)|(1<<XPT_DATA)|(1<<XPT_CLOSE)|(1<<XPT_DEFERRED))))
+       if (!svc_xprt_has_something_to_do(xprt))
                return;
 
        cpu = get_cpu();
@@ -343,28 +355,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
                dprintk("svc: transport %p busy, not enqueued\n", xprt);
                goto out_unlock;
        }
-       BUG_ON(xprt->xpt_pool != NULL);
-       xprt->xpt_pool = pool;
-
-       /* Handle pending connection */
-       if (test_bit(XPT_CONN, &xprt->xpt_flags))
-               goto process;
-
-       /* Handle close in-progress */
-       if (test_bit(XPT_CLOSE, &xprt->xpt_flags))
-               goto process;
-
-       /* Check if we have space to reply to a request */
-       if (!xprt->xpt_ops->xpo_has_wspace(xprt)) {
-               /* Don't enqueue while not enough space for reply */
-               dprintk("svc: no write space, transport %p  not enqueued\n",
-                       xprt);
-               xprt->xpt_pool = NULL;
-               clear_bit(XPT_BUSY, &xprt->xpt_flags);
-               goto out_unlock;
-       }
 
- process:
        if (!list_empty(&pool->sp_threads)) {
                rqstp = list_entry(pool->sp_threads.next,
                                   struct svc_rqst,
@@ -381,13 +372,11 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
                rqstp->rq_reserved = serv->sv_max_mesg;
                atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
                pool->sp_stats.threads_woken++;
-               BUG_ON(xprt->xpt_pool != pool);
                wake_up(&rqstp->rq_wait);
        } else {
                dprintk("svc: transport %p put into queue\n", xprt);
                list_add_tail(&xprt->xpt_ready, &pool->sp_sockets);
                pool->sp_stats.sockets_queued++;
-               BUG_ON(xprt->xpt_pool != pool);
        }
 
 out_unlock:
@@ -426,7 +415,6 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool)
 void svc_xprt_received(struct svc_xprt *xprt)
 {
        BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
-       xprt->xpt_pool = NULL;
        /* As soon as we clear busy, the xprt could be closed and
         * 'put', so we need a reference to call svc_xprt_enqueue with:
         */
@@ -722,7 +710,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
        if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
                dprintk("svc_recv: found XPT_CLOSE\n");
                svc_delete_xprt(xprt);
-       } else if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
+               /* Leave XPT_BUSY set on the dead xprt: */
+               goto out;
+       }
+       if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
                struct svc_xprt *newxpt;
                newxpt = xprt->xpt_ops->xpo_accept(xprt);
                if (newxpt) {
@@ -747,28 +738,23 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
                        spin_unlock_bh(&serv->sv_lock);
                        svc_xprt_received(newxpt);
                }
-               svc_xprt_received(xprt);
-       } else {
+       } else if (xprt->xpt_ops->xpo_has_wspace(xprt)) {
                dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
                        rqstp, pool->sp_id, xprt,
                        atomic_read(&xprt->xpt_ref.refcount));
                rqstp->rq_deferred = svc_deferred_dequeue(xprt);
-               if (rqstp->rq_deferred) {
-                       svc_xprt_received(xprt);
+               if (rqstp->rq_deferred)
                        len = svc_deferred_recv(rqstp);
-               } else {
+               else
                        len = xprt->xpt_ops->xpo_recvfrom(rqstp);
-                       svc_xprt_received(xprt);
-               }
                dprintk("svc: got len=%d\n", len);
        }
+       svc_xprt_received(xprt);
 
        /* No data, incomplete (TCP) read, or accept() */
-       if (len == 0 || len == -EAGAIN) {
-               rqstp->rq_res.len = 0;
-               svc_xprt_release(rqstp);
-               return -EAGAIN;
-       }
+       if (len == 0 || len == -EAGAIN)
+               goto out;
+
        clear_bit(XPT_OLD, &xprt->xpt_flags);
 
        rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp));
@@ -777,6 +763,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
        if (serv->sv_stats)
                serv->sv_stats->netcnt++;
        return len;
+out:
+       rqstp->rq_res.len = 0;
+       svc_xprt_release(rqstp);
+       return -EAGAIN;
 }
 EXPORT_SYMBOL_GPL(svc_recv);
 
@@ -935,7 +925,12 @@ void svc_close_xprt(struct svc_xprt *xprt)
        if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags))
                /* someone else will have to effect the close */
                return;
-
+       /*
+        * We expect svc_close_xprt() to work even when no threads are
+        * running (e.g., while configuring the server before starting
+        * any threads), so if the transport isn't busy, we delete
+        * it ourself:
+        */
        svc_delete_xprt(xprt);
 }
 EXPORT_SYMBOL_GPL(svc_close_xprt);
@@ -945,16 +940,16 @@ void svc_close_all(struct list_head *xprt_list)
        struct svc_xprt *xprt;
        struct svc_xprt *tmp;
 
+       /*
+        * The server is shutting down, and no more threads are running.
+        * svc_xprt_enqueue() might still be running, but at worst it
+        * will re-add the xprt to sp_sockets, which will soon get
+        * freed.  So we don't bother with any more locking, and don't
+        * leave the close to the (nonexistent) server threads:
+        */
        list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
                set_bit(XPT_CLOSE, &xprt->xpt_flags);
-               if (test_bit(XPT_BUSY, &xprt->xpt_flags)) {
-                       /* Waiting to be processed, but no threads left,
-                        * So just remove it from the waiting list
-                        */
-                       list_del_init(&xprt->xpt_ready);
-                       clear_bit(XPT_BUSY, &xprt->xpt_flags);
-               }
-               svc_close_xprt(xprt);
+               svc_delete_xprt(xprt);
        }
 }
 
@@ -1028,6 +1023,7 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req)
        }
        svc_xprt_get(rqstp->rq_xprt);
        dr->xprt = rqstp->rq_xprt;
+       rqstp->rq_dropme = true;
 
        dr->handle.revisit = svc_revisit;
        return &dr->handle;
@@ -1065,14 +1061,13 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
        if (!test_bit(XPT_DEFERRED, &xprt->xpt_flags))
                return NULL;
        spin_lock(&xprt->xpt_lock);
-       clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
        if (!list_empty(&xprt->xpt_deferred)) {
                dr = list_entry(xprt->xpt_deferred.next,
                                struct svc_deferred_req,
                                handle.recent);
                list_del_init(&dr->handle.recent);
-               set_bit(XPT_DEFERRED, &xprt->xpt_flags);
-       }
+       } else
+               clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
        spin_unlock(&xprt->xpt_lock);
        return dr;
 }
index 4e9393c24687ffac1a51527de4b7d384234b6e53..7963569fc04f014745c96054946d82cde28aa879 100644 (file)
@@ -118,7 +118,6 @@ EXPORT_SYMBOL_GPL(svc_auth_unregister);
 
 #define        DN_HASHBITS     6
 #define        DN_HASHMAX      (1<<DN_HASHBITS)
-#define        DN_HASHMASK     (DN_HASHMAX-1)
 
 static struct hlist_head       auth_domain_table[DN_HASHMAX];
 static spinlock_t      auth_domain_lock =
index 560677d187f1b0fc7eb3d72c119aa848eb306145..30916b06c12bd7f5ade9f9cea0641e51ac52e528 100644 (file)
@@ -30,7 +30,9 @@
 
 struct unix_domain {
        struct auth_domain      h;
+#ifdef CONFIG_NFSD_DEPRECATED
        int     addr_changes;
+#endif /* CONFIG_NFSD_DEPRECATED */
        /* other stuff later */
 };
 
@@ -64,7 +66,9 @@ struct auth_domain *unix_domain_find(char *name)
                        return NULL;
                }
                new->h.flavour = &svcauth_unix;
+#ifdef CONFIG_NFSD_DEPRECATED
                new->addr_changes = 0;
+#endif /* CONFIG_NFSD_DEPRECATED */
                rv = auth_domain_lookup(name, &new->h);
        }
 }
@@ -85,14 +89,15 @@ static void svcauth_unix_domain_release(struct auth_domain *dom)
  */
 #define        IP_HASHBITS     8
 #define        IP_HASHMAX      (1<<IP_HASHBITS)
-#define        IP_HASHMASK     (IP_HASHMAX-1)
 
 struct ip_map {
        struct cache_head       h;
        char                    m_class[8]; /* e.g. "nfsd" */
        struct in6_addr         m_addr;
        struct unix_domain      *m_client;
+#ifdef CONFIG_NFSD_DEPRECATED
        int                     m_add_change;
+#endif /* CONFIG_NFSD_DEPRECATED */
 };
 
 static void ip_map_put(struct kref *kref)
@@ -146,7 +151,9 @@ static void update(struct cache_head *cnew, struct cache_head *citem)
 
        kref_get(&item->m_client->h.ref);
        new->m_client = item->m_client;
+#ifdef CONFIG_NFSD_DEPRECATED
        new->m_add_change = item->m_add_change;
+#endif /* CONFIG_NFSD_DEPRECATED */
 }
 static struct cache_head *ip_map_alloc(void)
 {
@@ -331,6 +338,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
        ip.h.flags = 0;
        if (!udom)
                set_bit(CACHE_NEGATIVE, &ip.h.flags);
+#ifdef CONFIG_NFSD_DEPRECATED
        else {
                ip.m_add_change = udom->addr_changes;
                /* if this is from the legacy set_client system call,
@@ -339,6 +347,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
                if (expiry == NEVER)
                        ip.m_add_change++;
        }
+#endif /* CONFIG_NFSD_DEPRECATED */
        ip.h.expiry_time = expiry;
        ch = sunrpc_cache_update(cd, &ip.h, &ipm->h,
                                 hash_str(ipm->m_class, IP_HASHBITS) ^
@@ -358,6 +367,7 @@ static inline int ip_map_update(struct net *net, struct ip_map *ipm,
        return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry);
 }
 
+#ifdef CONFIG_NFSD_DEPRECATED
 int auth_unix_add_addr(struct net *net, struct in6_addr *addr, struct auth_domain *dom)
 {
        struct unix_domain *udom;
@@ -402,8 +412,7 @@ struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr)
                return NULL;
 
        if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) {
-               if (test_and_set_bit(CACHE_NEGATIVE, &ipm->h.flags) == 0)
-                       auth_domain_put(&ipm->m_client->h);
+               sunrpc_invalidate(&ipm->h, sn->ip_map_cache);
                rv = NULL;
        } else {
                rv = &ipm->m_client->h;
@@ -413,6 +422,7 @@ struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr)
        return rv;
 }
 EXPORT_SYMBOL_GPL(auth_unix_lookup);
+#endif /* CONFIG_NFSD_DEPRECATED */
 
 void svcauth_unix_purge(void)
 {
@@ -497,7 +507,6 @@ svcauth_unix_info_release(struct svc_xprt *xpt)
  */
 #define        GID_HASHBITS    8
 #define        GID_HASHMAX     (1<<GID_HASHBITS)
-#define        GID_HASHMASK    (GID_HASHMAX - 1)
 
 struct unix_gid {
        struct cache_head       h;
index d265aa700bb3dc9fd036ceef3e3650f8e9b59533..7bd3bbba4710d82ff658bd6de998543bca0609a7 100644 (file)
@@ -331,19 +331,21 @@ int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen,
                        len = onelen;
                        break;
                }
-               if (toclose && strcmp(toclose, buf + len) == 0)
+               if (toclose && strcmp(toclose, buf + len) == 0) {
                        closesk = svsk;
-               else
+                       svc_xprt_get(&closesk->sk_xprt);
+               } else
                        len += onelen;
        }
        spin_unlock_bh(&serv->sv_lock);
 
-       if (closesk)
+       if (closesk) {
                /* Should unregister with portmap, but you cannot
                 * unregister just one protocol...
                 */
                svc_close_xprt(&closesk->sk_xprt);
-       else if (toclose)
+               svc_xprt_put(&closesk->sk_xprt);
+       } else if (toclose)
                return -ENOENT;
        return len;
 }
@@ -992,15 +994,17 @@ static int svc_process_calldir(struct svc_sock *svsk, struct svc_rqst *rqstp,
                vec[0] = rqstp->rq_arg.head[0];
        } else {
                /* REPLY */
-               if (svsk->sk_bc_xprt)
-                       req = xprt_lookup_rqst(svsk->sk_bc_xprt, xid);
+               struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
+
+               if (bc_xprt)
+                       req = xprt_lookup_rqst(bc_xprt, xid);
 
                if (!req) {
                        printk(KERN_NOTICE
                                "%s: Got unrecognized reply: "
-                               "calldir 0x%x sk_bc_xprt %p xid %08x\n",
+                               "calldir 0x%x xpt_bc_xprt %p xid %08x\n",
                                __func__, ntohl(calldir),
-                               svsk->sk_bc_xprt, xid);
+                               bc_xprt, xid);
                        vec[0] = rqstp->rq_arg.head[0];
                        goto out;
                }
index 4c8f18aff7c341885764c6f1525a292688328c5d..856274d7e85c21eb6b89feff50ff767986b344e2 100644 (file)
@@ -965,6 +965,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req)
        xprt = kzalloc(size, GFP_KERNEL);
        if (xprt == NULL)
                goto out;
+       kref_init(&xprt->kref);
 
        xprt->max_reqs = max_req;
        xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL);
@@ -1101,8 +1102,10 @@ found:
                                -PTR_ERR(xprt));
                return xprt;
        }
+       if (test_and_set_bit(XPRT_INITIALIZED, &xprt->state))
+               /* ->setup returned a pre-initialized xprt: */
+               return xprt;
 
-       kref_init(&xprt->kref);
        spin_lock_init(&xprt->transport_lock);
        spin_lock_init(&xprt->reserve_lock);
 
index 96549df836ee0ed5da8285960e88c47f9d6b107d..c431f5a579605bfa5ea33161ff45188ab4bd570d 100644 (file)
@@ -2359,6 +2359,15 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
        struct svc_sock *bc_sock;
        struct rpc_xprt *ret;
 
+       if (args->bc_xprt->xpt_bc_xprt) {
+               /*
+                * This server connection already has a backchannel
+                * export; we can't create a new one, as we wouldn't be
+                * able to match replies based on xid any more.  So,
+                * reuse the already-existing one:
+                */
+                return args->bc_xprt->xpt_bc_xprt;
+       }
        xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
        if (IS_ERR(xprt))
                return xprt;
@@ -2375,16 +2384,6 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
        xprt->reestablish_timeout = 0;
        xprt->idle_timeout = 0;
 
-       /*
-        * The backchannel uses the same socket connection as the
-        * forechannel
-        */
-       xprt->bc_xprt = args->bc_xprt;
-       bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
-       bc_sock->sk_bc_xprt = xprt;
-       transport->sock = bc_sock->sk_sock;
-       transport->inet = bc_sock->sk_sk;
-
        xprt->ops = &bc_tcp_ops;
 
        switch (addr->sa_family) {
@@ -2406,6 +2405,20 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
                        xprt->address_strings[RPC_DISPLAY_PORT],
                        xprt->address_strings[RPC_DISPLAY_PROTO]);
 
+       /*
+        * Once we've associated a backchannel xprt with a connection,
+        * we want to keep it around as long as long as the connection
+        * lasts, in case we need to start using it for a backchannel
+        * again; this reference won't be dropped until bc_xprt is
+        * destroyed.
+        */
+       xprt_get(xprt);
+       args->bc_xprt->xpt_bc_xprt = xprt;
+       xprt->bc_xprt = args->bc_xprt;
+       bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
+       transport->sock = bc_sock->sk_sock;
+       transport->inet = bc_sock->sk_sk;
+
        /*
         * Since we don't want connections for the backchannel, we set
         * the xprt status to connected
@@ -2415,6 +2428,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
 
        if (try_module_get(THIS_MODULE))
                return xprt;
+       xprt_put(xprt);
        ret = ERR_PTR(-EINVAL);
 out_err:
        xprt_free(xprt);
index a3301cc4ab822e640a30d80dee10e9222adb66a3..185b00088320415191dafec55a5611dd3eaa5bb5 100644 (file)
@@ -90,12 +90,7 @@ int snd_cs5535audio_resume(struct pci_dev *pci)
        int i;
 
        pci_set_power_state(pci, PCI_D0);
-       if (pci_restore_state(pci) < 0) {
-               printk(KERN_ERR "cs5535audio: pci_restore_state failed, "
-                      "disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
+       pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
                printk(KERN_ERR "cs5535audio: pci_enable_device failed, "
                       "disabling device\n");