Skip to content

Commit cb8f51b

Browse files
committed
PM: Do not create wakeup sysfs files for devices that cannot wake up
Currently, wakeup sysfs attributes are created for all devices, regardless of whether or not they are wakeup-capable. This is excessive and complicates wakeup device identification from user space (i.e. to identify wakeup-capable devices user space has to read /sys/devices/.../power/wakeup for all devices and see if they are not empty). Fix this issue by avoiding to create wakeup sysfs files for devices that cannot wake up the system from sleep states (i.e. whose power.can_wakeup flags are unset during registration) and modify device_set_wakeup_capable() so that it adds (or removes) the relevant sysfs attributes if a device's wakeup capability status is changed. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
1 parent 4681b17 commit cb8f51b

File tree

7 files changed

+117
-65
lines changed

7 files changed

+117
-65
lines changed

Documentation/ABI/testing/sysfs-devices-power

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ Description:
2929
"disabled" to it.
3030

3131
For the devices that are not capable of generating system wakeup
32-
events this file contains "\n". In that cases the user space
33-
cannot modify the contents of this file and the device cannot be
34-
enabled to wake up the system.
32+
events this file is not present. In that case the device cannot
33+
be enabled to wake up the system from sleep states.
3534

3635
What: /sys/devices/.../power/control
3736
Date: January 2009
@@ -85,7 +84,7 @@ Description:
8584
The /sys/devices/.../wakeup_count attribute contains the number
8685
of signaled wakeup events associated with the device. This
8786
attribute is read-only. If the device is not enabled to wake up
88-
the system from sleep states, this attribute is empty.
87+
the system from sleep states, this attribute is not present.
8988

9089
What: /sys/devices/.../power/wakeup_active_count
9190
Date: September 2010
@@ -95,7 +94,7 @@ Description:
9594
number of times the processing of wakeup events associated with
9695
the device was completed (at the kernel level). This attribute
9796
is read-only. If the device is not enabled to wake up the
98-
system from sleep states, this attribute is empty.
97+
system from sleep states, this attribute is not present.
9998

10099
What: /sys/devices/.../power/wakeup_hit_count
101100
Date: September 2010
@@ -105,7 +104,8 @@ Description:
105104
number of times the processing of a wakeup event associated with
106105
the device might prevent the system from entering a sleep state.
107106
This attribute is read-only. If the device is not enabled to
108-
wake up the system from sleep states, this attribute is empty.
107+
wake up the system from sleep states, this attribute is not
108+
present.
109109

110110
What: /sys/devices/.../power/wakeup_active
111111
Date: September 2010
@@ -115,7 +115,7 @@ Description:
115115
or 0, depending on whether or not a wakeup event associated with
116116
the device is being processed (1). This attribute is read-only.
117117
If the device is not enabled to wake up the system from sleep
118-
states, this attribute is empty.
118+
states, this attribute is not present.
119119

120120
What: /sys/devices/.../power/wakeup_total_time_ms
121121
Date: September 2010
@@ -125,7 +125,7 @@ Description:
125125
the total time of processing wakeup events associated with the
126126
device, in milliseconds. This attribute is read-only. If the
127127
device is not enabled to wake up the system from sleep states,
128-
this attribute is empty.
128+
this attribute is not present.
129129

130130
What: /sys/devices/.../power/wakeup_max_time_ms
131131
Date: September 2010
@@ -135,7 +135,7 @@ Description:
135135
the maximum time of processing a single wakeup event associated
136136
with the device, in milliseconds. This attribute is read-only.
137137
If the device is not enabled to wake up the system from sleep
138-
states, this attribute is empty.
138+
states, this attribute is not present.
139139

140140
What: /sys/devices/.../power/wakeup_last_time_ms
141141
Date: September 2010
@@ -146,7 +146,7 @@ Description:
146146
signaling the last wakeup event associated with the device, in
147147
milliseconds. This attribute is read-only. If the device is
148148
not enabled to wake up the system from sleep states, this
149-
attribute is empty.
149+
attribute is not present.
150150

