summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2011-11-03 23:39:18 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2011-11-11 09:44:11 -0800
commitda5c50811e8e2342fd83c3d9fbd6609175fa2cf5 (patch)
tree0643db59165ea8b71d67a3fb18bedf1ce4a36157 /drivers
parentf571b637c81f3cbac21c93c2f0e283965235b152 (diff)
PM / Runtime: Automatically retry failed autosuspends
commit 886486b792e4f6f96d4fbe8ec5bf20811cab7d6a upstream. 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> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-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 acb3f83b8079..6a7f7b06968f 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -285,6 +285,9 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
* If a deferred resume was requested while the callback was running then carry
* it out; otherwise send an idle notification for the device (if the suspend
* failed) or for its parent (if the suspend succeeded).
+ * If ->runtime_suspend failed with -EAGAIN or -EBUSY, and if the RPM_AUTO
+ * flag is set and the next autosuspend-delay expiration time is in the
+ * future, schedule another autosuspend attempt.
*
* This function must be called under dev->power.lock with interrupts disabled.
*/
@@ -396,10 +399,21 @@ static int rpm_suspend(struct device *dev, int rpmflags)
if (retval) {
__update_runtime_status(dev, RPM_ACTIVE);
dev->power.deferred_resume = false;
- if (retval == -EAGAIN || retval == -EBUSY)
+ if (retval == -EAGAIN || retval == -EBUSY) {
dev->power.runtime_error = 0;
- else
+
+ /*
+ * If the callback routine failed an autosuspend, and
+ * if the last_busy time has been updated so that there
+ * is a new autosuspend expiration time, automatically
+ * reschedule another autosuspend.
+ */
+ if ((rpmflags & RPM_AUTO) &&
+ pm_runtime_autosuspend_expiration(dev) != 0)
+ goto repeat;
+ } else {
pm_runtime_cancel_pending(dev);
+ }
} else {
no_callback:
__update_runtime_status(dev, RPM_SUSPENDED);