aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2011-10-12 16:59:33 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-10-16 17:25:23 -0400
commit857b36c7b038ac56a882ee914df93e5985443074 (patch)
tree04af09cacf24cde80659c810c66bc89c6fcf84c9 /drivers/base/power
parent47d8f0bac0fda4c15a030f92cd6da6c6bed87459 (diff)
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>
Diffstat (limited to 'drivers/base/power')
-rw-r--r--drivers/base/power/runtime.c25
1 files changed, 13 insertions, 12 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index aa23a64ea33b..6bb3aafa85ed 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -291,11 +291,11 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
291 * another suspend has been started earlier, either return immediately 291 * another suspend has been started earlier, either return immediately
292 * or wait for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC 292 * or wait for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC
293 * flags. If the RPM_ASYNC flag is set then queue a suspend request; 293 * flags. If the RPM_ASYNC flag is set then queue a suspend request;
294 * otherwise run the ->runtime_suspend() callback directly. If a deferred 294 * otherwise run the ->runtime_suspend() callback directly. When
295 * resume was requested while the callback was running then carry it out; 295 * ->runtime_suspend succeeded, if a deferred resume was requested while
296 * otherwise send an idle notification for its parent (if the suspend 296 * the callback was running then carry it out, otherwise send an idle
297 * succeeded and both ignore_children of parent->power and irq_safe of 297 * notification for its parent (if the suspend succeeded and both
298 * dev->power are not set). 298 * ignore_children of parent->power and irq_safe of dev->power are not set).
299 * 299 *
300 * This function must be called under dev->power.lock with interrupts disabled. 300 * This function must be called under dev->power.lock with interrupts disabled.
301 */ 301 */
@@ -420,15 +420,16 @@ static int rpm_suspend(struct device *dev, int rpmflags)
420 dev->power.runtime_error = 0; 420 dev->power.runtime_error = 0;
421 else 421 else
422 pm_runtime_cancel_pending(dev); 422 pm_runtime_cancel_pending(dev);
423 } else { 423 wake_up_all(&dev->power.wait_queue);
424 goto out;
425 }
424 no_callback: 426 no_callback:
425 __update_runtime_status(dev, RPM_SUSPENDED); 427 __update_runtime_status(dev, RPM_SUSPENDED);
426 pm_runtime_deactivate_timer(dev); 428 pm_runtime_deactivate_timer(dev);
427 429
428 if (dev->parent) { 430 if (dev->parent) {
429 parent = dev->parent; 431 parent = dev->parent;
430 atomic_add_unless(&parent->power.child_count, -1, 0); 432 atomic_add_unless(&parent->power.child_count, -1, 0);
431 }
432 } 433 }
433 wake_up_all(&dev->power.wait_queue); 434 wake_up_all(&dev->power.wait_queue);
434 435