151151
What: /sys/devices/.../power/autosuspend_delay_ms
152152
Date: September 2010

Documentation/power/devices.txt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -159,18 +159,18 @@ matter, and the kernel is responsible for keeping track of it. By contrast,
159159
whether or not a wakeup-capable device should issue wakeup events is a policy
160160
decision, and it is managed by user space through a sysfs attribute: the
161161
power/wakeup file. User space can write the strings "enabled" or "disabled" to
162-
set or clear the should_wakeup flag, respectively. Reads from the file will
163-
return the corresponding string if can_wakeup is true, but if can_wakeup is
164-
false then reads will return an empty string, to indicate that the device
165-
doesn't support wakeup events. (But even though the file appears empty, writes
166-
will still affect the should_wakeup flag.)
162+
set or clear the "should_wakeup" flag, respectively. This file is only present
163+
for wakeup-capable devices (i.e. devices whose "can_wakeup" flags are set)
164+
and is created (or removed) by device_set_wakeup_capable(). Reads from the
165+
file will return the corresponding string.
167166

168167
The device_may_wakeup() routine returns true only if both flags are set.
169-
Drivers should check this routine when putting devices in a low-power state
170-
during a system sleep transition, to see whether or not to enable the devices'
171-
wakeup mechanisms. However for runtime power management, wakeup events should
172-
be enabled whenever the device and driver both support them, regardless of the
173-
should_wakeup flag.
168+
This information is used by subsystems, like the PCI bus type code, to see
169+
whether or not to enable the devices' wakeup mechanisms. If device wakeup
170+
mechanisms are enabled or disabled directly by drivers, they also should use
171+
device_may_wakeup() to decide what to do during a system sleep transition.
172+
However for runtime power management, wakeup events should be enabled whenever
173+
the device and driver both support them, regardless of the should_wakeup flag.
174174

175175

176176
/sys/devices/.../power/control files

drivers/base/power/power.h

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,18 @@ static inline void device_pm_move_last(struct device *dev) {}
5858
* sysfs.c
5959
*/
6060

61-
extern int dpm_sysfs_add(struct device *);
62-
extern void dpm_sysfs_remove(struct device *);
63-
extern void rpm_sysfs_remove(struct device *);
61+
extern int dpm_sysfs_add(struct device *dev);
62+
extern void dpm_sysfs_remove(struct device *dev);
63+
extern void rpm_sysfs_remove(struct device *dev);
64+
extern int wakeup_sysfs_add(struct device *dev);
65+
extern void wakeup_sysfs_remove(struct device *dev);
6466

6567
#else /* CONFIG_PM */
6668

67-
static inline int dpm_sysfs_add(struct device *dev)
68-
{
69-
return 0;
70-
}
71-
72-
static inline void dpm_sysfs_remove(struct device *dev)
73-
{
74-
}
69+
static inline int dpm_sysfs_add(struct device *dev) { return 0; }
70+
static inline void dpm_sysfs_remove(struct device *dev) {}
71+
static inline void rpm_sysfs_remove(struct device *dev) {}
72+
static inline int wakeup_sysfs_add(struct device *dev) { return 0; }
73+
static inline void wakeup_sysfs_remove(struct device *dev) {}
7574

7675
#endif

