diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/base/power/runtime.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/base/power/runtime.c')
-rw-r--r-- | drivers/base/power/runtime.c | 123 |
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 | */ |
702 | int __pm_runtime_get(struct device *dev, bool sync) | 752 | int __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) | |||
963 | EXPORT_SYMBOL_GPL(pm_runtime_enable); | 1011 | EXPORT_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 | */ | ||
1021 | void 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 | } | ||
1034 | EXPORT_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 | */ | ||
1042 | void 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 | } | ||
1055 | EXPORT_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; |