diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/runtime.c | 33 |
1 files changed, 18 insertions, 15 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index a770498a74ec..5a01ecef4af3 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c | |||
@@ -185,6 +185,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) | |||
185 | } | 185 | } |
186 | 186 | ||
187 | dev->power.runtime_status = RPM_SUSPENDING; | 187 | dev->power.runtime_status = RPM_SUSPENDING; |
188 | dev->power.deferred_resume = false; | ||
188 | 189 | ||
189 | if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) { | 190 | if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) { |
190 | spin_unlock_irq(&dev->power.lock); | 191 | spin_unlock_irq(&dev->power.lock); |
@@ -200,7 +201,6 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) | |||
200 | if (retval) { | 201 | if (retval) { |
201 | dev->power.runtime_status = RPM_ACTIVE; | 202 | dev->power.runtime_status = RPM_ACTIVE; |
202 | pm_runtime_cancel_pending(dev); | 203 | pm_runtime_cancel_pending(dev); |
203 | dev->power.deferred_resume = false; | ||
204 | 204 | ||
205 | if (retval == -EAGAIN || retval == -EBUSY) { | 205 | if (retval == -EAGAIN || retval == -EBUSY) { |
206 | notify = true; | 206 | notify = true; |
@@ -217,7 +217,6 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq) | |||
217 | wake_up_all(&dev->power.wait_queue); | 217 | wake_up_all(&dev->power.wait_queue); |
218 | 218 | ||
219 | if (dev->power.deferred_resume) { | 219 | if (dev->power.deferred_resume) { |
220 | dev->power.deferred_resume = false; | ||
221 | __pm_runtime_resume(dev, false); | 220 | __pm_runtime_resume(dev, false); |
222 | retval = -EAGAIN; | 221 | retval = -EAGAIN; |
223 | goto out; | 222 | goto out; |
@@ -328,11 +327,11 @@ int __pm_runtime_resume(struct device *dev, bool from_wq) | |||
328 | * necessary. | 327 | * necessary. |
329 | */ | 328 | */ |
330 | parent = dev->parent; | 329 | parent = dev->parent; |
331 | spin_unlock_irq(&dev->power.lock); | 330 | spin_unlock(&dev->power.lock); |
332 | 331 | ||
333 | pm_runtime_get_noresume(parent); | 332 | pm_runtime_get_noresume(parent); |
334 | 333 | ||
335 | spin_lock_irq(&parent->power.lock); | 334 | spin_lock(&parent->power.lock); |
336 | /* | 335 | /* |
337 | * We can resume if the parent's run-time PM is disabled or it | 336 | * We can resume if the parent's run-time PM is disabled or it |
338 | * is set to ignore children. | 337 | * is set to ignore children. |
@@ -343,9 +342,9 @@ int __pm_runtime_resume(struct device *dev, bool from_wq) | |||
343 | if (parent->power.runtime_status != RPM_ACTIVE) | 342 | if (parent->power.runtime_status != RPM_ACTIVE) |
344 | retval = -EBUSY; | 343 | retval = -EBUSY; |
345 | } | 344 | } |
346 | spin_unlock_irq(&parent->power.lock); | 345 | spin_unlock(&parent->power.lock); |
347 | 346 | ||
348 | spin_lock_irq(&dev->power.lock); | 347 | spin_lock(&dev->power.lock); |
349 | if (retval) | 348 | if (retval) |
350 | goto out; | 349 | goto out; |
351 | goto repeat; | 350 | goto repeat; |
@@ -626,6 +625,8 @@ int pm_schedule_suspend(struct device *dev, unsigned int delay) | |||
626 | goto out; | 625 | goto out; |
627 | 626 | ||
628 | dev->power.timer_expires = jiffies + msecs_to_jiffies(delay); | 627 | dev->power.timer_expires = jiffies + msecs_to_jiffies(delay); |
628 | if (!dev->power.timer_expires) | ||
629 | dev->power.timer_expires = 1; | ||
629 | mod_timer(&dev->power.suspend_timer, dev->power.timer_expires); | 630 | mod_timer(&dev->power.suspend_timer, dev->power.timer_expires); |
630 | 631 | ||
631 | out: | 632 | out: |
@@ -659,13 +660,17 @@ static int __pm_request_resume(struct device *dev) | |||
659 | 660 | ||
660 | pm_runtime_deactivate_timer(dev); | 661 | pm_runtime_deactivate_timer(dev); |
661 | 662 | ||
663 | if (dev->power.runtime_status == RPM_SUSPENDING) { | ||
664 | dev->power.deferred_resume = true; | ||
665 | return retval; | ||
666 | } | ||
662 | if (dev->power.request_pending) { | 667 | if (dev->power.request_pending) { |
663 | /* If non-resume request is pending, we can overtake it. */ | 668 | /* If non-resume request is pending, we can overtake it. */ |
664 | dev->power.request = retval ? RPM_REQ_NONE : RPM_REQ_RESUME; | 669 | dev->power.request = retval ? RPM_REQ_NONE : RPM_REQ_RESUME; |
665 | return retval; | 670 | return retval; |
666 | } else if (retval) { | ||
667 | return retval; | ||
668 | } | 671 | } |
672 | if (retval) | ||
673 | return retval; | ||
669 | 674 | ||
670 | dev->power.request = RPM_REQ_RESUME; | 675 | dev->power.request = RPM_REQ_RESUME; |
671 | dev->power.request_pending = true; | 676 | dev->power.request_pending = true; |
@@ -777,7 +782,7 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status) | |||
777 | } | 782 | } |
778 | 783 | ||
779 | if (parent) { | 784 | if (parent) { |
780 | spin_lock_irq(&parent->power.lock); | 785 | spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING); |
781 | 786 | ||
782 | /* | 787 | /* |
783 | * It is invalid to put an active child under a parent that is | 788 | * It is invalid to put an active child under a parent that is |
@@ -786,14 +791,12 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status) | |||
786 | */ | 791 | */ |
787 | if (!parent->power.disable_depth | 792 | if (!parent->power.disable_depth |
788 | && !parent->power.ignore_children | 793 | && !parent->power.ignore_children |
789 | && parent->power.runtime_status != RPM_ACTIVE) { | 794 | && parent->power.runtime_status != RPM_ACTIVE) |
790 | error = -EBUSY; | 795 | error = -EBUSY; |
791 | } else { | 796 | else if (dev->power.runtime_status == RPM_SUSPENDED) |
792 | if (dev->power.runtime_status == RPM_SUSPENDED) | 797 | atomic_inc(&parent->power.child_count); |
793 | atomic_inc(&parent->power.child_count); | ||
794 | } | ||
795 | 798 | ||
796 | spin_unlock_irq(&parent->power.lock); | 799 | spin_unlock(&parent->power.lock); |
797 | 800 | ||
798 | if (error) | 801 | if (error) |
799 | goto out; | 802 | goto out; |