aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/runtime.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/power/runtime.c')
-rw-r--r--drivers/base/power/runtime.c123
1 files changed, 108 insertions, 15 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 846d89e3d122..626dd147b75f 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -85,6 +85,19 @@ static int __pm_runtime_idle(struct device *dev)
85 dev->bus->pm->runtime_idle(dev); 85 dev->bus->pm->runtime_idle(dev);
86 86
87 spin_lock_irq(&dev->power.lock); 87 spin_lock_irq(&dev->power.lock);
88 } else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {
89 spin_unlock_irq(&dev->power.lock);
90
91 dev->type->pm->runtime_idle(dev);
92
93 spin_lock_irq(&dev->power.lock);
94 } else if (dev->class && dev->class->pm
95 && dev->class->pm->runtime_idle) {
96 spin_unlock_irq(&dev->power.lock);
97
98 dev->class->pm->runtime_idle(dev);
99
100 spin_lock_irq(&dev->power.lock);
88 } 101 }
89 102
90 dev->power.idle_notification = false; 103 dev->power.idle_notification = false;
@@ -185,6 +198,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
185 } 198 }
186 199
187 dev->power.runtime_status = RPM_SUSPENDING; 200 dev->power.runtime_status = RPM_SUSPENDING;
201 dev->power.deferred_resume = false;
188 202
189 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) { 203 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
190 spin_unlock_irq(&dev->power.lock); 204 spin_unlock_irq(&dev->power.lock);
@@ -193,6 +207,22 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
193 207
194 spin_lock_irq(&dev->power.lock); 208 spin_lock_irq(&dev->power.lock);
195 dev->power.runtime_error = retval; 209 dev->power.runtime_error = retval;
210 } else if (dev->type && dev->type->pm
211 && dev->type->pm->runtime_suspend) {
212 spin_unlock_irq(&dev->power.lock);
213
214 retval = dev->type->pm->runtime_suspend(dev);
215
216 spin_lock_irq(&dev->power.lock);
217 dev->power.runtime_error = retval;
218 } else if (dev->class && dev->class->pm
219 && dev->class->pm->runtime_suspend) {
220 spin_unlock_irq(&dev->power.lock);
221
222 retval = dev->class->pm->runtime_suspend(dev);
223
224 spin_lock_irq(&dev->power.lock);
225 dev->power.runtime_error = retval;
196 } else { 226 } else {
197 retval = -ENOSYS; 227 retval = -ENOSYS;
198 } 228 }
@@ -200,7 +230,6 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
200 if (retval) { 230 if (retval) {
201 dev->power.runtime_status = RPM_ACTIVE; 231 dev->power.runtime_status = RPM_ACTIVE;
202 pm_runtime_cancel_pending(dev); 232 pm_runtime_cancel_pending(dev);
203 dev->power.deferred_resume = false;
204 233
205 if (retval == -EAGAIN || retval == -EBUSY) { 234 if (retval == -EAGAIN || retval == -EBUSY) {
206 notify = true; 235 notify = true;
@@ -217,7 +246,6 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
217 wake_up_all(&dev->power.wait_queue); 246 wake_up_all(&dev->power.wait_queue);
218 247
219 if (dev->power.deferred_resume) { 248 if (dev->power.deferred_resume) {
220 dev->power.deferred_resume = false;
221 __pm_runtime_resume(dev, false); 249 __pm_runtime_resume(dev, false);
222 retval = -EAGAIN; 250 retval = -EAGAIN;
223 goto out; 251 goto out;
@@ -360,6 +388,22 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
360 388
361 spin_lock_irq(&dev->power.lock); 389 spin_lock_irq(&dev->power.lock);
362 dev->power.runtime_error = retval; 390 dev->power.runtime_error = retval;
391 } else if (dev->type && dev->type->pm
392 && dev->type->pm->runtime_resume) {
393 spin_unlock_irq(&dev->power.lock);
394
395 retval = dev->type->pm->runtime_resume(dev);
396
397 spin_lock_irq(&dev->power.lock);
398 dev->power.runtime_error = retval;
399 } else if (dev->class && dev->class->pm
400 && dev->class->pm->runtime_resume) {
401 spin_unlock_irq(&dev->power.lock);
402
403 retval = dev->class->pm->runtime_resume(dev);
404
405 spin_lock_irq(&dev->power.lock);
406 dev->power.runtime_error = retval;
363 } else { 407 } else {
364 retval = -ENOSYS; 408 retval = -ENOSYS;
365 } 409 }
@@ -626,6 +670,8 @@ int pm_schedule_suspend(struct device *dev, unsigned int delay)
626 goto out; 670 goto out;
627 671
628 dev->power.timer_expires = jiffies + msecs_to_jiffies(delay); 672 dev->power.timer_expires = jiffies + msecs_to_jiffies(delay);
673 if (!dev->power.timer_expires)
674 dev->power.timer_expires = 1;
629 mod_timer(&dev->power.suspend_timer, dev->power.timer_expires); 675 mod_timer(&dev->power.suspend_timer, dev->power.timer_expires);
630 676
631 out: 677 out:
@@ -659,13 +705,17 @@ static int __pm_request_resume(struct device *dev)
659 705
660 pm_runtime_deactivate_timer(dev); 706 pm_runtime_deactivate_timer(dev);
661 707
708 if (dev->power.runtime_status == RPM_SUSPENDING) {
709 dev->power.deferred_resume = true;
710 return retval;
711 }
662 if (dev->power.request_pending) { 712 if (dev->power.request_pending) {
663 /* If non-resume request is pending, we can overtake it. */ 713 /* If non-resume request is pending, we can overtake it. */
664 dev->power.request = retval ? RPM_REQ_NONE : RPM_REQ_RESUME; 714 dev->power.request = retval ? RPM_REQ_NONE : RPM_REQ_RESUME;
665 return retval; 715 return retval;
666 } else if (retval) {
667 return retval;
668 } 716 }
717 if (retval)
718 return retval;
669 719
670 dev->power.request = RPM_REQ_RESUME; 720 dev->power.request = RPM_REQ_RESUME;
671 dev->power.request_pending = true; 721 dev->power.request_pending = true;
@@ -696,15 +746,15 @@ EXPORT_SYMBOL_GPL(pm_request_resume);
696 * @dev: Device to handle. 746 * @dev: Device to handle.
697 * @sync: If set and the device is suspended, resume it synchronously. 747 * @sync: If set and the device is suspended, resume it synchronously.
698 * 748 *
699 * Increment the usage count of the device and if it was zero previously, 749 * Increment the usage count of the device and resume it or submit a resume
700 * resume it or submit a resume request for it, depending on the value of @sync. 750 * request for it, depending on the value of @sync.
701 */ 751 */
702int __pm_runtime_get(struct device *dev, bool sync) 752int __pm_runtime_get(struct device *dev, bool sync)
703{ 753{
704 int retval = 1; 754 int retval;
705 755
706 if (atomic_add_return(1, &dev->power.usage_count) == 1) 756 atomic_inc(&dev->power.usage_count);
707 retval = sync ? pm_runtime_resume(dev) : pm_request_resume(dev); 757 retval = sync ? pm_runtime_resume(dev) : pm_request_resume(dev);
708 758
709 return retval; 759 return retval;
710} 760}
@@ -777,7 +827,7 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
777 } 827 }
778 828
779 if (parent) { 829 if (parent) {
780 spin_lock(&parent->power.lock); 830 spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING);
781 831
782 /* 832 /*
783 * It is invalid to put an active child under a parent that is 833 * It is invalid to put an active child under a parent that is
@@ -786,12 +836,10 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
786 */ 836 */
787 if (!parent->power.disable_depth 837 if (!parent->power.disable_depth
788 && !parent->power.ignore_children 838 && !parent->power.ignore_children
789 && parent->power.runtime_status != RPM_ACTIVE) { 839 && parent->power.runtime_status != RPM_ACTIVE)
790 error = -EBUSY; 840 error = -EBUSY;
791 } else { 841 else if (dev->power.runtime_status == RPM_SUSPENDED)
792 if (dev->power.runtime_status == RPM_SUSPENDED) 842 atomic_inc(&parent->power.child_count);
793 atomic_inc(&parent->power.child_count);
794 }
795 843
796 spin_unlock(&parent->power.lock); 844 spin_unlock(&parent->power.lock);
797 845
@@ -963,6 +1011,50 @@ void pm_runtime_enable(struct device *dev)
963EXPORT_SYMBOL_GPL(pm_runtime_enable); 1011EXPORT_SYMBOL_GPL(pm_runtime_enable);
964 1012
965/** 1013/**
1014 * pm_runtime_forbid - Block run-time PM of a device.
1015 * @dev: Device to handle.
1016 *
1017 * Increase the device's usage count and clear its power.runtime_auto flag,
1018 * so that it cannot be suspended at run time until pm_runtime_allow() is called
1019 * for it.
1020 */
1021void pm_runtime_forbid(struct device *dev)
1022{
1023 spin_lock_irq(&dev->power.lock);
1024 if (!dev->power.runtime_auto)
1025 goto out;
1026
1027 dev->power.runtime_auto = false;
1028 atomic_inc(&dev->power.usage_count);
1029 __pm_runtime_resume(dev, false);
1030
1031 out:
1032 spin_unlock_irq(&dev->power.lock);
1033}
1034EXPORT_SYMBOL_GPL(pm_runtime_forbid);
1035
1036/**
1037 * pm_runtime_allow - Unblock run-time PM of a device.
1038 * @dev: Device to handle.
1039 *
1040 * Decrease the device's usage count and set its power.runtime_auto flag.
1041 */
1042void pm_runtime_allow(struct device *dev)
1043{
1044 spin_lock_irq(&dev->power.lock);
1045 if (dev->power.runtime_auto)
1046 goto out;
1047
1048 dev->power.runtime_auto = true;
1049 if (atomic_dec_and_test(&dev->power.usage_count))
1050 __pm_runtime_idle(dev);
1051
1052 out:
1053 spin_unlock_irq(&dev->power.lock);
1054}
1055EXPORT_SYMBOL_GPL(pm_runtime_allow);
1056
1057/**
966 * pm_runtime_init - Initialize run-time PM fields in given device object. 1058 * pm_runtime_init - Initialize run-time PM fields in given device object.
967 * @dev: Device object to initialize. 1059 * @dev: Device object to initialize.
968 */ 1060 */
@@ -980,6 +1072,7 @@ void pm_runtime_init(struct device *dev)
980 1072
981 atomic_set(&dev->power.child_count, 0); 1073 atomic_set(&dev->power.child_count, 0);
982 pm_suspend_ignore_children(dev, false); 1074 pm_suspend_ignore_children(dev, false);
1075 dev->power.runtime_auto = true;
983 1076
984 dev->power.request_pending = false; 1077 dev->power.request_pending = false;
985 dev->power.request = RPM_REQ_NONE; 1078 dev->power.request = RPM_REQ_NONE;