diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/ssb/main.c | 126 | ||||
| -rw-r--r-- | drivers/ssb/sprom.c | 10 | ||||
| -rw-r--r-- | drivers/ssb/ssb_private.h | 12 |
3 files changed, 78 insertions, 70 deletions
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 579b114be412..5681ebed9c65 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c | |||
| @@ -140,6 +140,19 @@ static void ssb_device_put(struct ssb_device *dev) | |||
| 140 | put_device(dev->dev); | 140 | put_device(dev->dev); |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | static inline struct ssb_driver *ssb_driver_get(struct ssb_driver *drv) | ||
| 144 | { | ||
| 145 | if (drv) | ||
| 146 | get_driver(&drv->drv); | ||
| 147 | return drv; | ||
| 148 | } | ||
| 149 | |||
| 150 | static inline void ssb_driver_put(struct ssb_driver *drv) | ||
| 151 | { | ||
| 152 | if (drv) | ||
| 153 | put_driver(&drv->drv); | ||
| 154 | } | ||
| 155 | |||
| 143 | static int ssb_device_resume(struct device *dev) | 156 | static int ssb_device_resume(struct device *dev) |
| 144 | { | 157 | { |
| 145 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | 158 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); |
| @@ -210,90 +223,81 @@ int ssb_bus_suspend(struct ssb_bus *bus) | |||
| 210 | EXPORT_SYMBOL(ssb_bus_suspend); | 223 | EXPORT_SYMBOL(ssb_bus_suspend); |
| 211 | 224 | ||
| 212 | #ifdef CONFIG_SSB_SPROM | 225 | #ifdef CONFIG_SSB_SPROM |
| 213 | int ssb_devices_freeze(struct ssb_bus *bus) | 226 | /** ssb_devices_freeze - Freeze all devices on the bus. |
| 227 | * | ||
| 228 | * After freezing no device driver will be handling a device | ||
| 229 | * on this bus anymore. ssb_devices_thaw() must be called after | ||
| 230 | * a successful freeze to reactivate the devices. | ||
| 231 | * | ||
| 232 | * @bus: The bus. | ||
| 233 | * @ctx: Context structure. Pass this to ssb_devices_thaw(). | ||
| 234 | */ | ||
| 235 | int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx) | ||
| 214 | { | 236 | { |
| 215 | struct ssb_device *dev; | 237 | struct ssb_device *sdev; |
| 216 | struct ssb_driver *drv; | 238 | struct ssb_driver *sdrv; |
| 217 | int err = 0; | 239 | unsigned int i; |
| 218 | int i; | 240 | |
| 219 | pm_message_t state = PMSG_FREEZE; | 241 | memset(ctx, 0, sizeof(*ctx)); |
| 242 | ctx->bus = bus; | ||
| 243 | SSB_WARN_ON(bus->nr_devices > ARRAY_SIZE(ctx->device_frozen)); | ||
| 220 | 244 | ||
| 221 | /* First check that we are capable to freeze all devices. */ | ||
| 222 | for (i = 0; i < bus->nr_devices; i++) { | 245 | for (i = 0; i < bus->nr_devices; i++) { |
| 223 | dev = &(bus->devices[i]); | 246 | sdev = ssb_device_get(&bus->devices[i]); |
| 224 | if (!dev->dev || | 247 | |
| 225 | !dev->dev->driver || | 248 | if (!sdev->dev || !sdev->dev->driver || |
| 226 | !device_is_registered(dev->dev)) | 249 | !device_is_registered(sdev->dev)) { |
| 227 | continue; | 250 | ssb_device_put(sdev); |
| 228 | drv = drv_to_ssb_drv(dev->dev->driver); | ||
| 229 | if (!drv) | ||
| 230 | continue; | 251 | continue; |
| 231 | if (!drv->suspend) { | ||
| 232 | /* Nope, can't suspend this one. */ | ||
| 233 | return -EOPNOTSUPP; | ||
| 234 | } | 252 | } |
| 235 | } | 253 | sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver)); |
| 236 | /* Now suspend all devices */ | 254 | if (!sdrv || SSB_WARN_ON(!sdrv->remove)) { |
| 237 | for (i = 0; i < bus->nr_devices; i++) { | 255 | ssb_device_put(sdev); |
| 238 | dev = &(bus->devices[i]); | ||
| 239 | if (!dev->dev || | ||
| 240 | !dev->dev->driver || | ||
| 241 | !device_is_registered(dev->dev)) | ||
| 242 | continue; | ||
| 243 | drv = drv_to_ssb_drv(dev->dev->driver); | ||
| 244 | if (!drv) | ||
| 245 | continue; | 256 | continue; |
| 246 | err = drv->suspend(dev, state); | ||
| 247 | if (err) { | ||
| 248 | ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n", | ||
| 249 | dev_name(dev->dev)); | ||
| 250 | goto err_unwind; | ||
| 251 | } | 257 | } |
| 258 | sdrv->remove(sdev); | ||
| 259 | ctx->device_frozen[i] = 1; | ||
| 252 | } | 260 | } |
| 253 | 261 | ||
| 254 | return 0; | 262 | return 0; |
| 255 | err_unwind: | ||
| 256 | for (i--; i >= 0; i--) { | ||
| 257 | dev = &(bus->devices[i]); | ||
| 258 | if (!dev->dev || | ||
| 259 | !dev->dev->driver || | ||
| 260 | !device_is_registered(dev->dev)) | ||
| 261 | continue; | ||
| 262 | drv = drv_to_ssb_drv(dev->dev->driver); | ||
| 263 | if (!drv) | ||
| 264 | continue; | ||
| 265 | if (drv->resume) | ||
| 266 | drv->resume(dev); | ||
| 267 | } | ||
| 268 | return err; | ||
| 269 | } | 263 | } |
| 270 | 264 | ||
| 271 | int ssb_devices_thaw(struct ssb_bus *bus) | 265 | /** ssb_devices_thaw - Unfreeze all devices on the bus. |
| 266 | * | ||
| 267 | * This will re-attach the device drivers and re-init the devices. | ||
| 268 | * | ||
| 269 | * @ctx: The context structure from ssb_devices_freeze() | ||
| 270 | */ | ||
| 271 | int ssb_devices_thaw(struct ssb_freeze_context *ctx) | ||
| 272 | { | 272 | { |
| 273 | struct ssb_device *dev; | 273 | struct ssb_bus *bus = ctx->bus; |
| 274 | struct ssb_driver *drv; | 274 | struct ssb_device *sdev; |
| 275 | int err; | 275 | struct ssb_driver *sdrv; |
| 276 | int i; | 276 | unsigned int i; |
| 277 | int err, result = 0; | ||
| 277 | 278 | ||
| 278 | for (i = 0; i < bus->nr_devices; i++) { | 279 | for (i = 0; i < bus->nr_devices; i++) { |
| 279 | dev = &(bus->devices[i]); | 280 | if (!ctx->device_frozen[i]) |
| 280 | if (!dev->dev || | ||
| 281 | !dev->dev->driver || | ||
| 282 | !device_is_registered(dev->dev)) | ||
| 283 | continue; | 281 | continue; |
| 284 | drv = drv_to_ssb_drv(dev->dev->driver); | 282 | sdev = &bus->devices[i]; |
| 285 | if (!drv) | 283 | |
| 284 | if (SSB_WARN_ON(!sdev->dev || !sdev->dev->driver)) | ||
| 286 | continue; | 285 | continue; |
| 287 | if (SSB_WARN_ON(!drv->resume)) | 286 | sdrv = drv_to_ssb_drv(sdev->dev->driver); |
| 287 | if (SSB_WARN_ON(!sdrv || !sdrv->probe)) | ||
| 288 | continue; | 288 | continue; |
| 289 | err = drv->resume(dev); | 289 | |
| 290 | err = sdrv->probe(sdev, &sdev->id); | ||
| 290 | if (err) { | 291 | if (err) { |
| 291 | ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", | 292 | ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", |
| 292 | dev_name(dev->dev)); | 293 | dev_name(sdev->dev)); |
| 294 | result = err; | ||
| 293 | } | 295 | } |
| 296 | ssb_driver_put(sdrv); | ||
| 297 | ssb_device_put(sdev); | ||
| 294 | } | 298 | } |
| 295 | 299 | ||
| 296 | return 0; | 300 | return result; |
| 297 | } | 301 | } |
| 298 | #endif /* CONFIG_SSB_SPROM */ | 302 | #endif /* CONFIG_SSB_SPROM */ |
| 299 | 303 | ||
diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c index 8943015a3eef..580f779ecf49 100644 --- a/drivers/ssb/sprom.c +++ b/drivers/ssb/sprom.c | |||
| @@ -90,6 +90,7 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus, | |||
| 90 | u16 *sprom; | 90 | u16 *sprom; |
| 91 | int res = 0, err = -ENOMEM; | 91 | int res = 0, err = -ENOMEM; |
| 92 | size_t sprom_size_words = bus->sprom_size; | 92 | size_t sprom_size_words = bus->sprom_size; |
| 93 | struct ssb_freeze_context freeze; | ||
| 93 | 94 | ||
| 94 | sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); | 95 | sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); |
| 95 | if (!sprom) | 96 | if (!sprom) |
| @@ -111,18 +112,13 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus, | |||
| 111 | err = -ERESTARTSYS; | 112 | err = -ERESTARTSYS; |
| 112 | if (mutex_lock_interruptible(&bus->sprom_mutex)) | 113 | if (mutex_lock_interruptible(&bus->sprom_mutex)) |
| 113 | goto out_kfree; | 114 | goto out_kfree; |
| 114 | err = ssb_devices_freeze(bus); | 115 | err = ssb_devices_freeze(bus, &freeze); |
| 115 | if (err == -EOPNOTSUPP) { | ||
| 116 | ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. " | ||
| 117 | "No suspend support. Is CONFIG_PM enabled?\n"); | ||
| 118 | goto out_unlock; | ||
| 119 | } | ||
| 120 | if (err) { | 116 | if (err) { |
| 121 | ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); | 117 | ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); |
| 122 | goto out_unlock; | 118 | goto out_unlock; |
| 123 | } | 119 | } |
| 124 | res = sprom_write(bus, sprom); | 120 | res = sprom_write(bus, sprom); |
| 125 | err = ssb_devices_thaw(bus); | 121 | err = ssb_devices_thaw(&freeze); |
| 126 | if (err) | 122 | if (err) |
| 127 | ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); | 123 | ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); |
| 128 | out_unlock: | 124 | out_unlock: |
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 25433565dfda..56054be4d113 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h | |||
| @@ -176,13 +176,21 @@ extern const struct ssb_sprom *ssb_get_fallback_sprom(void); | |||
| 176 | 176 | ||
| 177 | /* core.c */ | 177 | /* core.c */ |
| 178 | extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); | 178 | extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); |
| 179 | extern int ssb_devices_freeze(struct ssb_bus *bus); | ||
| 180 | extern int ssb_devices_thaw(struct ssb_bus *bus); | ||
| 181 | extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); | 179 | extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); |
| 182 | int ssb_for_each_bus_call(unsigned long data, | 180 | int ssb_for_each_bus_call(unsigned long data, |
| 183 | int (*func)(struct ssb_bus *bus, unsigned long data)); | 181 | int (*func)(struct ssb_bus *bus, unsigned long data)); |
| 184 | extern struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev); | 182 | extern struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev); |
| 185 | 183 | ||
| 184 | struct ssb_freeze_context { | ||
| 185 | /* Pointer to the bus */ | ||
| 186 | struct ssb_bus *bus; | ||
| 187 | /* Boolean list to indicate whether a device is frozen on this bus. */ | ||
| 188 | bool device_frozen[SSB_MAX_NR_CORES]; | ||
| 189 | }; | ||
| 190 | extern int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx); | ||
| 191 | extern int ssb_devices_thaw(struct ssb_freeze_context *ctx); | ||
| 192 | |||
| 193 | |||
| 186 | 194 | ||
| 187 | /* b43_pci_bridge.c */ | 195 | /* b43_pci_bridge.c */ |
| 188 | #ifdef CONFIG_SSB_B43_PCI_BRIDGE | 196 | #ifdef CONFIG_SSB_B43_PCI_BRIDGE |
