diff options
| author | Shaohua Li <shaohua.li@intel.com> | 2005-08-10 22:37:39 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-09-05 19:03:12 -0400 |
| commit | ceaeade1f94c0a1c0163906ceeaede6493a9715e (patch) | |
| tree | fafff19d6510ce06e229b4cbacc1023f6845a8f7 | |
| parent | 91e49001b9a7fe5dc2fa5b56039fbca9aa638ccc (diff) | |
[PATCH] Driver core: hande sysdev suspend failure
This patch adds the return value check for sysdev suspend and does
restore in failure case. Send the patch to pm-list, but seems lost, so I
resend it.
Signed-off-by: Shaohua Li<shaohua.li@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | drivers/base/sys.c | 110 |
1 files changed, 85 insertions, 25 deletions
diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 214b96435409..3431eb6004c3 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c | |||
| @@ -288,6 +288,27 @@ void sysdev_shutdown(void) | |||
| 288 | up(&sysdev_drivers_lock); | 288 | up(&sysdev_drivers_lock); |
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | static void __sysdev_resume(struct sys_device *dev) | ||
| 292 | { | ||
| 293 | struct sysdev_class *cls = dev->cls; | ||
| 294 | struct sysdev_driver *drv; | ||
| 295 | |||
| 296 | /* First, call the class-specific one */ | ||
| 297 | if (cls->resume) | ||
| 298 | cls->resume(dev); | ||
| 299 | |||
| 300 | /* Call auxillary drivers next. */ | ||
| 301 | list_for_each_entry(drv, &cls->drivers, entry) { | ||
| 302 | if (drv->resume) | ||
| 303 | drv->resume(dev); | ||
| 304 | } | ||
| 305 | |||
| 306 | /* Call global drivers. */ | ||
| 307 | list_for_each_entry(drv, &sysdev_drivers, entry) { | ||
| 308 | if (drv->resume) | ||
| 309 | drv->resume(dev); | ||
| 310 | } | ||
| 311 | } | ||
| 291 | 312 | ||
| 292 | /** | 313 | /** |
| 293 | * sysdev_suspend - Suspend all system devices. | 314 | * sysdev_suspend - Suspend all system devices. |
| @@ -305,38 +326,93 @@ void sysdev_shutdown(void) | |||
| 305 | int sysdev_suspend(pm_message_t state) | 326 | int sysdev_suspend(pm_message_t state) |
| 306 | { | 327 | { |
| 307 | struct sysdev_class * cls; | 328 | struct sysdev_class * cls; |
| 329 | struct sys_device *sysdev, *err_dev; | ||
| 330 | struct sysdev_driver *drv, *err_drv; | ||
| 331 | int ret; | ||
| 308 | 332 | ||
| 309 | pr_debug("Suspending System Devices\n"); | 333 | pr_debug("Suspending System Devices\n"); |
| 310 | 334 | ||
| 311 | list_for_each_entry_reverse(cls, &system_subsys.kset.list, | 335 | list_for_each_entry_reverse(cls, &system_subsys.kset.list, |
| 312 | kset.kobj.entry) { | 336 | kset.kobj.entry) { |
| 313 | struct sys_device * sysdev; | ||
| 314 | 337 | ||
| 315 | pr_debug("Suspending type '%s':\n", | 338 | pr_debug("Suspending type '%s':\n", |
| 316 | kobject_name(&cls->kset.kobj)); | 339 | kobject_name(&cls->kset.kobj)); |
| 317 | 340 | ||
| 318 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { | 341 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { |
| 319 | struct sysdev_driver * drv; | ||
| 320 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); | 342 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); |
| 321 | 343 | ||
| 322 | /* Call global drivers first. */ | 344 | /* Call global drivers first. */ |
| 323 | list_for_each_entry(drv, &sysdev_drivers, entry) { | 345 | list_for_each_entry(drv, &sysdev_drivers, entry) { |
| 324 | if (drv->suspend) | 346 | if (drv->suspend) { |
| 325 | drv->suspend(sysdev, state); | 347 | ret = drv->suspend(sysdev, state); |
| 348 | if (ret) | ||
| 349 | goto gbl_driver; | ||
| 350 | } | ||
| 326 | } | 351 | } |
| 327 | 352 | ||
| 328 | /* Call auxillary drivers next. */ | 353 | /* Call auxillary drivers next. */ |
| 329 | list_for_each_entry(drv, &cls->drivers, entry) { | 354 | list_for_each_entry(drv, &cls->drivers, entry) { |
| 330 | if (drv->suspend) | 355 | if (drv->suspend) { |
| 331 | drv->suspend(sysdev, state); | 356 | ret = drv->suspend(sysdev, state); |
| 357 | if (ret) | ||
| 358 | goto aux_driver; | ||
| 359 | } | ||
| 332 | } | 360 | } |
| 333 | 361 | ||
| 334 | /* Now call the generic one */ | 362 | /* Now call the generic one */ |
| 335 | if (cls->suspend) | 363 | if (cls->suspend) { |
| 336 | cls->suspend(sysdev, state); | 364 | ret = cls->suspend(sysdev, state); |
| 365 | if (ret) | ||
| 366 | goto cls_driver; | ||
| 367 | } | ||
| 337 | } | 368 | } |
| 338 | } | 369 | } |
| 339 | return 0; | 370 | return 0; |
| 371 | /* resume current sysdev */ | ||
| 372 | cls_driver: | ||
| 373 | drv = NULL; | ||
| 374 | printk(KERN_ERR "Class suspend failed for %s\n", | ||
| 375 | kobject_name(&sysdev->kobj)); | ||
| 376 | |||
| 377 | aux_driver: | ||
| 378 | if (drv) | ||
| 379 | printk(KERN_ERR "Class driver suspend failed for %s\n", | ||
| 380 | kobject_name(&sysdev->kobj)); | ||
| 381 | list_for_each_entry(err_drv, &cls->drivers, entry) { | ||
| 382 | if (err_drv == drv) | ||
| 383 | break; | ||
| 384 | if (err_drv->resume) | ||
| 385 | err_drv->resume(sysdev); | ||
| 386 | } | ||
| 387 | drv = NULL; | ||
| 388 | |||
| 389 | gbl_driver: | ||
| 390 | if (drv) | ||
| 391 | printk(KERN_ERR "sysdev driver suspend failed for %s\n", | ||
| 392 | kobject_name(&sysdev->kobj)); | ||
| 393 | list_for_each_entry(err_drv, &sysdev_drivers, entry) { | ||
| 394 | if (err_drv == drv) | ||
| 395 | break; | ||
| 396 | if (err_drv->resume) | ||
| 397 | err_drv->resume(sysdev); | ||
| 398 | } | ||
| 399 | /* resume other sysdevs in current class */ | ||
| 400 | list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { | ||
| 401 | if (err_dev == sysdev) | ||
| 402 | break; | ||
| 403 | pr_debug(" %s\n", kobject_name(&err_dev->kobj)); | ||
| 404 | __sysdev_resume(err_dev); | ||
| 405 | } | ||
| 406 | |||
| 407 | /* resume other classes */ | ||
| 408 | list_for_each_entry_continue(cls, &system_subsys.kset.list, | ||
| 409 | kset.kobj.entry) { | ||
| 410 | list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { | ||
| 411 | pr_debug(" %s\n", kobject_name(&err_dev->kobj)); | ||
| 412 | __sysdev_resume(err_dev); | ||
| 413 | } | ||
| 414 | } | ||
| 415 | return ret; | ||
| 340 | } | 416 | } |
| 341 | 417 | ||
| 342 | 418 | ||
| @@ -362,25 +438,9 @@ int sysdev_resume(void) | |||
| 362 | kobject_name(&cls->kset.kobj)); | 438 | kobject_name(&cls->kset.kobj)); |
| 363 | 439 | ||
| 364 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { | 440 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { |
| 365 | struct sysdev_driver * drv; | ||
| 366 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); | 441 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); |
| 367 | 442 | ||
| 368 | /* First, call the class-specific one */ | 443 | __sysdev_resume(sysdev); |
| 369 | if (cls->resume) | ||
| 370 | cls->resume(sysdev); | ||
| 371 | |||
| 372 | /* Call auxillary drivers next. */ | ||
| 373 | list_for_each_entry(drv, &cls->drivers, entry) { | ||
| 374 | if (drv->resume) | ||
| 375 | drv->resume(sysdev); | ||
| 376 | } | ||
| 377 | |||
| 378 | /* Call global drivers. */ | ||
| 379 | list_for_each_entry(drv, &sysdev_drivers, entry) { | ||
| 380 | if (drv->resume) | ||
| 381 | drv->resume(sysdev); | ||
| 382 | } | ||
| 383 | |||
| 384 | } | 444 | } |
| 385 | } | 445 | } |
| 386 | return 0; | 446 | return 0; |
