diff options
-rw-r--r-- | Documentation/power/runtime_pm.txt | 10 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 18 |
2 files changed, 26 insertions, 2 deletions
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index 0e856088db7c..5336149f831b 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt | |||
@@ -789,6 +789,16 @@ will behave normally, not taking the autosuspend delay into account. | |||
789 | Similarly, if the power.use_autosuspend field isn't set then the autosuspend | 789 | Similarly, if the power.use_autosuspend field isn't set then the autosuspend |
790 | helper functions will behave just like the non-autosuspend counterparts. | 790 | helper functions will behave just like the non-autosuspend counterparts. |
791 | 791 | ||
792 | Under some circumstances a driver or subsystem may want to prevent a device | ||
793 | from autosuspending immediately, even though the usage counter is zero and the | ||
794 | autosuspend delay time has expired. If the ->runtime_suspend() callback | ||
795 | returns -EAGAIN or -EBUSY, and if the next autosuspend delay expiration time is | ||
796 | in the future (as it normally would be if the callback invoked | ||
797 | pm_runtime_mark_last_busy()), the PM core will automatically reschedule the | ||
798 | autosuspend. The ->runtime_suspend() callback can't do this rescheduling | ||
799 | itself because no suspend requests of any kind are accepted while the device is | ||
800 | suspending (i.e., while the callback is running). | ||
801 | |||
792 | The implementation is well suited for asynchronous use in interrupt contexts. | 802 | The implementation is well suited for asynchronous use in interrupt contexts. |
793 | However such use inevitably involves races, because the PM core can't | 803 | However such use inevitably involves races, because the PM core can't |
794 | synchronize ->runtime_suspend() callbacks with the arrival of I/O requests. | 804 | synchronize ->runtime_suspend() callbacks with the arrival of I/O requests. |
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 | } |