aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-09-22 16:09:10 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2010-10-16 19:57:43 -0400
commit074037ec79bea73edf1b1ec72fef1010e83e3cc5 (patch)
tree1876caa07f755e680da5ea102d985efe4b508d56 /drivers/base
parent0702d9ee0f1dcb6258789032f03b3208bfafaffc (diff)
PM / Wakeup: Introduce wakeup source objects and event statistics (v3)
Introduce struct wakeup_source for representing system wakeup sources within the kernel and for collecting statistics related to them. Make the recently introduced helper functions pm_wakeup_event(), pm_stay_awake() and pm_relax() use struct wakeup_source objects internally, so that wakeup statistics associated with wakeup devices can be collected and reported in a consistent way (the definition of pm_relax() is changed, which is harmless, because this function is not called directly by anyone yet). Introduce new wakeup-related sysfs device attributes in /sys/devices/.../power for reporting the device wakeup statistics. Change the global wakeup events counters event_count and events_in_progress into atomic variables, so that it is not necessary to acquire a global spinlock in pm_wakeup_event(), pm_stay_awake() and pm_relax(), which should allow us to avoid lock contention in these functions on SMP systems with many wakeup devices. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/power/main.c4
-rw-r--r--drivers/base/power/power.h1
-rw-r--r--drivers/base/power/runtime.c2
-rw-r--r--drivers/base/power/sysfs.c121
-rw-r--r--drivers/base/power/wakeup.c528
5 files changed, 573 insertions, 83 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index db677199403..7ae6fe414c3 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -60,7 +60,8 @@ void device_pm_init(struct device *dev)
60 dev->power.status = DPM_ON; 60 dev->power.status = DPM_ON;
61 init_completion(&dev->power.completion); 61 init_completion(&dev->power.completion);
62 complete_all(&dev->power.completion); 62 complete_all(&dev->power.completion);
63 dev->power.wakeup_count = 0; 63 dev->power.wakeup = NULL;
64 spin_lock_init(&dev->power.lock);
64 pm_runtime_init(dev); 65 pm_runtime_init(dev);
65} 66}
66 67
@@ -120,6 +121,7 @@ void device_pm_remove(struct device *dev)
120 mutex_lock(&dpm_list_mtx); 121 mutex_lock(&dpm_list_mtx);
121 list_del_init(&dev->power.entry); 122 list_del_init(&dev->power.entry);
122 mutex_unlock(&dpm_list_mtx); 123 mutex_unlock(&dpm_list_mtx);
124 device_wakeup_disable(dev);
123 pm_runtime_remove(dev); 125 pm_runtime_remove(dev);
124} 126}
125 127
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index c0bd03c83b9..8b2745c69e2 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -34,6 +34,7 @@ extern void device_pm_move_last(struct device *);
34 34
35static inline void device_pm_init(struct device *dev) 35static inline void device_pm_init(struct device *dev)
36{ 36{
37 spin_lock_init(&dev->power.lock);
37 pm_runtime_init(dev); 38 pm_runtime_init(dev);
38} 39}
39 40
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index b78c401ffa7..e9520ad2d71 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1099,8 +1099,6 @@ EXPORT_SYMBOL_GPL(pm_runtime_allow);
1099 */ 1099 */
1100void pm_runtime_init(struct device *dev) 1100void pm_runtime_init(struct device *dev)
1101{ 1101{
1102 spin_lock_init(&dev->power.lock);
1103
1104 dev->power.runtime_status = RPM_SUSPENDED; 1102 dev->power.runtime_status = RPM_SUSPENDED;
1105 dev->power.idle_notification = false; 1103 dev->power.idle_notification = false;
1106 1104
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index e56b4388fe6..8859780817e 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -210,11 +210,122 @@ static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
210static ssize_t wakeup_count_show(struct device *dev, 210static ssize_t wakeup_count_show(struct device *dev,
211 struct device_attribute *attr, char *buf) 211 struct device_attribute *attr, char *buf)
212{ 212{
213 return sprintf(buf, "%lu\n", dev->power.wakeup_count); 213 unsigned long count = 0;
214 bool enabled = false;
215
216 spin_lock_irq(&dev->power.lock);
217 if (dev->power.wakeup) {
218 count = dev->power.wakeup->event_count;
219 enabled = true;
220 }
221 spin_unlock_irq(&dev->power.lock);
222 return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
214} 223}
215 224
216static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL); 225static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL);
217#endif 226
227static ssize_t wakeup_active_count_show(struct device *dev,
228 struct device_attribute *attr, char *buf)
229{
230 unsigned long count = 0;
231 bool enabled = false;
232
233 spin_lock_irq(&dev->power.lock);
234 if (dev->power.wakeup) {
235 count = dev->power.wakeup->active_count;
236 enabled = true;
237 }
238 spin_unlock_irq(&dev->power.lock);
239 return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
240}
241
242static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL);
243
244static ssize_t wakeup_hit_count_show(struct device *dev,
245 struct device_attribute *attr, char *buf)
246{
247 unsigned long count = 0;
248 bool enabled = false;
249
250 spin_lock_irq(&dev->power.lock);
251 if (dev->power.wakeup) {
252 count = dev->power.wakeup->hit_count;
253 enabled = true;
254 }
255 spin_unlock_irq(&dev->power.lock);
256 return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
257}
258
259static DEVICE_ATTR(wakeup_hit_count, 0444, wakeup_hit_count_show, NULL);
260
261static ssize_t wakeup_active_show(struct device *dev,
262 struct device_attribute *attr, char *buf)
263{
264 unsigned int active = 0;
265 bool enabled = false;
266
267 spin_lock_irq(&dev->power.lock);
268 if (dev->power.wakeup) {
269 active = dev->power.wakeup->active;
270 enabled = true;
271 }
272 spin_unlock_irq(&dev->power.lock);
273 return enabled ? sprintf(buf, "%u\n", active) : sprintf(buf, "\n");
274}
275
276static DEVICE_ATTR(wakeup_active, 0444, wakeup_active_show, NULL);
277
278static ssize_t wakeup_total_time_show(struct device *dev,
279 struct device_attribute *attr, char *buf)
280{
281 s64 msec = 0;
282 bool enabled = false;
283
284 spin_lock_irq(&dev->power.lock);
285 if (dev->power.wakeup) {
286 msec = ktime_to_ms(dev->power.wakeup->total_time);
287 enabled = true;
288 }
289 spin_unlock_irq(&dev->power.lock);
290 return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
291}
292
293static DEVICE_ATTR(wakeup_total_time_ms, 0444, wakeup_total_time_show, NULL);
294
295static ssize_t wakeup_max_time_show(struct device *dev,
296 struct device_attribute *attr, char *buf)
297{
298 s64 msec = 0;
299 bool enabled = false;
300
301 spin_lock_irq(&dev->power.lock);
302 if (dev->power.wakeup) {
303 msec = ktime_to_ms(dev->power.wakeup->max_time);
304 enabled = true;
305 }
306 spin_unlock_irq(&dev->power.lock);
307 return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
308}
309
310static DEVICE_ATTR(wakeup_max_time_ms, 0444, wakeup_max_time_show, NULL);
311
312static ssize_t wakeup_last_time_show(struct device *dev,
313 struct device_attribute *attr, char *buf)
314{
315 s64 msec = 0;
316 bool enabled = false;
317
318 spin_lock_irq(&dev->power.lock);
319 if (dev->power.wakeup) {
320 msec = ktime_to_ms(dev->power.wakeup->last_time);
321 enabled = true;
322 }
323 spin_unlock_irq(&dev->power.lock);
324 return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
325}
326
327static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL);
328#endif /* CONFIG_PM_SLEEP */
218 329
219#ifdef CONFIG_PM_ADVANCED_DEBUG 330#ifdef CONFIG_PM_ADVANCED_DEBUG
220#ifdef CONFIG_PM_RUNTIME 331#ifdef CONFIG_PM_RUNTIME
@@ -288,6 +399,12 @@ static struct attribute * power_attrs[] = {
288 &dev_attr_wakeup.attr, 399 &dev_attr_wakeup.attr,
289#ifdef CONFIG_PM_SLEEP 400#ifdef CONFIG_PM_SLEEP
290 &dev_attr_wakeup_count.attr, 401 &dev_attr_wakeup_count.attr,
402 &dev_attr_wakeup_active_count.attr,
403 &dev_attr_wakeup_hit_count.attr,
404 &dev_attr_wakeup_active.attr,
405 &dev_attr_wakeup_total_time_ms.attr,
406 &dev_attr_wakeup_max_time_ms.attr,
407 &dev_attr_wakeup_last_time_ms.attr,
291#endif 408#endif
292#ifdef CONFIG_PM_ADVANCED_DEBUG 409#ifdef CONFIG_PM_ADVANCED_DEBUG
293 &dev_attr_async.attr, 410 &dev_attr_async.attr,
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index eb594facfc3..03751a01dba 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -11,7 +11,10 @@
11#include <linux/sched.h> 11#include <linux/sched.h>
12#include <linux/capability.h> 12#include <linux/capability.h>
13#include <linux/suspend.h> 13#include <linux/suspend.h>
14#include <linux/pm.h> 14
15#include "power.h"
16
17#define TIMEOUT 100
15 18
16/* 19/*
17 * If set, the suspend/hibernate code will abort transitions to a sleep state 20 * If set, the suspend/hibernate code will abort transitions to a sleep state
@@ -20,18 +23,244 @@
20bool events_check_enabled; 23bool events_check_enabled;
21 24
22/* The counter of registered wakeup events. */ 25/* The counter of registered wakeup events. */
23static unsigned long event_count; 26static atomic_t event_count = ATOMIC_INIT(0);
24/* A preserved old value of event_count. */ 27/* A preserved old value of event_count. */
25static unsigned long saved_event_count; 28static unsigned int saved_count;
26/* The counter of wakeup events being processed. */ 29/* The counter of wakeup events being processed. */
27static unsigned long events_in_progress; 30static atomic_t events_in_progress = ATOMIC_INIT(0);
28 31
29static DEFINE_SPINLOCK(events_lock); 32static DEFINE_SPINLOCK(events_lock);
30 33
31static void pm_wakeup_timer_fn(unsigned long data); 34static void pm_wakeup_timer_fn(unsigned long data);
32 35
33static DEFINE_TIMER(events_timer, pm_wakeup_timer_fn, 0, 0); 36static LIST_HEAD(wakeup_sources);
34static unsigned long events_timer_expires; 37
38/**
39 * wakeup_source_create - Create a struct wakeup_source object.
40 * @name: Name of the new wakeup source.
41 */
42struct wakeup_source *wakeup_source_create(const char *name)
43{
44 struct wakeup_source *ws;
45
46 ws = kzalloc(sizeof(*ws), GFP_KERNEL);
47 if (!ws)
48 return NULL;
49
50 spin_lock_init(&ws->lock);
51 if (name)
52 ws->name = kstrdup(name, GFP_KERNEL);
53
54 return ws;
55}
56EXPORT_SYMBOL_GPL(wakeup_source_create);
57
58/**
59 * wakeup_source_destroy - Destroy a struct wakeup_source object.
60 * @ws: Wakeup source to destroy.
61 */
62void wakeup_source_destroy(struct wakeup_source *ws)
63{
64 if (!ws)
65 return;
66
67 spin_lock_irq(&ws->lock);
68 while (ws->active) {
69 spin_unlock_irq(&ws->lock);
70
71 schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT));
72
73 spin_lock_irq(&ws->lock);
74 }
75 spin_unlock_irq(&ws->lock);
76
77 kfree(ws->name);
78 kfree(ws);
79}
80EXPORT_SYMBOL_GPL(wakeup_source_destroy);
81
82/**
83 * wakeup_source_add - Add given object to the list of wakeup sources.
84 * @ws: Wakeup source object to add to the list.
85 */
86void wakeup_source_add(struct wakeup_source *ws)
87{
88 if (WARN_ON(!ws))
89 return;
90
91 setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);
92 ws->active = false;
93
94 spin_lock_irq(&events_lock);
95 list_add_rcu(&ws->entry, &wakeup_sources);
96 spin_unlock_irq(&events_lock);
97 synchronize_rcu();
98}
99EXPORT_SYMBOL_GPL(wakeup_source_add);
100
101/**
102 * wakeup_source_remove - Remove given object from the wakeup sources list.
103 * @ws: Wakeup source object to remove from the list.
104 */
105void wakeup_source_remove(struct wakeup_source *ws)
106{
107 if (WARN_ON(!ws))
108 return;
109
110 spin_lock_irq(&events_lock);
111 list_del_rcu(&ws->entry);
112 spin_unlock_irq(&events_lock);
113 synchronize_rcu();
114}
115EXPORT_SYMBOL_GPL(wakeup_source_remove);
116
117/**
118 * wakeup_source_register - Create wakeup source and add it to the list.
119 * @name: Name of the wakeup source to register.
120 */
121struct wakeup_source *wakeup_source_register(const char *name)
122{
123 struct wakeup_source *ws;
124
125 ws = wakeup_source_create(name);
126 if (ws)
127 wakeup_source_add(ws);
128
129 return ws;
130}
131EXPORT_SYMBOL_GPL(wakeup_source_register);
132
133/**
134 * wakeup_source_unregister - Remove wakeup source from the list and remove it.
135 * @ws: Wakeup source object to unregister.
136 */
137void wakeup_source_unregister(struct wakeup_source *ws)
138{
139 wakeup_source_remove(ws);
140 wakeup_source_destroy(ws);
141}
142EXPORT_SYMBOL_GPL(wakeup_source_unregister);
143
144/**
145 * device_wakeup_attach - Attach a wakeup source object to a device object.
146 * @dev: Device to handle.
147 * @ws: Wakeup source object to attach to @dev.
148 *
149 * This causes @dev to be treated as a wakeup device.
150 */
151static int device_wakeup_attach(struct device *dev, struct wakeup_source *ws)
152{
153 spin_lock_irq(&dev->power.lock);
154 if (dev->power.wakeup) {
155 spin_unlock_irq(&dev->power.lock);
156 return -EEXIST;
157 }
158 dev->power.wakeup = ws;
159 spin_unlock_irq(&dev->power.lock);
160 return 0;
161}
162
163/**
164 * device_wakeup_enable - Enable given device to be a wakeup source.
165 * @dev: Device to handle.
166 *
167 * Create a wakeup source object, register it and attach it to @dev.
168 */
169int device_wakeup_enable(struct device *dev)
170{
171 struct wakeup_source *ws;
172 int ret;
173
174 if (!dev || !dev->power.can_wakeup)
175 return -EINVAL;
176
177 ws = wakeup_source_register(dev_name(dev));
178 if (!ws)
179 return -ENOMEM;
180
181 ret = device_wakeup_attach(dev, ws);
182 if (ret)
183 wakeup_source_unregister(ws);
184
185 return ret;
186}
187EXPORT_SYMBOL_GPL(device_wakeup_enable);
188
189/**
190 * device_wakeup_detach - Detach a device's wakeup source object from it.
191 * @dev: Device to detach the wakeup source object from.
192 *
193 * After it returns, @dev will not be treated as a wakeup device any more.
194 */
195static struct wakeup_source *device_wakeup_detach(struct device *dev)
196{
197 struct wakeup_source *ws;
198
199 spin_lock_irq(&dev->power.lock);
200 ws = dev->power.wakeup;
201 dev->power.wakeup = NULL;
202 spin_unlock_irq(&dev->power.lock);
203 return ws;
204}
205
206/**
207 * device_wakeup_disable - Do not regard a device as a wakeup source any more.
208 * @dev: Device to handle.
209 *
210 * Detach the @dev's wakeup source object from it, unregister this wakeup source
211 * object and destroy it.
212 */
213int device_wakeup_disable(struct device *dev)
214{
215 struct wakeup_source *ws;
216
217 if (!dev || !dev->power.can_wakeup)
218 return -EINVAL;
219
220 ws = device_wakeup_detach(dev);
221 if (ws)
222 wakeup_source_unregister(ws);
223
224 return 0;
225}
226EXPORT_SYMBOL_GPL(device_wakeup_disable);
227
228/**
229 * device_init_wakeup - Device wakeup initialization.
230 * @dev: Device to handle.
231 * @enable: Whether or not to enable @dev as a wakeup device.
232 *
233 * By default, most devices should leave wakeup disabled. The exceptions are
234 * devices that everyone expects to be wakeup sources: keyboards, power buttons,
235 * possibly network interfaces, etc.
236 */
237int device_init_wakeup(struct device *dev, bool enable)
238{
239 int ret = 0;
240
241 if (enable) {
242 device_set_wakeup_capable(dev, true);
243 ret = device_wakeup_enable(dev);
244 } else {
245 device_set_wakeup_capable(dev, false);
246 }
247
248 return ret;
249}
250EXPORT_SYMBOL_GPL(device_init_wakeup);
251
252/**
253 * device_set_wakeup_enable - Enable or disable a device to wake up the system.
254 * @dev: Device to handle.
255 */
256int device_set_wakeup_enable(struct device *dev, bool enable)
257{
258 if (!dev || !dev->power.can_wakeup)
259 return -EINVAL;
260
261 return enable ? device_wakeup_enable(dev) : device_wakeup_disable(dev);
262}
263EXPORT_SYMBOL_GPL(device_set_wakeup_enable);
35 264
36/* 265/*
37 * The functions below use the observation that each wakeup event starts a 266 * The functions below use the observation that each wakeup event starts a
@@ -55,118 +284,259 @@ static unsigned long events_timer_expires;
55 * knowledge, however, may not be available to it, so it can simply specify time 284 * knowledge, however, may not be available to it, so it can simply specify time
56 * to wait before the system can be suspended and pass it as the second 285 * to wait before the system can be suspended and pass it as the second
57 * argument of pm_wakeup_event(). 286 * argument of pm_wakeup_event().
287 *
288 * It is valid to call pm_relax() after pm_wakeup_event(), in which case the
289 * "no suspend" period will be ended either by the pm_relax(), or by the timer
290 * function executed when the timer expires, whichever comes first.
58 */ 291 */
59 292
60/** 293/**
294 * wakup_source_activate - Mark given wakeup source as active.
295 * @ws: Wakeup source to handle.
296 *
297 * Update the @ws' statistics and, if @ws has just been activated, notify the PM
298 * core of the event by incrementing the counter of of wakeup events being
299 * processed.
300 */
301static void wakeup_source_activate(struct wakeup_source *ws)
302{
303 ws->active = true;
304 ws->active_count++;
305 ws->timer_expires = jiffies;
306 ws->last_time = ktime_get();
307
308 atomic_inc(&events_in_progress);
309}
310
311/**
312 * __pm_stay_awake - Notify the PM core of a wakeup event.
313 * @ws: Wakeup source object associated with the source of the event.
314 *
315 * It is safe to call this function from interrupt context.
316 */
317void __pm_stay_awake(struct wakeup_source *ws)
318{
319 unsigned long flags;
320
321 if (!ws)
322 return;
323
324 spin_lock_irqsave(&ws->lock, flags);
325 ws->event_count++;
326 if (!ws->active)
327 wakeup_source_activate(ws);
328 spin_unlock_irqrestore(&ws->lock, flags);
329}
330EXPORT_SYMBOL_GPL(__pm_stay_awake);
331
332/**
61 * pm_stay_awake - Notify the PM core that a wakeup event is being processed. 333 * pm_stay_awake - Notify the PM core that a wakeup event is being processed.
62 * @dev: Device the wakeup event is related to. 334 * @dev: Device the wakeup event is related to.
63 * 335 *
64 * Notify the PM core of a wakeup event (signaled by @dev) by incrementing the 336 * Notify the PM core of a wakeup event (signaled by @dev) by calling
65 * counter of wakeup events being processed. If @dev is not NULL, the counter 337 * __pm_stay_awake for the @dev's wakeup source object.
66 * of wakeup events related to @dev is incremented too.
67 * 338 *
68 * Call this function after detecting of a wakeup event if pm_relax() is going 339 * Call this function after detecting of a wakeup event if pm_relax() is going
69 * to be called directly after processing the event (and possibly passing it to 340 * to be called directly after processing the event (and possibly passing it to
70 * user space for further processing). 341 * user space for further processing).
71 *
72 * It is safe to call this function from interrupt context.
73 */ 342 */
74void pm_stay_awake(struct device *dev) 343void pm_stay_awake(struct device *dev)
75{ 344{
76 unsigned long flags; 345 unsigned long flags;
77 346
78 spin_lock_irqsave(&events_lock, flags); 347 if (!dev)
79 if (dev) 348 return;
80 dev->power.wakeup_count++;
81 349
82 events_in_progress++; 350 spin_lock_irqsave(&dev->power.lock, flags);
83 spin_unlock_irqrestore(&events_lock, flags); 351 __pm_stay_awake(dev->power.wakeup);
352 spin_unlock_irqrestore(&dev->power.lock, flags);
84} 353}
354EXPORT_SYMBOL_GPL(pm_stay_awake);
85 355
86/** 356/**
87 * pm_relax - Notify the PM core that processing of a wakeup event has ended. 357 * wakup_source_deactivate - Mark given wakeup source as inactive.
358 * @ws: Wakeup source to handle.
88 * 359 *
89 * Notify the PM core that a wakeup event has been processed by decrementing 360 * Update the @ws' statistics and notify the PM core that the wakeup source has
90 * the counter of wakeup events being processed and incrementing the counter 361 * become inactive by decrementing the counter of wakeup events being processed
91 * of registered wakeup events. 362 * and incrementing the counter of registered wakeup events.
363 */
364static void wakeup_source_deactivate(struct wakeup_source *ws)
365{
366 ktime_t duration;
367 ktime_t now;
368
369 ws->relax_count++;
370 /*
371 * __pm_relax() may be called directly or from a timer function.
372 * If it is called directly right after the timer function has been
373 * started, but before the timer function calls __pm_relax(), it is
374 * possible that __pm_stay_awake() will be called in the meantime and
375 * will set ws->active. Then, ws->active may be cleared immediately
376 * by the __pm_relax() called from the timer function, but in such a
377 * case ws->relax_count will be different from ws->active_count.
378 */
379 if (ws->relax_count != ws->active_count) {
380 ws->relax_count--;
381 return;
382 }
383
384 ws->active = false;
385
386 now = ktime_get();
387 duration = ktime_sub(now, ws->last_time);
388 ws->total_time = ktime_add(ws->total_time, duration);
389 if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))
390 ws->max_time = duration;
391
392 del_timer(&ws->timer);
393
394 /*
395 * event_count has to be incremented before events_in_progress is
396 * modified, so that the callers of pm_check_wakeup_events() and
397 * pm_save_wakeup_count() don't see the old value of event_count and
398 * events_in_progress equal to zero at the same time.
399 */
400 atomic_inc(&event_count);
401 smp_mb__before_atomic_dec();
402 atomic_dec(&events_in_progress);
403}
404
405/**
406 * __pm_relax - Notify the PM core that processing of a wakeup event has ended.
407 * @ws: Wakeup source object associated with the source of the event.
92 * 408 *
93 * Call this function for wakeup events whose processing started with calling 409 * Call this function for wakeup events whose processing started with calling
94 * pm_stay_awake(). 410 * __pm_stay_awake().
95 * 411 *
96 * It is safe to call it from interrupt context. 412 * It is safe to call it from interrupt context.
97 */ 413 */
98void pm_relax(void) 414void __pm_relax(struct wakeup_source *ws)
99{ 415{
100 unsigned long flags; 416 unsigned long flags;
101 417
102 spin_lock_irqsave(&events_lock, flags); 418 if (!ws)
103 if (events_in_progress) { 419 return;
104 events_in_progress--; 420
105 event_count++; 421 spin_lock_irqsave(&ws->lock, flags);
106 } 422 if (ws->active)
107 spin_unlock_irqrestore(&events_lock, flags); 423 wakeup_source_deactivate(ws);
424 spin_unlock_irqrestore(&ws->lock, flags);
425}
426EXPORT_SYMBOL_GPL(__pm_relax);
427
428/**
429 * pm_relax - Notify the PM core that processing of a wakeup event has ended.
430 * @dev: Device that signaled the event.
431 *
432 * Execute __pm_relax() for the @dev's wakeup source object.
433 */
434void pm_relax(struct device *dev)
435{
436 unsigned long flags;
437
438 if (!dev)
439 return;
440
441 spin_lock_irqsave(&dev->power.lock, flags);
442 __pm_relax(dev->power.wakeup);
443 spin_unlock_irqrestore(&dev->power.lock, flags);
108} 444}
445EXPORT_SYMBOL_GPL(pm_relax);
109 446
110/** 447/**
111 * pm_wakeup_timer_fn - Delayed finalization of a wakeup event. 448 * pm_wakeup_timer_fn - Delayed finalization of a wakeup event.
449 * @data: Address of the wakeup source object associated with the event source.
112 * 450 *
113 * Decrease the counter of wakeup events being processed after it was increased 451 * Call __pm_relax() for the wakeup source whose address is stored in @data.
114 * by pm_wakeup_event().
115 */ 452 */
116static void pm_wakeup_timer_fn(unsigned long data) 453static void pm_wakeup_timer_fn(unsigned long data)
117{ 454{
455 __pm_relax((struct wakeup_source *)data);
456}
457
458/**
459 * __pm_wakeup_event - Notify the PM core of a wakeup event.
460 * @ws: Wakeup source object associated with the event source.
461 * @msec: Anticipated event processing time (in milliseconds).
462 *
463 * Notify the PM core of a wakeup event whose source is @ws that will take
464 * approximately @msec milliseconds to be processed by the kernel. If @ws is
465 * not active, activate it. If @msec is nonzero, set up the @ws' timer to
466 * execute pm_wakeup_timer_fn() in future.
467 *
468 * It is safe to call this function from interrupt context.
469 */
470void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec)
471{
118 unsigned long flags; 472 unsigned long flags;
473 unsigned long expires;
119 474
120 spin_lock_irqsave(&events_lock, flags); 475 if (!ws)
121 if (events_timer_expires 476 return;
122 && time_before_eq(events_timer_expires, jiffies)) { 477
123 events_in_progress--; 478 spin_lock_irqsave(&ws->lock, flags);
124 events_timer_expires = 0; 479
480 ws->event_count++;
481 if (!ws->active)
482 wakeup_source_activate(ws);
483
484 if (!msec) {
485 wakeup_source_deactivate(ws);
486 goto unlock;
125 } 487 }
126 spin_unlock_irqrestore(&events_lock, flags); 488
489 expires = jiffies + msecs_to_jiffies(msec);
490 if (!expires)
491 expires = 1;
492
493 if (time_after(expires, ws->timer_expires)) {
494 mod_timer(&ws->timer, expires);
495 ws->timer_expires = expires;
496 }
497
498 unlock:
499 spin_unlock_irqrestore(&ws->lock, flags);
127} 500}
501EXPORT_SYMBOL_GPL(__pm_wakeup_event);
502
128 503
129/** 504/**
130 * pm_wakeup_event - Notify the PM core of a wakeup event. 505 * pm_wakeup_event - Notify the PM core of a wakeup event.
131 * @dev: Device the wakeup event is related to. 506 * @dev: Device the wakeup event is related to.
132 * @msec: Anticipated event processing time (in milliseconds). 507 * @msec: Anticipated event processing time (in milliseconds).
133 * 508 *
134 * Notify the PM core of a wakeup event (signaled by @dev) that will take 509 * Call __pm_wakeup_event() for the @dev's wakeup source object.
135 * approximately @msec milliseconds to be processed by the kernel. Increment
136 * the counter of registered wakeup events and (if @msec is nonzero) set up
137 * the wakeup events timer to execute pm_wakeup_timer_fn() in future (if the
138 * timer has not been set up already, increment the counter of wakeup events
139 * being processed). If @dev is not NULL, the counter of wakeup events related
140 * to @dev is incremented too.
141 *
142 * It is safe to call this function from interrupt context.
143 */ 510 */
144void pm_wakeup_event(struct device *dev, unsigned int msec) 511void pm_wakeup_event(struct device *dev, unsigned int msec)
145{ 512{
146 unsigned long flags; 513 unsigned long flags;
147 514
148 spin_lock_irqsave(&events_lock, flags); 515 if (!dev)
149 event_count++; 516 return;
150 if (dev)
151 dev->power.wakeup_count++;
152
153 if (msec) {
154 unsigned long expires;
155 517
156 expires = jiffies + msecs_to_jiffies(msec); 518 spin_lock_irqsave(&dev->power.lock, flags);
157 if (!expires) 519 __pm_wakeup_event(dev->power.wakeup, msec);
158 expires = 1; 520 spin_unlock_irqrestore(&dev->power.lock, flags);
521}
522EXPORT_SYMBOL_GPL(pm_wakeup_event);
159 523
160 if (!events_timer_expires 524/**
161 || time_after(expires, events_timer_expires)) { 525 * pm_wakeup_update_hit_counts - Update hit counts of all active wakeup sources.
162 if (!events_timer_expires) 526 */
163 events_in_progress++; 527static void pm_wakeup_update_hit_counts(void)
528{
529 unsigned long flags;
530 struct wakeup_source *ws;
164 531
165 mod_timer(&events_timer, expires); 532 rcu_read_lock();
166 events_timer_expires = expires; 533 list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
167 } 534 spin_lock_irqsave(&ws->lock, flags);
535 if (ws->active)
536 ws->hit_count++;
537 spin_unlock_irqrestore(&ws->lock, flags);
168 } 538 }
169 spin_unlock_irqrestore(&events_lock, flags); 539 rcu_read_unlock();
170} 540}
171 541
172/** 542/**
@@ -184,10 +554,13 @@ bool pm_check_wakeup_events(void)
184 554
185 spin_lock_irqsave(&events_lock, flags); 555 spin_lock_irqsave(&events_lock, flags);
186 if (events_check_enabled) { 556 if (events_check_enabled) {
187 ret = (event_count == saved_event_count) && !events_in_progress; 557 ret = ((unsigned int)atomic_read(&event_count) == saved_count)
558 && !atomic_read(&events_in_progress);
188 events_check_enabled = ret; 559 events_check_enabled = ret;
189 } 560 }
190 spin_unlock_irqrestore(&events_lock, flags); 561 spin_unlock_irqrestore(&events_lock, flags);
562 if (!ret)
563 pm_wakeup_update_hit_counts();
191 return ret; 564 return ret;
192} 565}
193 566
@@ -202,24 +575,20 @@ bool pm_check_wakeup_events(void)
202 * drop down to zero has been interrupted by a signal (and the current number 575 * drop down to zero has been interrupted by a signal (and the current number
203 * of wakeup events being processed is still nonzero). Otherwise return true. 576 * of wakeup events being processed is still nonzero). Otherwise return true.
204 */ 577 */
205bool pm_get_wakeup_count(unsigned long *count) 578bool pm_get_wakeup_count(unsigned int *count)
206{ 579{
207 bool ret; 580 bool ret;
208 581
209 spin_lock_irq(&events_lock);
210 if (capable(CAP_SYS_ADMIN)) 582 if (capable(CAP_SYS_ADMIN))
211 events_check_enabled = false; 583 events_check_enabled = false;
212 584
213 while (events_in_progress && !signal_pending(current)) { 585 while (atomic_read(&events_in_progress) && !signal_pending(current)) {
214 spin_unlock_irq(&events_lock); 586 pm_wakeup_update_hit_counts();
215 587 schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT));
216 schedule_timeout_interruptible(msecs_to_jiffies(100));
217
218 spin_lock_irq(&events_lock);
219 } 588 }
220 *count = event_count; 589
221 ret = !events_in_progress; 590 ret = !atomic_read(&events_in_progress);
222 spin_unlock_irq(&events_lock); 591 *count = atomic_read(&event_count);
223 return ret; 592 return ret;
224} 593}
225 594
@@ -232,16 +601,19 @@ bool pm_get_wakeup_count(unsigned long *count)
232 * old number of registered wakeup events to be used by pm_check_wakeup_events() 601 * old number of registered wakeup events to be used by pm_check_wakeup_events()
233 * and return true. Otherwise return false. 602 * and return true. Otherwise return false.
234 */ 603 */
235bool pm_save_wakeup_count(unsigned long count) 604bool pm_save_wakeup_count(unsigned int count)
236{ 605{
237 bool ret = false; 606 bool ret = false;
238 607
239 spin_lock_irq(&events_lock); 608 spin_lock_irq(&events_lock);
240 if (count == event_count && !events_in_progress) { 609 if (count == (unsigned int)atomic_read(&event_count)
241 saved_event_count = count; 610 && !atomic_read(&events_in_progress)) {
611 saved_count = count;
242 events_check_enabled = true; 612 events_check_enabled = true;
243 ret = true; 613 ret = true;
244 } 614 }
245 spin_unlock_irq(&events_lock); 615 spin_unlock_irq(&events_lock);
616 if (!ret)
617 pm_wakeup_update_hit_counts();
246 return ret; 618 return ret;
247} 619}