diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-08 07:55:01 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-08 07:55:01 -0800 |
commit | d7fc02c7bae7b1cf69269992cf880a43a350cdaa (patch) | |
tree | a43d56fa72913a1cc98a0bbebe054d08581b3a7c /drivers/ssb/main.c | |
parent | ee1262dbc65ce0b6234a915d8432171e8d77f518 (diff) | |
parent | 28b4d5cc17c20786848cdc07b7ea237a309776bb (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1815 commits)
mac80211: fix reorder buffer release
iwmc3200wifi: Enable wimax core through module parameter
iwmc3200wifi: Add wifi-wimax coexistence mode as a module parameter
iwmc3200wifi: Coex table command does not expect a response
iwmc3200wifi: Update wiwi priority table
iwlwifi: driver version track kernel version
iwlwifi: indicate uCode type when fail dump error/event log
iwl3945: remove duplicated event logging code
b43: fix two warnings
ipw2100: fix rebooting hang with driver loaded
cfg80211: indent regulatory messages with spaces
iwmc3200wifi: fix NULL pointer dereference in pmkid update
mac80211: Fix TX status reporting for injected data frames
ath9k: enable 2GHz band only if the device supports it
airo: Fix integer overflow warning
rt2x00: Fix padding bug on L2PAD devices.
WE: Fix set events not propagated
b43legacy: avoid PPC fault during resume
b43: avoid PPC fault during resume
tcp: fix a timewait refcnt race
...
Fix up conflicts due to sysctl cleanups (dead sysctl_check code and
CTL_UNNUMBERED removed) in
kernel/sysctl_check.c
net/ipv4/sysctl_net_ipv4.c
net/ipv6/addrconf.c
net/sctp/sysctl.c
Diffstat (limited to 'drivers/ssb/main.c')
-rw-r--r-- | drivers/ssb/main.c | 126 |
1 files changed, 65 insertions, 61 deletions
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 579b114be41..5681ebed9c6 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -140,6 +140,19 @@ static void ssb_device_put(struct ssb_device *dev) put_device(dev->dev); } +static inline struct ssb_driver *ssb_driver_get(struct ssb_driver *drv) +{ + if (drv) + get_driver(&drv->drv); + return drv; +} + +static inline void ssb_driver_put(struct ssb_driver *drv) +{ + if (drv) + put_driver(&drv->drv); +} + static int ssb_device_resume(struct device *dev) { struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); @@ -210,90 +223,81 @@ int ssb_bus_suspend(struct ssb_bus *bus) EXPORT_SYMBOL(ssb_bus_suspend); #ifdef CONFIG_SSB_SPROM -int ssb_devices_freeze(struct ssb_bus *bus) +/** ssb_devices_freeze - Freeze all devices on the bus. + * + * After freezing no device driver will be handling a device + * on this bus anymore. ssb_devices_thaw() must be called after + * a successful freeze to reactivate the devices. + * + * @bus: The bus. + * @ctx: Context structure. Pass this to ssb_devices_thaw(). + */ +int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx) { - struct ssb_device *dev; - struct ssb_driver *drv; - int err = 0; - int i; - pm_message_t state = PMSG_FREEZE; + struct ssb_device *sdev; + struct ssb_driver *sdrv; + unsigned int i; + + memset(ctx, 0, sizeof(*ctx)); + ctx->bus = bus; + SSB_WARN_ON(bus->nr_devices > ARRAY_SIZE(ctx->device_frozen)); - /* First check that we are capable to freeze all devices. */ for (i = 0; i < bus->nr_devices; i++) { - dev = &(bus->devices[i]); - if (!dev->dev || - !dev->dev->driver || - !device_is_registered(dev->dev)) - continue; - drv = drv_to_ssb_drv(dev->dev->driver); - if (!drv) + sdev = ssb_device_get(&bus->devices[i]); + + if (!sdev->dev || !sdev->dev->driver || + !device_is_registered(sdev->dev)) { + ssb_device_put(sdev); continue; - if (!drv->suspend) { - /* Nope, can't suspend this one. */ - return -EOPNOTSUPP; } - } - /* Now suspend all devices */ - for (i = 0; i < bus->nr_devices; i++) { - dev = &(bus->devices[i]); - if (!dev->dev || - !dev->dev->driver || - !device_is_registered(dev->dev)) - continue; - drv = drv_to_ssb_drv(dev->dev->driver); - if (!drv) + sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver)); + if (!sdrv || SSB_WARN_ON(!sdrv->remove)) { + ssb_device_put(sdev); continue; - err = drv->suspend(dev, state); - if (err) { - ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n", - dev_name(dev->dev)); - goto err_unwind; } + sdrv->remove(sdev); + ctx->device_frozen[i] = 1; } return 0; -err_unwind: - for (i--; i >= 0; i--) { - dev = &(bus->devices[i]); - if (!dev->dev || - !dev->dev->driver || - !device_is_registered(dev->dev)) - continue; - drv = drv_to_ssb_drv(dev->dev->driver); - if (!drv) - continue; - if (drv->resume) - drv->resume(dev); - } - return err; } -int ssb_devices_thaw(struct ssb_bus *bus) +/** ssb_devices_thaw - Unfreeze all devices on the bus. + * + * This will re-attach the device drivers and re-init the devices. + * + * @ctx: The context structure from ssb_devices_freeze() + */ +int ssb_devices_thaw(struct ssb_freeze_context *ctx) { - struct ssb_device *dev; - struct ssb_driver *drv; - int err; - int i; + struct ssb_bus *bus = ctx->bus; + struct ssb_device *sdev; + struct ssb_driver *sdrv; + unsigned int i; + int err, result = 0; for (i = 0; i < bus->nr_devices; i++) { - dev = &(bus->devices[i]); - if (!dev->dev || - !dev->dev->driver || - !device_is_registered(dev->dev)) + if (!ctx->device_frozen[i]) continue; - drv = drv_to_ssb_drv(dev->dev->driver); - if (!drv) + sdev = &bus->devices[i]; + + if (SSB_WARN_ON(!sdev->dev || !sdev->dev->driver)) continue; - if (SSB_WARN_ON(!drv->resume)) + sdrv = drv_to_ssb_drv(sdev->dev->driver); + if (SSB_WARN_ON(!sdrv || !sdrv->probe)) continue; - err = drv->resume(dev); + + err = sdrv->probe(sdev, &sdev->id); if (err) { ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", - dev_name(dev->dev)); + dev_name(sdev->dev)); + result = err; } + ssb_driver_put(sdrv); + ssb_device_put(sdev); } - return 0; + return result; } #endif /* CONFIG_SSB_SPROM */ |