diff options
-rw-r--r-- | Documentation/power/runtime_pm.txt | 21 | ||||
-rw-r--r-- | drivers/base/power/main.c | 35 |
2 files changed, 44 insertions, 12 deletions
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index 0ec3d610fc9a..d50dd1ab590d 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt | |||
@@ -583,6 +583,13 @@ this is: | |||
583 | pm_runtime_set_active(dev); | 583 | pm_runtime_set_active(dev); |
584 | pm_runtime_enable(dev); | 584 | pm_runtime_enable(dev); |
585 | 585 | ||
586 | The PM core always increments the run-time usage counter before calling the | ||
587 | ->suspend() callback and decrements it after calling the ->resume() callback. | ||
588 | Hence disabling run-time PM temporarily like this will not cause any runtime | ||
589 | suspend attempts to be permanently lost. If the usage count goes to zero | ||
590 | following the return of the ->resume() callback, the ->runtime_idle() callback | ||
591 | will be invoked as usual. | ||
592 | |||
586 | On some systems, however, system sleep is not entered through a global firmware | 593 | On some systems, however, system sleep is not entered through a global firmware |
587 | or hardware operation. Instead, all hardware components are put into low-power | 594 | or hardware operation. Instead, all hardware components are put into low-power |
588 | states directly by the kernel in a coordinated way. Then, the system sleep | 595 | states directly by the kernel in a coordinated way. Then, the system sleep |
@@ -595,6 +602,20 @@ place (in particular, if the system is not waking up from hibernation), it may | |||
595 | be more efficient to leave the devices that had been suspended before the system | 602 | be more efficient to leave the devices that had been suspended before the system |
596 | suspend began in the suspended state. | 603 | suspend began in the suspended state. |
597 | 604 | ||
605 | The PM core does its best to reduce the probability of race conditions between | ||
606 | the runtime PM and system suspend/resume (and hibernation) callbacks by carrying | ||
607 | out the following operations: | ||
608 | |||
609 | * During system suspend it calls pm_runtime_get_noresume() and | ||
610 | pm_runtime_barrier() for every device right before executing the | ||
611 | subsystem-level .suspend() callback for it. In addition to that it calls | ||
612 | pm_runtime_disable() for every device right after executing the | ||
613 | subsystem-level .suspend() callback for it. | ||
614 | |||
615 | * During system resume it calls pm_runtime_enable() and pm_runtime_put_sync() | ||
616 | for every device right before and right after executing the subsystem-level | ||
617 | .resume() callback for it, respectively. | ||
618 | |||
598 | 7. Generic subsystem callbacks | 619 | 7. Generic subsystem callbacks |
599 | 620 | ||
600 | Subsystems may wish to conserve code space by using the set of generic power | 621 | Subsystems may wish to conserve code space by using the set of generic power |
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 85b591a5429a..a85459126bc6 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -505,6 +505,7 @@ static int legacy_resume(struct device *dev, int (*cb)(struct device *dev)) | |||
505 | static int device_resume(struct device *dev, pm_message_t state, bool async) | 505 | static int device_resume(struct device *dev, pm_message_t state, bool async) |
506 | { | 506 | { |
507 | int error = 0; | 507 | int error = 0; |
508 | bool put = false; | ||
508 | 509 | ||
509 | TRACE_DEVICE(dev); | 510 | TRACE_DEVICE(dev); |
510 | TRACE_RESUME(0); | 511 | TRACE_RESUME(0); |
@@ -521,6 +522,9 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
521 | if (!dev->power.is_suspended) | 522 | if (!dev->power.is_suspended) |
522 | goto Unlock; | 523 | goto Unlock; |
523 | 524 | ||
525 | pm_runtime_enable(dev); | ||
526 | put = true; | ||
527 | |||
524 | if (dev->pm_domain) { | 528 | if (dev->pm_domain) { |
525 | pm_dev_dbg(dev, state, "power domain "); | 529 | pm_dev_dbg(dev, state, "power domain "); |
526 | error = pm_op(dev, &dev->pm_domain->ops, state); | 530 | error = pm_op(dev, &dev->pm_domain->ops, state); |
@@ -563,6 +567,10 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
563 | complete_all(&dev->power.completion); | 567 | complete_all(&dev->power.completion); |
564 | 568 | ||
565 | TRACE_RESUME(error); | 569 | TRACE_RESUME(error); |
570 | |||
571 | if (put) | ||
572 | pm_runtime_put_sync(dev); | ||
573 | |||
566 | return error; | 574 | return error; |
567 | } | 575 | } |
568 | 576 | ||
@@ -843,16 +851,22 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
843 | int error = 0; | 851 | int error = 0; |
844 | 852 | ||
845 | dpm_wait_for_children(dev, async); | 853 | dpm_wait_for_children(dev, async); |
846 | device_lock(dev); | ||
847 | 854 | ||
848 | if (async_error) | 855 | if (async_error) |
849 | goto Unlock; | 856 | return 0; |
857 | |||
858 | pm_runtime_get_noresume(dev); | ||
859 | if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) | ||
860 | pm_wakeup_event(dev, 0); | ||
850 | 861 | ||
851 | if (pm_wakeup_pending()) { | 862 | if (pm_wakeup_pending()) { |
863 | pm_runtime_put_sync(dev); | ||
852 | async_error = -EBUSY; | 864 | async_error = -EBUSY; |
853 | goto Unlock; | 865 | return 0; |
854 | } | 866 | } |
855 | 867 | ||
868 | device_lock(dev); | ||
869 | |||
856 | if (dev->pm_domain) { | 870 | if (dev->pm_domain) { |
857 | pm_dev_dbg(dev, state, "power domain "); | 871 | pm_dev_dbg(dev, state, "power domain "); |
858 | error = pm_op(dev, &dev->pm_domain->ops, state); | 872 | error = pm_op(dev, &dev->pm_domain->ops, state); |
@@ -890,12 +904,15 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
890 | End: | 904 | End: |
891 | dev->power.is_suspended = !error; | 905 | dev->power.is_suspended = !error; |
892 | 906 | ||
893 | Unlock: | ||
894 | device_unlock(dev); | 907 | device_unlock(dev); |
895 | complete_all(&dev->power.completion); | 908 | complete_all(&dev->power.completion); |
896 | 909 | ||
897 | if (error) | 910 | if (error) { |
911 | pm_runtime_put_sync(dev); | ||
898 | async_error = error; | 912 | async_error = error; |
913 | } else if (dev->power.is_suspended) { | ||
914 | __pm_runtime_disable(dev, false); | ||
915 | } | ||
899 | 916 | ||
900 | return error; | 917 | return error; |
901 | } | 918 | } |
@@ -1035,13 +1052,7 @@ int dpm_prepare(pm_message_t state) | |||
1035 | get_device(dev); | 1052 | get_device(dev); |
1036 | mutex_unlock(&dpm_list_mtx); | 1053 | mutex_unlock(&dpm_list_mtx); |
1037 | 1054 | ||
1038 | pm_runtime_get_noresume(dev); | 1055 | error = device_prepare(dev, state); |
1039 | if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) | ||
1040 | pm_wakeup_event(dev, 0); | ||
1041 | |||
1042 | pm_runtime_put_sync(dev); | ||
1043 | error = pm_wakeup_pending() ? | ||
1044 | -EBUSY : device_prepare(dev, state); | ||
1045 | 1056 | ||
1046 | mutex_lock(&dpm_list_mtx); | 1057 | mutex_lock(&dpm_list_mtx); |
1047 | if (error) { | 1058 | if (error) { |