diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/Kconfig | 7 | ||||
-rw-r--r-- | drivers/base/base.h | 2 | ||||
-rw-r--r-- | drivers/base/sys.c | 202 |
3 files changed, 2 insertions, 209 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index e9e5238f3106..d57e8d0fb823 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig | |||
@@ -168,11 +168,4 @@ config SYS_HYPERVISOR | |||
168 | bool | 168 | bool |
169 | default n | 169 | default n |
170 | 170 | ||
171 | config ARCH_NO_SYSDEV_OPS | ||
172 | bool | ||
173 | ---help--- | ||
174 | To be selected by architectures that don't use sysdev class or | ||
175 | sysdev driver power management (suspend/resume) and shutdown | ||
176 | operations. | ||
177 | |||
178 | endmenu | 171 | endmenu |
diff --git a/drivers/base/base.h b/drivers/base/base.h index 19f49e41ce5d..a34dca0ad041 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h | |||
@@ -111,8 +111,6 @@ static inline int driver_match_device(struct device_driver *drv, | |||
111 | return drv->bus->match ? drv->bus->match(dev, drv) : 1; | 111 | return drv->bus->match ? drv->bus->match(dev, drv) : 1; |
112 | } | 112 | } |
113 | 113 | ||
114 | extern void sysdev_shutdown(void); | ||
115 | |||
116 | extern char *make_class_name(const char *name, struct kobject *kobj); | 114 | extern char *make_class_name(const char *name, struct kobject *kobj); |
117 | 115 | ||
118 | extern int devres_release_all(struct device *dev); | 116 | extern int devres_release_all(struct device *dev); |
diff --git a/drivers/base/sys.c b/drivers/base/sys.c index acde9b5ee131..9dff77bfe1e3 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c | |||
@@ -328,203 +328,8 @@ void sysdev_unregister(struct sys_device *sysdev) | |||
328 | kobject_put(&sysdev->kobj); | 328 | kobject_put(&sysdev->kobj); |
329 | } | 329 | } |
330 | 330 | ||
331 | 331 | EXPORT_SYMBOL_GPL(sysdev_register); | |
332 | #ifndef CONFIG_ARCH_NO_SYSDEV_OPS | 332 | EXPORT_SYMBOL_GPL(sysdev_unregister); |
333 | /** | ||
334 | * sysdev_shutdown - Shut down all system devices. | ||
335 | * | ||
336 | * Loop over each class of system devices, and the devices in each | ||
337 | * of those classes. For each device, we call the shutdown method for | ||
338 | * each driver registered for the device - the auxiliaries, | ||
339 | * and the class driver. | ||
340 | * | ||
341 | * Note: The list is iterated in reverse order, so that we shut down | ||
342 | * child devices before we shut down their parents. The list ordering | ||
343 | * is guaranteed by virtue of the fact that child devices are registered | ||
344 | * after their parents. | ||
345 | */ | ||
346 | void sysdev_shutdown(void) | ||
347 | { | ||
348 | struct sysdev_class *cls; | ||
349 | |||
350 | pr_debug("Shutting Down System Devices\n"); | ||
351 | |||
352 | mutex_lock(&sysdev_drivers_lock); | ||
353 | list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { | ||
354 | struct sys_device *sysdev; | ||
355 | |||
356 | pr_debug("Shutting down type '%s':\n", | ||
357 | kobject_name(&cls->kset.kobj)); | ||
358 | |||
359 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { | ||
360 | struct sysdev_driver *drv; | ||
361 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); | ||
362 | |||
363 | /* Call auxiliary drivers first */ | ||
364 | list_for_each_entry(drv, &cls->drivers, entry) { | ||
365 | if (drv->shutdown) | ||
366 | drv->shutdown(sysdev); | ||
367 | } | ||
368 | |||
369 | /* Now call the generic one */ | ||
370 | if (cls->shutdown) | ||
371 | cls->shutdown(sysdev); | ||
372 | } | ||
373 | } | ||
374 | mutex_unlock(&sysdev_drivers_lock); | ||
375 | } | ||
376 | |||
377 | static void __sysdev_resume(struct sys_device *dev) | ||
378 | { | ||
379 | struct sysdev_class *cls = dev->cls; | ||
380 | struct sysdev_driver *drv; | ||
381 | |||
382 | /* First, call the class-specific one */ | ||
383 | if (cls->resume) | ||
384 | cls->resume(dev); | ||
385 | WARN_ONCE(!irqs_disabled(), | ||
386 | "Interrupts enabled after %pF\n", cls->resume); | ||
387 | |||
388 | /* Call auxiliary drivers next. */ | ||
389 | list_for_each_entry(drv, &cls->drivers, entry) { | ||
390 | if (drv->resume) | ||
391 | drv->resume(dev); | ||
392 | WARN_ONCE(!irqs_disabled(), | ||
393 | "Interrupts enabled after %pF\n", drv->resume); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | /** | ||
398 | * sysdev_suspend - Suspend all system devices. | ||
399 | * @state: Power state to enter. | ||
400 | * | ||
401 | * We perform an almost identical operation as sysdev_shutdown() | ||
402 | * above, though calling ->suspend() instead. Interrupts are disabled | ||
403 | * when this called. Devices are responsible for both saving state and | ||
404 | * quiescing or powering down the device. | ||
405 | * | ||
406 | * This is only called by the device PM core, so we let them handle | ||
407 | * all synchronization. | ||
408 | */ | ||
409 | int sysdev_suspend(pm_message_t state) | ||
410 | { | ||
411 | struct sysdev_class *cls; | ||
412 | struct sys_device *sysdev, *err_dev; | ||
413 | struct sysdev_driver *drv, *err_drv; | ||
414 | int ret; | ||
415 | |||
416 | pr_debug("Checking wake-up interrupts\n"); | ||
417 | |||
418 | /* Return error code if there are any wake-up interrupts pending */ | ||
419 | ret = check_wakeup_irqs(); | ||
420 | if (ret) | ||
421 | return ret; | ||
422 | |||
423 | WARN_ONCE(!irqs_disabled(), | ||
424 | "Interrupts enabled while suspending system devices\n"); | ||
425 | |||
426 | pr_debug("Suspending System Devices\n"); | ||
427 | |||
428 | list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { | ||
429 | pr_debug("Suspending type '%s':\n", | ||
430 | kobject_name(&cls->kset.kobj)); | ||
431 | |||
432 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { | ||
433 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); | ||
434 | |||
435 | /* Call auxiliary drivers first */ | ||
436 | list_for_each_entry(drv, &cls->drivers, entry) { | ||
437 | if (drv->suspend) { | ||
438 | ret = drv->suspend(sysdev, state); | ||
439 | if (ret) | ||
440 | goto aux_driver; | ||
441 | } | ||
442 | WARN_ONCE(!irqs_disabled(), | ||
443 | "Interrupts enabled after %pF\n", | ||
444 | drv->suspend); | ||
445 | } | ||
446 | |||
447 | /* Now call the generic one */ | ||
448 | if (cls->suspend) { | ||
449 | ret = cls->suspend(sysdev, state); | ||
450 | if (ret) | ||
451 | goto cls_driver; | ||
452 | WARN_ONCE(!irqs_disabled(), | ||
453 | "Interrupts enabled after %pF\n", | ||
454 | cls->suspend); | ||
455 | } | ||
456 | } | ||
457 | } | ||
458 | return 0; | ||
459 | /* resume current sysdev */ | ||
460 | cls_driver: | ||
461 | drv = NULL; | ||
462 | printk(KERN_ERR "Class suspend failed for %s: %d\n", | ||
463 | kobject_name(&sysdev->kobj), ret); | ||
464 | |||
465 | aux_driver: | ||
466 | if (drv) | ||
467 | printk(KERN_ERR "Class driver suspend failed for %s: %d\n", | ||
468 | kobject_name(&sysdev->kobj), ret); | ||
469 | list_for_each_entry(err_drv, &cls->drivers, entry) { | ||
470 | if (err_drv == drv) | ||
471 | break; | ||
472 | if (err_drv->resume) | ||
473 | err_drv->resume(sysdev); | ||
474 | } | ||
475 | |||
476 | /* resume other sysdevs in current class */ | ||
477 | list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { | ||
478 | if (err_dev == sysdev) | ||
479 | break; | ||
480 | pr_debug(" %s\n", kobject_name(&err_dev->kobj)); | ||
481 | __sysdev_resume(err_dev); | ||
482 | } | ||
483 | |||
484 | /* resume other classes */ | ||
485 | list_for_each_entry_continue(cls, &system_kset->list, kset.kobj.entry) { | ||
486 | list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { | ||
487 | pr_debug(" %s\n", kobject_name(&err_dev->kobj)); | ||
488 | __sysdev_resume(err_dev); | ||
489 | } | ||
490 | } | ||
491 | return ret; | ||
492 | } | ||
493 | EXPORT_SYMBOL_GPL(sysdev_suspend); | ||
494 | |||
495 | /** | ||
496 | * sysdev_resume - Bring system devices back to life. | ||
497 | * | ||
498 | * Similar to sysdev_suspend(), but we iterate the list forwards | ||
499 | * to guarantee that parent devices are resumed before their children. | ||
500 | * | ||
501 | * Note: Interrupts are disabled when called. | ||
502 | */ | ||
503 | int sysdev_resume(void) | ||
504 | { | ||
505 | struct sysdev_class *cls; | ||
506 | |||
507 | WARN_ONCE(!irqs_disabled(), | ||
508 | "Interrupts enabled while resuming system devices\n"); | ||
509 | |||
510 | pr_debug("Resuming System Devices\n"); | ||
511 | |||
512 | list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) { | ||
513 | struct sys_device *sysdev; | ||
514 | |||
515 | pr_debug("Resuming type '%s':\n", | ||
516 | kobject_name(&cls->kset.kobj)); | ||
517 | |||
518 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { | ||
519 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); | ||
520 | |||
521 | __sysdev_resume(sysdev); | ||
522 | } | ||
523 | } | ||
524 | return 0; | ||
525 | } | ||
526 | EXPORT_SYMBOL_GPL(sysdev_resume); | ||
527 | #endif /* CONFIG_ARCH_NO_SYSDEV_OPS */ | ||
528 | 333 | ||
529 | int __init system_bus_init(void) | 334 | int __init system_bus_init(void) |
530 | { | 335 | { |
@@ -534,9 +339,6 @@ int __init system_bus_init(void) | |||
534 | return 0; | 339 | return 0; |
535 | } | 340 | } |
536 | 341 | ||
537 | EXPORT_SYMBOL_GPL(sysdev_register); | ||
538 | EXPORT_SYMBOL_GPL(sysdev_unregister); | ||
539 | |||
540 | #define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr) | 342 | #define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr) |
541 | 343 | ||
542 | ssize_t sysdev_store_ulong(struct sys_device *sysdev, | 344 | ssize_t sysdev_store_ulong(struct sys_device *sysdev, |