| From 62690b36f3600b1838068b1fad62fd97d2323c4f Mon Sep 17 00:00:00 2001 |
| From: Ming Lei <ming.lei@canonical.com> |
| Date: Wed, 12 Oct 2011 22:59:33 +0200 |
| Subject: PM / Runtime: Handle .runtime_suspend() failure correctly |
| |
| If .runtime_suspend() returns -EAGAIN or -EBUSY, the device should |
| still be in ACTIVE state, so it is not necessary to send an idle |
| notification to its parent. If .runtime_suspend() returns other |
| fatal failure, it doesn't make sense to send idle notification to |
| its parent. |
| |
| Skip parent idle notification when failure is returned from |
| .runtime_suspend() and update comments in rpm_suspend() to reflect |
| that change. |
| |
| [rjw: Modified the subject and changelog slightly.] |
| |
| Signed-off-by: Ming Lei <ming.lei@canonical.com> |
| Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> |
| (cherry picked from commit 857b36c7b038ac56a882ee914df93e5985443074) |
| |
| Signed-off-by: Simon Horman <horms@verge.net.au> |
| --- |
| drivers/base/power/runtime.c | 25 +++++++++++++------------ |
| 1 file changed, 13 insertions(+), 12 deletions(-) |
| |
| --- a/drivers/base/power/runtime.c |
| +++ b/drivers/base/power/runtime.c |
| @@ -291,11 +291,11 @@ static int rpm_callback(int (*cb)(struct |
| * another suspend has been started earlier, either return immediately |
| * or wait for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC |
| * flags. If the RPM_ASYNC flag is set then queue a suspend request; |
| - * otherwise run the ->runtime_suspend() callback directly. If a deferred |
| - * resume was requested while the callback was running then carry it out; |
| - * otherwise send an idle notification for its parent (if the suspend |
| - * succeeded and both ignore_children of parent->power and irq_safe of |
| - * dev->power are not set). |
| + * otherwise run the ->runtime_suspend() callback directly. When |
| + * ->runtime_suspend succeeded, if a deferred resume was requested while |
| + * the callback was running then carry it out, otherwise send an idle |
| + * notification for its parent (if the suspend succeeded and both |
| + * ignore_children of parent->power and irq_safe of dev->power are not set). |
| * |
| * This function must be called under dev->power.lock with interrupts disabled. |
| */ |
| @@ -419,15 +419,16 @@ static int rpm_suspend(struct device *de |
| dev->power.runtime_error = 0; |
| else |
| pm_runtime_cancel_pending(dev); |
| - } else { |
| + wake_up_all(&dev->power.wait_queue); |
| + goto out; |
| + } |
| no_callback: |
| - __update_runtime_status(dev, RPM_SUSPENDED); |
| - pm_runtime_deactivate_timer(dev); |
| + __update_runtime_status(dev, RPM_SUSPENDED); |
| + pm_runtime_deactivate_timer(dev); |
| |
| - if (dev->parent) { |
| - parent = dev->parent; |
| - atomic_add_unless(&parent->power.child_count, -1, 0); |
| - } |
| + if (dev->parent) { |
| + parent = dev->parent; |
| + atomic_add_unless(&parent->power.child_count, -1, 0); |
| } |
| wake_up_all(&dev->power.wait_queue); |
| |