aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-02-08 17:26:02 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2011-03-14 19:43:14 -0400
commitcb8f51bdadb7969139c2e39c2defd4cde98c1ea8 (patch)
treea6d6e20878460d50b8f61d5fe3237818c54065eb /drivers/base
parent4681b17154b3fd81f898802262985f662344e6ed (diff)
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>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/power.h21
-rw-r--r--drivers/base/power/sysfs.c78
-rw-r--r--drivers/base/power/wakeup.c29
3 files changed, 90 insertions, 38 deletions
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 698dde742587..f2a25f18fde7 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -58,19 +58,18 @@ static inline void device_pm_move_last(struct device *dev) {}
58 * sysfs.c 58 * sysfs.c
59 */ 59 */
60 60
61extern int dpm_sysfs_add(struct device *); 61extern int dpm_sysfs_add(struct device *dev);
62extern void dpm_sysfs_remove(struct device *); 62extern void dpm_sysfs_remove(struct device *dev);
63extern void rpm_sysfs_remove(struct device *); 63extern void rpm_sysfs_remove(struct device *dev);
64extern int wakeup_sysfs_add(struct device *dev);
65extern void wakeup_sysfs_remove(struct device *dev);
64 66
65#else /* CONFIG_PM */ 67#else /* CONFIG_PM */
66 68
67static inline int dpm_sysfs_add(struct device *dev) 69static inline int dpm_sysfs_add(struct device *dev) { return 0; }
68{ 70static inline void dpm_sysfs_remove(struct device *dev) {}
69 return 0; 71static inline void rpm_sysfs_remove(struct device *dev) {}
70} 72static inline int wakeup_sysfs_add(struct device *dev) { return 0; }
71 73static inline void wakeup_sysfs_remove(struct device *dev) {}
72static inline void dpm_sysfs_remove(struct device *dev)
73{
74}
75 74
76#endif 75#endif
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 0b1e46bf3e56..fff49bee781d 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -431,26 +431,18 @@ static ssize_t async_store(struct device *dev, struct device_attribute *attr,
431static DEVICE_ATTR(async, 0644, async_show, async_store); 431static DEVICE_ATTR(async, 0644, async_show, async_store);
432#endif /* CONFIG_PM_ADVANCED_DEBUG */ 432#endif /* CONFIG_PM_ADVANCED_DEBUG */
433 433
434static struct attribute * power_attrs[] = { 434static 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
445#ifdef CONFIG_PM_ADVANCED_DEBUG 435#ifdef CONFIG_PM_ADVANCED_DEBUG
436#ifdef CONFIG_PM_SLEEP
446 &dev_attr_async.attr, 437 &dev_attr_async.attr,
438#endif
447#ifdef CONFIG_PM_RUNTIME 439#ifdef CONFIG_PM_RUNTIME
448 &dev_attr_runtime_status.attr, 440 &dev_attr_runtime_status.attr,
449 &dev_attr_runtime_usage.attr, 441 &dev_attr_runtime_usage.attr,
450 &dev_attr_runtime_active_kids.attr, 442 &dev_attr_runtime_active_kids.attr,
451 &dev_attr_runtime_enabled.attr, 443 &dev_attr_runtime_enabled.attr,
452#endif 444#endif
453#endif 445#endif /* CONFIG_PM_ADVANCED_DEBUG */
454 NULL, 446 NULL,
455}; 447};
456static struct attribute_group pm_attr_group = { 448static struct attribute_group pm_attr_group = {
@@ -458,9 +450,26 @@ static struct attribute_group pm_attr_group = {
458 .attrs = power_attrs, 450 .attrs = power_attrs,
459}; 451};
460 452
461#ifdef CONFIG_PM_RUNTIME 453static 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};
466static struct attribute_group pm_wakeup_attr_group = {
467 .name = power_group_name,
468 .attrs = wakeup_attrs,
469};
462 470
463static struct attribute *runtime_attrs[] = { 471static struct attribute *runtime_attrs[] = {
472#ifdef CONFIG_PM_RUNTIME
464#ifndef CONFIG_PM_ADVANCED_DEBUG 473#ifndef CONFIG_PM_ADVANCED_DEBUG
465 &dev_attr_runtime_status.attr, 474 &dev_attr_runtime_status.attr,
466#endif 475#endif
@@ -468,6 +477,7 @@ static struct attribute *runtime_attrs[] = {
468 &dev_attr_runtime_suspended_time.attr, 477 &dev_attr_runtime_suspended_time.attr,
469 &dev_attr_runtime_active_time.attr, 478 &dev_attr_runtime_active_time.attr,
470 &dev_attr_autosuspend_delay_ms.attr, 479 &dev_attr_autosuspend_delay_ms.attr,
480#endif /* CONFIG_PM_RUNTIME */
471 NULL, 481 NULL,
472}; 482};
473static struct attribute_group pm_runtime_attr_group = { 483static struct attribute_group pm_runtime_attr_group = {
@@ -480,35 +490,49 @@ int dpm_sysfs_add(struct device *dev)
480 int rc; 490 int rc;
481 491
482 rc = sysfs_create_group(&dev->kobj, &pm_attr_group); 492 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)) {
484 rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group); 497 rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group);
485 if (rc) 498 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 }
487 } 510 }
511 return 0;
512
513 err_out:
514 sysfs_remove_group(&dev->kobj, &pm_attr_group);
488 return rc; 515 return rc;
489} 516}
490 517
491void rpm_sysfs_remove(struct device *dev) 518int wakeup_sysfs_add(struct device *dev)
492{ 519{
493 sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group); 520 return sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
494} 521}
495 522
496void dpm_sysfs_remove(struct device *dev) 523void wakeup_sysfs_remove(struct device *dev)
497{ 524{
498 rpm_sysfs_remove(dev); 525 sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
499 sysfs_remove_group(&dev->kobj, &pm_attr_group);
500} 526}
501 527
502#else /* CONFIG_PM_RUNTIME */ 528void rpm_sysfs_remove(struct device *dev)
503
504int dpm_sysfs_add(struct device * dev)
505{ 529{
506 return sysfs_create_group(&dev->kobj, &pm_attr_group); 530 sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
507} 531}
508 532
509void dpm_sysfs_remove(struct device * dev) 533void dpm_sysfs_remove(struct device *dev)
510{ 534{
535 rpm_sysfs_remove(dev);
536 sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
511 sysfs_remove_group(&dev->kobj, &pm_attr_group); 537 sysfs_remove_group(&dev->kobj, &pm_attr_group);
512} 538}
513
514#endif
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 82836383997f..4573c83df6dd 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -242,6 +242,35 @@ int device_wakeup_disable(struct device *dev)
242EXPORT_SYMBOL_GPL(device_wakeup_disable); 242EXPORT_SYMBOL_GPL(device_wakeup_disable);
243 243
244/** 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 */
256void 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}
271EXPORT_SYMBOL_GPL(device_set_wakeup_capable);
272
273/**
245 * device_init_wakeup - Device wakeup initialization. 274 * device_init_wakeup - Device wakeup initialization.
246 * @dev: Device to handle. 275 * @dev: Device to handle.
247 * @enable: Whether or not to enable @dev as a wakeup device. 276 * @enable: Whether or not to enable @dev as a wakeup device.