aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ssb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ssb')
-rw-r--r--drivers/ssb/main.c126
-rw-r--r--drivers/ssb/sprom.c10
-rw-r--r--drivers/ssb/ssb_private.h12
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
143static 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
150static inline void ssb_driver_put(struct ssb_driver *drv)
151{
152 if (drv)
153 put_driver(&drv->drv);
154}
155
143static int ssb_device_resume(struct device *dev) 156static 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)
210EXPORT_SYMBOL(ssb_bus_suspend); 223EXPORT_SYMBOL(ssb_bus_suspend);
211 224
212#ifdef CONFIG_SSB_SPROM 225#ifdef CONFIG_SSB_SPROM
213int 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 */
235int 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;
255err_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
271int 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 */
271int 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");
128out_unlock: 124out_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 */
178extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); 178extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m);
179extern int ssb_devices_freeze(struct ssb_bus *bus);
180extern int ssb_devices_thaw(struct ssb_bus *bus);
181extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); 179extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev);
182int ssb_for_each_bus_call(unsigned long data, 180int 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));
184extern struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev); 182extern struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev);
185 183
184struct 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};
190extern int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx);
191extern 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