aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2011-11-03 18:39:18 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-11-04 17:28:14 -0400
commit886486b792e4f6f96d4fbe8ec5bf20811cab7d6a (patch)
tree1c638e14492c16f8f69ca71fa93b2d81d8e4eeb6 /drivers/base
parent6513fd6972f725291ee8ce62c7a39fb8a6c7391e (diff)
PM / Runtime: Automatically retry failed autosuspends
Originally, the runtime PM core would send an idle notification whenever a suspend attempt failed. The idle callback routine could then schedule a delayed suspend for some time later. However this behavior was changed by commit f71648d73c1650b8b4aceb3856bebbde6daa3b86 (PM / Runtime: Remove idle notification after failing suspend). No notifications were sent, and there was no clear mechanism to retry failed suspends. This caused problems for the usbhid driver, because it fails autosuspend attempts as long as a key is being held down. Therefore this patch (as1492) adds a mechanism for retrying failed autosuspends. If the callback routine updates the last_busy field so that the next autosuspend expiration time is in the future, the autosuspend will automatically be rescheduled. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: Henrik Rydberg <rydberg@euromail.se> Cc: <stable@kernel.org> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/runtime.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 18ef87e525fa..124dbf60c9bf 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -293,6 +293,9 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
293 * the callback was running then carry it out, otherwise send an idle 293 * the callback was running then carry it out, otherwise send an idle
294 * notification for its parent (if the suspend succeeded and both 294 * notification for its parent (if the suspend succeeded and both
295 * ignore_children of parent->power and irq_safe of dev->power are not set). 295 * ignore_children of parent->power and irq_safe of dev->power are not set).
296 * If ->runtime_suspend failed with -EAGAIN or -EBUSY, and if the RPM_AUTO
297 * flag is set and the next autosuspend-delay expiration time is in the
298 * future, schedule another autosuspend attempt.
296 * 299 *
297 * 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.
298 */ 301 */
@@ -413,10 +416,21 @@ static int rpm_suspend(struct device *dev, int rpmflags)
413 if (retval) { 416 if (retval) {
414 __update_runtime_status(dev, RPM_ACTIVE); 417 __update_runtime_status(dev, RPM_ACTIVE);
415 dev->power.deferred_resume = false; 418 dev->power.deferred_resume = false;
416 if (retval == -EAGAIN || retval == -EBUSY) 419 if (retval == -EAGAIN || retval == -EBUSY) {
417 dev->power.runtime_error = 0; 420 dev->power.runtime_error = 0;
418 else 421
422 /*
423 * If the callback routine failed an autosuspend, and
424 * if the last_busy time has been updated so that there
425 * is a new autosuspend expiration time, automatically
426 * reschedule another autosuspend.
427 */
428 if ((rpmflags & RPM_AUTO) &&
429 pm_runtime_autosuspend_expiration(dev) != 0)
430 goto repeat;
431 } else {
419 pm_runtime_cancel_pending(dev); 432 pm_runtime_cancel_pending(dev);
433 }
420 wake_up_all(&dev->power.wait_queue); 434 wake_up_all(&dev->power.wait_queue);
421 goto out; 435 goto out;
422 } 436 }