aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/power/runtime_pm.txt37
-rw-r--r--drivers/base/power/power.h1
-rw-r--r--drivers/base/power/runtime.c54
-rw-r--r--drivers/base/power/sysfs.c56
-rw-r--r--include/linux/pm.h7
-rw-r--r--include/linux/pm_runtime.h2
6 files changed, 149 insertions, 8 deletions
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index 55b859b3bc72..9ba49b21ac86 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -1,6 +1,7 @@
1Run-time Power Management Framework for I/O Devices 1Run-time Power Management Framework for I/O Devices
2 2
3(C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. 3(C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
4(C) 2010 Alan Stern <stern@rowland.harvard.edu>
4 5
51. Introduction 61. Introduction
6 7
@@ -230,6 +231,11 @@ defined in include/linux/pm.h:
230 interface; it may only be modified with the help of the pm_runtime_allow() 231 interface; it may only be modified with the help of the pm_runtime_allow()
231 and pm_runtime_forbid() helper functions 232 and pm_runtime_forbid() helper functions
232 233
234 unsigned int no_callbacks;
235 - indicates that the device does not use the run-time PM callbacks (see
236 Section 8); it may be modified only by the pm_runtime_no_callbacks()
237 helper function
238
233All of the above fields are members of the 'power' member of 'struct device'. 239All of the above fields are members of the 'power' member of 'struct device'.
234 240
2354. Run-time PM Device Helper Functions 2414. Run-time PM Device Helper Functions
@@ -349,6 +355,11 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
349 counter (used by the /sys/devices/.../power/control interface to 355 counter (used by the /sys/devices/.../power/control interface to
350 effectively prevent the device from being power managed at run time) 356 effectively prevent the device from being power managed at run time)
351 357
358 void pm_runtime_no_callbacks(struct device *dev);
359 - set the power.no_callbacks flag for the device and remove the run-time
360 PM attributes from /sys/devices/.../power (or prevent them from being
361 added when the device is registered)
362
352It is safe to execute the following helper functions from interrupt context: 363It is safe to execute the following helper functions from interrupt context:
353 364
354pm_request_idle() 365pm_request_idle()
@@ -524,3 +535,29 @@ poweroff and run-time suspend callback, and similarly for system resume, thaw,
524restore, and run-time resume, can achieve this with the help of the 535restore, and run-time resume, can achieve this with the help of the
525UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h (possibly setting its 536UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h (possibly setting its
526last argument to NULL). 537last argument to NULL).
538
5398. "No-Callback" Devices
540
541Some "devices" are only logical sub-devices of their parent and cannot be
542power-managed on their own. (The prototype example is a USB interface. Entire
543USB devices can go into low-power mode or send wake-up requests, but neither is
544possible for individual interfaces.) The drivers for these devices have no
545need of run-time PM callbacks; if the callbacks did exist, ->runtime_suspend()
546and ->runtime_resume() would always return 0 without doing anything else and
547->runtime_idle() would always call pm_runtime_suspend().
548
549Subsystems can tell the PM core about these devices by calling
550pm_runtime_no_callbacks(). This should be done after the device structure is
551initialized and before it is registered (although after device registration is
552also okay). The routine will set the device's power.no_callbacks flag and
553prevent the non-debugging run-time PM sysfs attributes from being created.
554
555When power.no_callbacks is set, the PM core will not invoke the
556->runtime_idle(), ->runtime_suspend(), or ->runtime_resume() callbacks.
557Instead it will assume that suspends and resumes always succeed and that idle
558devices should be suspended.
559
560As a consequence, the PM core will never directly inform the device's subsystem
561or driver about run-time power changes. Instead, the driver for the device's
562parent must take responsibility for telling the device's driver when the
563parent's power state changes.
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 8b2745c69e2a..698dde742587 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -60,6 +60,7 @@ static inline void device_pm_move_last(struct device *dev) {}
60 60
61extern int dpm_sysfs_add(struct device *); 61extern int dpm_sysfs_add(struct device *);
62extern void dpm_sysfs_remove(struct device *); 62extern void dpm_sysfs_remove(struct device *);
63extern void rpm_sysfs_remove(struct device *);
63 64
64#else /* CONFIG_PM */ 65#else /* CONFIG_PM */
65 66
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 */
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 8859780817e1..b5708c47ce2d 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -81,6 +81,9 @@
81static const char enabled[] = "enabled"; 81static const char enabled[] = "enabled";
82static const char disabled[] = "disabled"; 82static const char disabled[] = "disabled";
83 83
84const char power_group_name[] = "power";
85EXPORT_SYMBOL_GPL(power_group_name);
86
84#ifdef CONFIG_PM_RUNTIME 87#ifdef CONFIG_PM_RUNTIME
85static const char ctrl_auto[] = "auto"; 88static const char ctrl_auto[] = "auto";
86static const char ctrl_on[] = "on"; 89static const char ctrl_on[] = "on";
@@ -390,12 +393,6 @@ static DEVICE_ATTR(async, 0644, async_show, async_store);
390#endif /* CONFIG_PM_ADVANCED_DEBUG */ 393#endif /* CONFIG_PM_ADVANCED_DEBUG */
391 394
392static struct attribute * power_attrs[] = { 395static struct attribute * power_attrs[] = {
393#ifdef CONFIG_PM_RUNTIME
394 &dev_attr_control.attr,
395 &dev_attr_runtime_status.attr,
396 &dev_attr_runtime_suspended_time.attr,
397 &dev_attr_runtime_active_time.attr,
398#endif
399 &dev_attr_wakeup.attr, 396 &dev_attr_wakeup.attr,
400#ifdef CONFIG_PM_SLEEP 397#ifdef CONFIG_PM_SLEEP
401 &dev_attr_wakeup_count.attr, 398 &dev_attr_wakeup_count.attr,
@@ -409,6 +406,7 @@ static struct attribute * power_attrs[] = {
409#ifdef CONFIG_PM_ADVANCED_DEBUG 406#ifdef CONFIG_PM_ADVANCED_DEBUG
410 &dev_attr_async.attr, 407 &dev_attr_async.attr,
411#ifdef CONFIG_PM_RUNTIME 408#ifdef CONFIG_PM_RUNTIME
409 &dev_attr_runtime_status.attr,
412 &dev_attr_runtime_usage.attr, 410 &dev_attr_runtime_usage.attr,
413 &dev_attr_runtime_active_kids.attr, 411 &dev_attr_runtime_active_kids.attr,
414 &dev_attr_runtime_enabled.attr, 412 &dev_attr_runtime_enabled.attr,
@@ -417,10 +415,52 @@ static struct attribute * power_attrs[] = {
417 NULL, 415 NULL,
418}; 416};
419static struct attribute_group pm_attr_group = { 417static struct attribute_group pm_attr_group = {
420 .name = "power", 418 .name = power_group_name,
421 .attrs = power_attrs, 419 .attrs = power_attrs,
422}; 420};
423 421
422#ifdef CONFIG_PM_RUNTIME
423
424static struct attribute *runtime_attrs[] = {
425#ifndef CONFIG_PM_ADVANCED_DEBUG
426 &dev_attr_runtime_status.attr,
427#endif
428 &dev_attr_control.attr,
429 &dev_attr_runtime_suspended_time.attr,
430 &dev_attr_runtime_active_time.attr,
431 NULL,
432};
433static struct attribute_group pm_runtime_attr_group = {
434 .name = power_group_name,
435 .attrs = runtime_attrs,
436};
437
438int dpm_sysfs_add(struct device *dev)
439{
440 int rc;
441
442 rc = sysfs_create_group(&dev->kobj, &pm_attr_group);
443 if (rc == 0 && !dev->power.no_callbacks) {
444 rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group);
445 if (rc)
446 sysfs_remove_group(&dev->kobj, &pm_attr_group);
447 }
448 return rc;
449}
450
451void rpm_sysfs_remove(struct device *dev)
452{
453 sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
454}
455
456void dpm_sysfs_remove(struct device *dev)
457{
458 rpm_sysfs_remove(dev);
459 sysfs_remove_group(&dev->kobj, &pm_attr_group);
460}
461
462#else /* CONFIG_PM_RUNTIME */
463
424int dpm_sysfs_add(struct device * dev) 464int dpm_sysfs_add(struct device * dev)
425{ 465{
426 return sysfs_create_group(&dev->kobj, &pm_attr_group); 466 return sysfs_create_group(&dev->kobj, &pm_attr_group);
@@ -430,3 +470,5 @@ void dpm_sysfs_remove(struct device * dev)
430{ 470{
431 sysfs_remove_group(&dev->kobj, &pm_attr_group); 471 sysfs_remove_group(&dev->kobj, &pm_attr_group);
432} 472}
473
474#endif
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 1abfe84f447d..abd81ffaba3c 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -41,6 +41,12 @@ extern void (*pm_power_off_prepare)(void);
41 41
42struct device; 42struct device;
43 43
44#ifdef CONFIG_PM
45extern const char power_group_name[]; /* = "power" */
46#else
47#define power_group_name NULL
48#endif
49
44typedef struct pm_message { 50typedef struct pm_message {
45 int event; 51 int event;
46} pm_message_t; 52} pm_message_t;
@@ -475,6 +481,7 @@ struct dev_pm_info {
475 unsigned int deferred_resume:1; 481 unsigned int deferred_resume:1;
476 unsigned int run_wake:1; 482 unsigned int run_wake:1;
477 unsigned int runtime_auto:1; 483 unsigned int runtime_auto:1;
484 unsigned int no_callbacks:1;
478 enum rpm_request request; 485 enum rpm_request request;
479 enum rpm_status runtime_status; 486 enum rpm_status runtime_status;
480 int runtime_error; 487 int runtime_error;
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 5869d87fffac..8ca52f7c357e 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -36,6 +36,7 @@ extern void pm_runtime_forbid(struct device *dev);
36extern int pm_generic_runtime_idle(struct device *dev); 36extern int pm_generic_runtime_idle(struct device *dev);
37extern int pm_generic_runtime_suspend(struct device *dev); 37extern int pm_generic_runtime_suspend(struct device *dev);
38extern int pm_generic_runtime_resume(struct device *dev); 38extern int pm_generic_runtime_resume(struct device *dev);
39extern void pm_runtime_no_callbacks(struct device *dev);
39 40
40static inline bool pm_children_suspended(struct device *dev) 41static inline bool pm_children_suspended(struct device *dev)
41{ 42{
@@ -110,6 +111,7 @@ static inline bool pm_runtime_suspended(struct device *dev) { return false; }
110static inline int pm_generic_runtime_idle(struct device *dev) { return 0; } 111static inline int pm_generic_runtime_idle(struct device *dev) { return 0; }
111static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; } 112static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
112static inline int pm_generic_runtime_resume(struct device *dev) { return 0; } 113static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
114static inline void pm_runtime_no_callbacks(struct device *dev) {}
113 115
114#endif /* !CONFIG_PM_RUNTIME */ 116#endif /* !CONFIG_PM_RUNTIME */
115 117