aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/runtime.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/power/runtime.c')
-rw-r--r--drivers/base/power/runtime.c54
1 files changed, 53 insertions, 1 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index ed227b7c1bb5..5bd4daa93ef1 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -10,8 +10,10 @@
10#include <linux/sched.h> 10#include <linux/sched.h>
11#include <linux/pm_runtime.h> 11#include <linux/pm_runtime.h>
12#include <linux/jiffies.h> 12#include <linux/jiffies.h>
13#include "power.h"
13 14
14static int rpm_resume(struct device *dev, int rpmflags); 15static int rpm_resume(struct device *dev, int rpmflags);
16static int rpm_suspend(struct device *dev, int rpmflags);
15 17
16/** 18/**
17 * update_pm_runtime_accounting - Update the time accounting of power states 19 * update_pm_runtime_accounting - Update the time accounting of power states
@@ -148,6 +150,12 @@ static int rpm_idle(struct device *dev, int rpmflags)
148 /* Pending requests need to be canceled. */ 150 /* Pending requests need to be canceled. */
149 dev->power.request = RPM_REQ_NONE; 151 dev->power.request = RPM_REQ_NONE;
150 152
153 if (dev->power.no_callbacks) {
154 /* Assume ->runtime_idle() callback would have suspended. */
155 retval = rpm_suspend(dev, rpmflags);
156 goto out;
157 }
158
151 /* Carry out an asynchronous or a synchronous idle notification. */ 159 /* Carry out an asynchronous or a synchronous idle notification. */
152 if (rpmflags & RPM_ASYNC) { 160 if (rpmflags & RPM_ASYNC) {
153 dev->power.request = RPM_REQ_IDLE; 161 dev->power.request = RPM_REQ_IDLE;
@@ -254,6 +262,10 @@ static int rpm_suspend(struct device *dev, int rpmflags)
254 goto repeat; 262 goto repeat;
255 } 263 }
256 264
265 dev->power.deferred_resume = false;
266 if (dev->power.no_callbacks)
267 goto no_callback; /* Assume success. */
268
257 /* Carry out an asynchronous or a synchronous suspend. */ 269 /* Carry out an asynchronous or a synchronous suspend. */
258 if (rpmflags & RPM_ASYNC) { 270 if (rpmflags & RPM_ASYNC) {
259 dev->power.request = RPM_REQ_SUSPEND; 271 dev->power.request = RPM_REQ_SUSPEND;
@@ -265,7 +277,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
265 } 277 }
266 278
267 __update_runtime_status(dev, RPM_SUSPENDING); 279 __update_runtime_status(dev, RPM_SUSPENDING);
268 dev->power.deferred_resume = false;
269 280
270 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) { 281 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
271 spin_unlock_irq(&dev->power.lock); 282 spin_unlock_irq(&dev->power.lock);
@@ -305,6 +316,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
305 pm_runtime_cancel_pending(dev); 316 pm_runtime_cancel_pending(dev);
306 } 317 }
307 } else { 318 } else {
319 no_callback:
308 __update_runtime_status(dev, RPM_SUSPENDED); 320 __update_runtime_status(dev, RPM_SUSPENDED);
309 pm_runtime_deactivate_timer(dev); 321 pm_runtime_deactivate_timer(dev);
310 322
@@ -409,6 +421,23 @@ static int rpm_resume(struct device *dev, int rpmflags)
409 goto repeat; 421 goto repeat;
410 } 422 }
411 423
424 /*
425 * See if we can skip waking up the parent. This is safe only if
426 * power.no_callbacks is set, because otherwise we don't know whether
427 * the resume will actually succeed.
428 */
429 if (dev->power.no_callbacks && !parent && dev->parent) {
430 spin_lock(&dev->parent->power.lock);
431 if (dev->parent->power.disable_depth > 0
432 || dev->parent->power.ignore_children
433 || dev->parent->power.runtime_status == RPM_ACTIVE) {
434 atomic_inc(&dev->parent->power.child_count);
435 spin_unlock(&dev->parent->power.lock);
436 goto no_callback; /* Assume success. */
437 }
438 spin_unlock(&dev->parent->power.lock);
439 }
440
412 /* Carry out an asynchronous or a synchronous resume. */ 441 /* Carry out an asynchronous or a synchronous resume. */
413 if (rpmflags & RPM_ASYNC) { 442 if (rpmflags & RPM_ASYNC) {
414 dev->power.request = RPM_REQ_RESUME; 443 dev->power.request = RPM_REQ_RESUME;
@@ -449,6 +478,9 @@ static int rpm_resume(struct device *dev, int rpmflags)
449 goto repeat; 478 goto repeat;
450 } 479 }
451 480
481 if (dev->power.no_callbacks)
482 goto no_callback; /* Assume success. */
483
452 __update_runtime_status(dev, RPM_RESUMING); 484 __update_runtime_status(dev, RPM_RESUMING);
453 485
454 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) { 486 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {
@@ -482,6 +514,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
482 __update_runtime_status(dev, RPM_SUSPENDED); 514 __update_runtime_status(dev, RPM_SUSPENDED);
483 pm_runtime_cancel_pending(dev); 515 pm_runtime_cancel_pending(dev);
484 } else { 516 } else {
517 no_callback:
485 __update_runtime_status(dev, RPM_ACTIVE); 518 __update_runtime_status(dev, RPM_ACTIVE);
486 if (parent) 519 if (parent)
487 atomic_inc(&parent->power.child_count); 520 atomic_inc(&parent->power.child_count);
@@ -955,6 +988,25 @@ void pm_runtime_allow(struct device *dev)
955EXPORT_SYMBOL_GPL(pm_runtime_allow); 988EXPORT_SYMBOL_GPL(pm_runtime_allow);
956 989
957/** 990/**
991 * pm_runtime_no_callbacks - Ignore run-time PM callbacks for a device.
992 * @dev: Device to handle.
993 *
994 * Set the power.no_callbacks flag, which tells the PM core that this
995 * device is power-managed through its parent and has no run-time PM
996 * callbacks of its own. The run-time sysfs attributes will be removed.
997 *
998 */
999void pm_runtime_no_callbacks(struct device *dev)
1000{
1001 spin_lock_irq(&dev->power.lock);
1002 dev->power.no_callbacks = 1;
1003 spin_unlock_irq(&dev->power.lock);
1004 if (device_is_registered(dev))
1005 rpm_sysfs_remove(dev);
1006}
1007EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks);
1008
1009/**
958 * pm_runtime_init - Initialize run-time PM fields in given device object. 1010 * pm_runtime_init - Initialize run-time PM fields in given device object.
959 * @dev: Device object to initialize. 1011 * @dev: Device object to initialize.
960 */ 1012 */