aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ssb/main.c
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2009-11-23 14:12:13 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-23 17:05:41 -0500
commit3ba6018aa314559c5867138a8173b068268a70db (patch)
tree6da72b198ec84c40a52b21545b5be3a4b1bd4c74 /drivers/ssb/main.c
parent77593ae28c4c134eaf28ef34ecac3cd4464ecd6e (diff)
ssb: Fix SPROM writing
The SPROM writing routines were broken since we rewrote the suspend handling on wireless devices, because SPROM writing depended on suspend. This patch changes it and freezes devices with the driver remove(), probe() callbacks instead. This also simplifies the whole logics a lot. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/ssb/main.c')
-rw-r--r--drivers/ssb/main.c126
1 files changed, 65 insertions, 61 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