drivers/base/power/sysfs.c

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -431,43 +431,53 @@ static ssize_t async_store(struct device *dev, struct device_attribute *attr,
431431
static DEVICE_ATTR(async, 0644, async_show, async_store);
432432
#endif /* CONFIG_PM_ADVANCED_DEBUG */
433433

434-
static struct attribute * power_attrs[] = {
435-
&dev_attr_wakeup.attr,
436-
#ifdef CONFIG_PM_SLEEP
437-
&dev_attr_wakeup_count.attr,
438-
&dev_attr_wakeup_active_count.attr,
439-
&dev_attr_wakeup_hit_count.attr,
440-
&dev_attr_wakeup_active.attr,
441-
&dev_attr_wakeup_total_time_ms.attr,
442-
&dev_attr_wakeup_max_time_ms.attr,
443-
&dev_attr_wakeup_last_time_ms.attr,
444-
#endif
434+
static struct attribute *power_attrs[] = {
445435
#ifdef CONFIG_PM_ADVANCED_DEBUG
436+
#ifdef CONFIG_PM_SLEEP
446437
&dev_attr_async.attr,
438+
#endif
447439
#ifdef CONFIG_PM_RUNTIME
448440
&dev_attr_runtime_status.attr,
449441
&dev_attr_runtime_usage.attr,
450442
&dev_attr_runtime_active_kids.attr,
451443
&dev_attr_runtime_enabled.attr,
452444
#endif
453-
#endif
445+
#endif /* CONFIG_PM_ADVANCED_DEBUG */
454446
NULL,
455447
};
456448
static struct attribute_group pm_attr_group = {
457449
.name = power_group_name,
458450
.attrs = power_attrs,
459451
};
460452

461-
#ifdef CONFIG_PM_RUNTIME
453+
static struct attribute *wakeup_attrs[] = {
454+
#ifdef CONFIG_PM_SLEEP
455+
&dev_attr_wakeup.attr,
456+
&dev_attr_wakeup_count.attr,
457+
&dev_attr_wakeup_active_count.attr,
458+
&dev_attr_wakeup_hit_count.attr,
459+
&dev_attr_wakeup_active.attr,
460+
&dev_attr_wakeup_total_time_ms.attr,
461+
&dev_attr_wakeup_max_time_ms.attr,
462+
&dev_attr_wakeup_last_time_ms.attr,
463+
#endif
464+
NULL,
465+
};
466+
static struct attribute_group pm_wakeup_attr_group = {
467+
.name = power_group_name,
468+
.attrs = wakeup_attrs,
469+
};
462470

463471
static struct attribute *runtime_attrs[] = {
472+
#ifdef CONFIG_PM_RUNTIME
464473
#ifndef CONFIG_PM_ADVANCED_DEBUG
465474
&dev_attr_runtime_status.attr,
466475
#endif
467476
&dev_attr_control.attr,
468477
&dev_attr_runtime_suspended_time.attr,
469478
&dev_attr_runtime_active_time.attr,
470479
&dev_attr_autosuspend_delay_ms.attr,
480+
#endif /* CONFIG_PM_RUNTIME */
471481
NULL,
472482
};
473483
static struct attribute_group pm_runtime_attr_group = {
@@ -480,35 +490,49 @@ int dpm_sysfs_add(struct device *dev)
480490
int rc;
481491

482492
rc = sysfs_create_group(&dev->kobj, &pm_attr_group);
483-
if (rc == 0 && !dev->power.no_callbacks) {
493+
if (rc)
494+
return rc;
495+
496+
if (pm_runtime_callbacks_present(dev)) {
484497
rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group);
485498
if (rc)
486-
sysfs_remove_group(&dev->kobj, &pm_attr_group);
499+
goto err_out;
500+
}
501+
502+
if (device_can_wakeup(dev)) {
503+
rc = sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
504+
if (rc) {
505+
if (pm_runtime_callbacks_present(dev))
506+
sysfs_unmerge_group(&dev->kobj,
507+
&pm_runtime_attr_group);
508+
goto err_out;
509+
}
487510
}
511+
return 0;
512+
513+
err_out:
514+
sysfs_remove_group(&dev->kobj, &pm_attr_group);
488515
return rc;
489516
}
490517

491-
void rpm_sysfs_remove(struct device *dev)
518+
int wakeup_sysfs_add(struct device *dev)
492519
{
493-
sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
520+
return sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
494521
}
495522

496-
void dpm_sysfs_remove(struct device *dev)
523+
void wakeup_sysfs_remove(struct device *dev)
497524
{
498-
rpm_sysfs_remove(dev);
499-
sysfs_remove_group(&dev->kobj, &pm_attr_group);
525+
sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
500526
}
501527

502-
#else /* CONFIG_PM_RUNTIME */
503-
504-
int dpm_sysfs_add(struct device * dev)
528+
void rpm_sysfs_remove(struct device *dev)
505529
{
506-
return sysfs_create_group(&dev->kobj, &pm_attr_group);
530+
sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
507531
}
508532

509-
void dpm_sysfs_remove(struct device * dev)
533+
void dpm_sysfs_remove(struct device *dev)
510534
{
535+
rpm_sysfs_remove(dev);
536+
sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
511537
sysfs_remove_group(&dev->kobj, &pm_attr_group);
512538
}
513-
514-
#endif

drivers/base/power/wakeup.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,35 @@ int device_wakeup_disable(struct device *dev)
241241
}
242242
EXPORT_SYMBOL_GPL(device_wakeup_disable);
243243

244+
/**
245+
* device_set_wakeup_capable - Set/reset device wakeup capability flag.
246+
* @dev: Device to handle.
247+
* @capable: Whether or not @dev is capable of waking up the system from sleep.
248+
*
249+
* If @capable is set, set the @dev's power.can_wakeup flag and add its
250+
* wakeup-related attributes to sysfs. Otherwise, unset the @dev's
251+
* power.can_wakeup flag and remove its wakeup-related attributes from sysfs.
252+
*
253+
* This function may sleep and it can't be called from any context where
254+
* sleeping is not allowed.
255+
*/
256+
void device_set_wakeup_capable(struct device *dev, bool capable)
257+
{
258+
if (!!dev->power.can_wakeup == !!capable)
259+
return;
260+
261+
if (device_is_registered(dev)) {
262+
if (capable) {
263+
if (wakeup_sysfs_add(dev))
264+
return;
265+
} else {
266+
wakeup_sysfs_remove(dev);
267+
}
268+
}
269+
dev->power.can_wakeup = capable;
270+
}
271+
EXPORT_SYMBOL_GPL(device_set_wakeup_capable);
272+
244273
/**
245274
* device_init_wakeup - Device wakeup initialization.
246275
* @dev: Device to handle.

include/linux/pm_runtime.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ static inline bool pm_runtime_enabled(struct device *dev)
8787
return !dev->power.disable_depth;
8888
}
8989

90+
static inline bool pm_runtime_callbacks_present(struct device *dev)
91+
{
92+
return !dev->power.no_callbacks;
93+
}
94+
9095
static inline void pm_runtime_mark_last_busy(struct device *dev)
9196
{
9297
ACCESS_ONCE(dev->power.last_busy) = jiffies;
@@ -133,6 +138,7 @@ static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
133138
static inline void pm_runtime_no_callbacks(struct device *dev) {}
134139
static inline void pm_runtime_irq_safe(struct device *dev) {}
135140

141+
static inline bool pm_runtime_callbacks_present(struct device *dev) { return false; }
136142
static inline void pm_runtime_mark_last_busy(struct device *dev) {}
137143
static inline void __pm_runtime_use_autosuspend(struct device *dev,
138144
bool use) {}

include/linux/pm_wakeup.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,11 @@ struct wakeup_source {
6262
* Changes to device_may_wakeup take effect on the next pm state change.
6363
*/
6464

65-
static inline void device_set_wakeup_capable(struct device *dev, bool capable)
66-
{
67-
dev->power.can_wakeup = capable;
68-
}
69-
7065
static inline bool device_can_wakeup(struct device *dev)
7166
{
7267
return dev->power.can_wakeup;
7368
}
7469

75-
76-
7770
static inline bool device_may_wakeup(struct device *dev)
7871
{
7972
return dev->power.can_wakeup && !!dev->power.wakeup;
@@ -88,6 +81,7 @@ extern struct wakeup_source *wakeup_source_register(const char *name);
8881
extern void wakeup_source_unregister(struct wakeup_source *ws);
8982
extern int device_wakeup_enable(struct device *dev);
9083
extern int device_wakeup_disable(struct device *dev);
84+
extern void device_set_wakeup_capable(struct device *dev, bool capable);
9185
extern int device_init_wakeup(struct device *dev, bool val);
9286
extern int device_set_wakeup_enable(struct device *dev, bool enable);
9387
extern void __pm_stay_awake(struct wakeup_source *ws);

0 commit comments

Comments
 (0)