aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/runtime.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2010-09-25 17:35:15 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2010-10-16 19:57:47 -0400
commit7490e44239e60293bca0c2663229050c36c660c2 (patch)
tree938cd1cafba133f2d47c648ac01242de841d6d1b /drivers/base/power/runtime.c
parent140a6c945211ee911dec776fafa52e03a7d7bb9a (diff)
PM / Runtime: Add no_callbacks flag
Some devices, such as USB interfaces, cannot be power-managed independently of their parents, i.e., they cannot be put in low power while the parent remains at full power. This patch (as1425) creates a new "no_callbacks" flag, which tells the PM core not to invoke the runtime-PM callback routines for the such devices but instead to assume that the callbacks always succeed. In addition, the non-debugging runtime-PM sysfs attributes for the devices are removed, since they are pretty much meaningless. The advantage of this scheme comes not so much from avoiding the callbacks themselves, but rather from the fact that without the need for a process context in which to run the callbacks, more work can be done in interrupt context. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
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 */