aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/sysfs.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-07-05 16:43:53 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2010-07-18 19:58:48 -0400
commitc125e96f044427f38d106fab7bc5e4a5e6a18262 (patch)
treed9bbd40cc933fe522dbdf8ca2f7edf7b6f2f7ca4 /drivers/base/power/sysfs.c
parentb14e033e17d0ea0ba12668d0d2f371cd31586994 (diff)
PM: Make it possible to avoid races between wakeup and system sleep
One of the arguments during the suspend blockers discussion was that the mainline kernel didn't contain any mechanisms making it possible to avoid races between wakeup and system suspend. Generally, there are two problems in that area. First, if a wakeup event occurs exactly when /sys/power/state is being written to, it may be delivered to user space right before the freezer kicks in, so the user space consumer of the event may not be able to process it before the system is suspended. Second, if a wakeup event occurs after user space has been frozen, it is not generally guaranteed that the ongoing transition of the system into a sleep state will be aborted. To address these issues introduce a new global sysfs attribute, /sys/power/wakeup_count, associated with a running counter of wakeup events and three helper functions, pm_stay_awake(), pm_relax(), and pm_wakeup_event(), that may be used by kernel subsystems to control the behavior of this attribute and to request the PM core to abort system transitions into a sleep state already in progress. The /sys/power/wakeup_count file may be read from or written to by user space. Reads will always succeed (unless interrupted by a signal) and return the current value of the wakeup events counter. Writes, however, will only succeed if the written number is equal to the current value of the wakeup events counter. If a write is successful, it will cause the kernel to save the current value of the wakeup events counter and to abort the subsequent system transition into a sleep state if any wakeup events are reported after the write has returned. [The assumption is that before writing to /sys/power/state user space will first read from /sys/power/wakeup_count. Next, user space consumers of wakeup events will have a chance to acknowledge or veto the upcoming system transition to a sleep state. Finally, if the transition is allowed to proceed, /sys/power/wakeup_count will be written to and if that succeeds, /sys/power/state will be written to as well. Still, if any wakeup events are reported to the PM core by kernel subsystems after that point, the transition will be aborted.] Additionally, put a wakeup events counter into struct dev_pm_info and make these per-device wakeup event counters available via sysfs, so that it's possible to check the activity of various wakeup event sources within the kernel. To illustrate how subsystems can use pm_wakeup_event(), make the low-level PCI runtime PM wakeup-handling code use it. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org> Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Acked-by: markgross <markgross@thegnar.org> Reviewed-by: Alan Stern <stern@rowland.harvard.edu>
Diffstat (limited to 'drivers/base/power/sysfs.c')
-rw-r--r--drivers/base/power/sysfs.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index a4c33bc5125..81d344e0e95 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -73,6 +73,8 @@
73 * device are known to the PM core. However, for some devices this 73 * device are known to the PM core. However, for some devices this
74 * attribute is set to "enabled" by bus type code or device drivers and in 74 * attribute is set to "enabled" by bus type code or device drivers and in
75 * that cases it should be safe to leave the default value. 75 * that cases it should be safe to leave the default value.
76 *
77 * wakeup_count - Report the number of wakeup events related to the device
76 */ 78 */
77 79
78static const char enabled[] = "enabled"; 80static const char enabled[] = "enabled";
@@ -144,6 +146,16 @@ wake_store(struct device * dev, struct device_attribute *attr,
144 146
145static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); 147static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
146 148
149#ifdef CONFIG_PM_SLEEP
150static ssize_t wakeup_count_show(struct device *dev,
151 struct device_attribute *attr, char *buf)
152{
153 return sprintf(buf, "%lu\n", dev->power.wakeup_count);
154}
155
156static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL);
157#endif
158
147#ifdef CONFIG_PM_ADVANCED_DEBUG 159#ifdef CONFIG_PM_ADVANCED_DEBUG
148#ifdef CONFIG_PM_RUNTIME 160#ifdef CONFIG_PM_RUNTIME
149 161
@@ -230,6 +242,9 @@ static struct attribute * power_attrs[] = {
230 &dev_attr_control.attr, 242 &dev_attr_control.attr,
231#endif 243#endif
232 &dev_attr_wakeup.attr, 244 &dev_attr_wakeup.attr,
245#ifdef CONFIG_PM_SLEEP
246 &dev_attr_wakeup_count.attr,
247#endif
233#ifdef CONFIG_PM_ADVANCED_DEBUG 248#ifdef CONFIG_PM_ADVANCED_DEBUG
234 &dev_attr_async.attr, 249 &dev_attr_async.attr,
235#ifdef CONFIG_PM_RUNTIME 250#ifdef CONFIG_PM_RUNTIME