Skip to content

Commit 5382363

Browse files
committed
PM / Runtime: Add sysfs switch for disabling device run-time PM
Add new device sysfs attribute, power/control, allowing the user space to block the run-time power management of the devices. If this attribute is set to "on", the driver of the device won't be able to power manage it at run time (without breaking the rules) and the device will always be in the full power state (except when the entire system goes into a sleep state). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Alan Stern <stern@rowland.harvard.edu>
1 parent 68c6b85 commit 5382363

File tree

4 files changed

+101
-0
lines changed

4 files changed

+101
-0
lines changed

drivers/base/power/runtime.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,50 @@ void pm_runtime_enable(struct device *dev)
10101010
}
10111011
EXPORT_SYMBOL_GPL(pm_runtime_enable);
10121012

1013+
/**
1014+
* pm_runtime_forbid - Block run-time PM of a device.
1015+
* @dev: Device to handle.
1016+
*
1017+
* Increase the device's usage count and clear its power.runtime_auto flag,
1018+
* so that it cannot be suspended at run time until pm_runtime_allow() is called
1019+
* for it.
1020+
*/
1021+
void pm_runtime_forbid(struct device *dev)
1022+
{
1023+
spin_lock_irq(&dev->power.lock);
1024+
if (!dev->power.runtime_auto)
1025+
goto out;
1026+
1027+
dev->power.runtime_auto = false;
1028+
atomic_inc(&dev->power.usage_count);
1029+
__pm_runtime_resume(dev, false);
1030+
1031+
out:
1032+
spin_unlock_irq(&dev->power.lock);
1033+
}
1034+
EXPORT_SYMBOL_GPL(pm_runtime_forbid);
1035+
1036+
/**
1037+
* pm_runtime_allow - Unblock run-time PM of a device.
1038+
* @dev: Device to handle.
1039+
*
1040+
* Decrease the device's usage count and set its power.runtime_auto flag.
1041+
*/
1042+
void pm_runtime_allow(struct device *dev)
1043+
{
1044+
spin_lock_irq(&dev->power.lock);
1045+
if (dev->power.runtime_auto)
1046+
goto out;
1047+
1048+
dev->power.runtime_auto = true;
1049+
if (atomic_dec_and_test(&dev->power.usage_count))
1050+
__pm_runtime_idle(dev);
1051+
1052+
out:
1053+
spin_unlock_irq(&dev->power.lock);
1054+
}
1055+
EXPORT_SYMBOL_GPL(pm_runtime_allow);
1056+
10131057
/**
10141058
* pm_runtime_init - Initialize run-time PM fields in given device object.
10151059
* @dev: Device object to initialize.
@@ -1028,6 +1072,7 @@ void pm_runtime_init(struct device *dev)
10281072

10291073
atomic_set(&dev->power.child_count, 0);
10301074
pm_suspend_ignore_children(dev, false);
1075+
dev->power.runtime_auto = true;
10311076

10321077
dev->power.request_pending = false;
10331078
dev->power.request = RPM_REQ_NONE;

drivers/base/power/sysfs.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,25 @@
44

55
#include <linux/device.h>
66
#include <linux/string.h>
7+
#include <linux/pm_runtime.h>
78
#include "power.h"
89

910
/*
11+
* control - Report/change current runtime PM setting of the device
12+
*
13+
* Runtime power management of a device can be blocked with the help of
14+
* this attribute. All devices have one of the following two values for
15+
* the power/control file:
16+
*
17+
* + "auto\n" to allow the device to be power managed at run time;
18+
* + "on\n" to prevent the device from being power managed at run time;
19+
*
20+
* The default for all devices is "auto", which means that devices may be
21+
* subject to automatic power management, depending on their drivers.
22+
* Changing this attribute to "on" prevents the driver from power managing
23+
* the device at run time. Doing that while the device is suspended causes
24+
* it to be woken up.
25+
*
1026
* wakeup - Report/change current wakeup option for device
1127
*
1228
* Some devices support "wakeup" events, which are hardware signals
@@ -43,6 +59,38 @@
4359
static const char enabled[] = "enabled";
4460
static const char disabled[] = "disabled";
4561

62+
#ifdef CONFIG_PM_RUNTIME
63+
static const char ctrl_auto[] = "auto";
64+
static const char ctrl_on[] = "on";
65+
66+
static ssize_t control_show(struct device *dev, struct device_attribute *attr,
67+
char *buf)
68+
{
69+
return sprintf(buf, "%s\n",
70+
dev->power.runtime_auto ? ctrl_auto : ctrl_on);
71+
}
72+
73+
static ssize_t control_store(struct device * dev, struct device_attribute *attr,
74+
const char * buf, size_t n)
75+
{
76+
char *cp;
77+
int len = n;
78+
79+
cp = memchr(buf, '\n', n);
80+
if (cp)
81+
len = cp - buf;
82+
if (len == sizeof ctrl_auto - 1 && strncmp(buf, ctrl_auto, len) == 0)
83+
pm_runtime_allow(dev);
84+
else if (len == sizeof ctrl_on - 1 && strncmp(buf, ctrl_on, len) == 0)
85+
pm_runtime_forbid(dev);
86+
else
87+
return -EINVAL;
88+
return n;
89+
}
90+
91+
static DEVICE_ATTR(control, 0644, control_show, control_store);
92+
#endif
93+
4694
static ssize_t
4795
wake_show(struct device * dev, struct device_attribute *attr, char * buf)
4896
{
@@ -79,6 +127,9 @@ static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
79127

80128

81129
static struct attribute * power_attrs[] = {
130+
#ifdef CONFIG_PM_RUNTIME
131+
&dev_attr_control.attr,
132+
#endif
82133
&dev_attr_wakeup.attr,
83134
NULL,
84135
};

include/linux/pm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ struct dev_pm_info {
430430
unsigned int request_pending:1;
431431
unsigned int deferred_resume:1;
432432
unsigned int run_wake:1;
433+
unsigned int runtime_auto:1;
433434
enum rpm_request request;
434435
enum rpm_status runtime_status;
435436
int runtime_error;

include/linux/pm_runtime.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
2828
extern int pm_runtime_barrier(struct device *dev);
2929
extern void pm_runtime_enable(struct device *dev);
3030
extern void __pm_runtime_disable(struct device *dev, bool check_resume);
31+
extern void pm_runtime_allow(struct device *dev);
32+
extern void pm_runtime_forbid(struct device *dev);
3133

3234
static inline bool pm_children_suspended(struct device *dev)
3335
{
@@ -78,6 +80,8 @@ static inline int __pm_runtime_set_status(struct device *dev,
7880
static inline int pm_runtime_barrier(struct device *dev) { return 0; }
7981
static inline void pm_runtime_enable(struct device *dev) {}
8082
static inline void __pm_runtime_disable(struct device *dev, bool c) {}
83+
static inline void pm_runtime_allow(struct device *dev) {}
84+
static inline void pm_runtime_forbid(struct device *dev) {}
8185

8286
static inline bool pm_children_suspended(struct device *dev) { return false; }
8387
static inline void pm_suspend_ignore_children(struct device *dev, bool en) {}

0 commit comments

Comments
 (0)