blob: 2583856fab315aadceacf4a822f3ca00a094628a [file] [log] [blame]
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -07001/* kernel/power/wakelock.c
2 *
3 * Copyright (C) 2005-2008 Google, Inc.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/rtc.h>
19#include <linux/suspend.h>
20#include <linux/syscalls.h> /* sys_sync */
21#include <linux/wakelock.h>
22#ifdef CONFIG_WAKELOCK_STAT
23#include <linux/proc_fs.h>
24#endif
25#include "power.h"
26
27enum {
28 DEBUG_EXIT_SUSPEND = 1U << 0,
29 DEBUG_WAKEUP = 1U << 1,
30 DEBUG_SUSPEND = 1U << 2,
31 DEBUG_EXPIRE = 1U << 3,
32 DEBUG_WAKE_LOCK = 1U << 4,
33};
34static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP;
35module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
36
37#define WAKE_LOCK_TYPE_MASK (0x0f)
38#define WAKE_LOCK_INITIALIZED (1U << 8)
39#define WAKE_LOCK_ACTIVE (1U << 9)
40#define WAKE_LOCK_AUTO_EXPIRE (1U << 10)
41#define WAKE_LOCK_PREVENTING_SUSPEND (1U << 11)
42
43static DEFINE_SPINLOCK(list_lock);
44static LIST_HEAD(inactive_locks);
45static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT];
46static int current_event_num;
Pratik Patel529461b2011-07-21 19:13:34 -070047static int suspend_sys_sync_count;
48static DEFINE_SPINLOCK(suspend_sys_sync_lock);
49static struct workqueue_struct *suspend_sys_sync_work_queue;
50static DECLARE_COMPLETION(suspend_sys_sync_comp);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -070051struct workqueue_struct *suspend_work_queue;
52struct wake_lock main_wake_lock;
53suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
54static struct wake_lock unknown_wakeup;
Todd Poynor7013f492011-08-25 19:29:45 -070055static struct wake_lock suspend_backoff_lock;
56
57#define SUSPEND_BACKOFF_THRESHOLD 10
58#define SUSPEND_BACKOFF_INTERVAL 10000
59
60static unsigned suspend_short_count;
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -070061
62#ifdef CONFIG_WAKELOCK_STAT
63static struct wake_lock deleted_wake_locks;
64static ktime_t last_sleep_time_update;
65static int wait_for_wakeup;
66
67int get_expired_time(struct wake_lock *lock, ktime_t *expire_time)
68{
69 struct timespec ts;
70 struct timespec kt;
71 struct timespec tomono;
72 struct timespec delta;
Colin Cross28e23cf2011-03-30 12:37:49 -070073 struct timespec sleep;
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -070074 long timeout;
75
76 if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE))
77 return 0;
Colin Cross28e23cf2011-03-30 12:37:49 -070078 get_xtime_and_monotonic_and_sleep_offset(&kt, &tomono, &sleep);
79 timeout = lock->expires - jiffies;
80 if (timeout > 0)
81 return 0;
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -070082 jiffies_to_timespec(-timeout, &delta);
83 set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec,
84 kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec);
85 *expire_time = timespec_to_ktime(ts);
86 return 1;
87}
88
89
Arve Hjønnevåg1b074952009-12-02 18:22:00 -080090static int print_lock_stat(struct seq_file *m, struct wake_lock *lock)
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -070091{
92 int lock_count = lock->stat.count;
93 int expire_count = lock->stat.expire_count;
94 ktime_t active_time = ktime_set(0, 0);
95 ktime_t total_time = lock->stat.total_time;
96 ktime_t max_time = lock->stat.max_time;
Erik Gilling10f01382009-08-25 20:09:12 -070097
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -070098 ktime_t prevent_suspend_time = lock->stat.prevent_suspend_time;
99 if (lock->flags & WAKE_LOCK_ACTIVE) {
100 ktime_t now, add_time;
101 int expired = get_expired_time(lock, &now);
102 if (!expired)
103 now = ktime_get();
104 add_time = ktime_sub(now, lock->stat.last_time);
105 lock_count++;
106 if (!expired)
107 active_time = add_time;
108 else
109 expire_count++;
110 total_time = ktime_add(total_time, add_time);
111 if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND)
112 prevent_suspend_time = ktime_add(prevent_suspend_time,
113 ktime_sub(now, last_sleep_time_update));
114 if (add_time.tv64 > max_time.tv64)
115 max_time = add_time;
116 }
117
Arve Hjønnevåg1b074952009-12-02 18:22:00 -0800118 return seq_printf(m,
Erik Gilling10f01382009-08-25 20:09:12 -0700119 "\"%s\"\t%d\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
120 lock->name, lock_count, expire_count,
121 lock->stat.wakeup_count, ktime_to_ns(active_time),
122 ktime_to_ns(total_time),
123 ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
124 ktime_to_ns(lock->stat.last_time));
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700125}
126
Arve Hjønnevåg1b074952009-12-02 18:22:00 -0800127static int wakelock_stats_show(struct seq_file *m, void *unused)
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700128{
129 unsigned long irqflags;
130 struct wake_lock *lock;
Arve Hjønnevåg1b074952009-12-02 18:22:00 -0800131 int ret;
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700132 int type;
133
134 spin_lock_irqsave(&list_lock, irqflags);
135
Arve Hjønnevåg1b074952009-12-02 18:22:00 -0800136 ret = seq_puts(m, "name\tcount\texpire_count\twake_count\tactive_since"
Erik Gilling10f01382009-08-25 20:09:12 -0700137 "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
Arve Hjønnevåg1b074952009-12-02 18:22:00 -0800138 list_for_each_entry(lock, &inactive_locks, link)
139 ret = print_lock_stat(m, lock);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700140 for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) {
141 list_for_each_entry(lock, &active_wake_locks[type], link)
Arve Hjønnevåg1b074952009-12-02 18:22:00 -0800142 ret = print_lock_stat(m, lock);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700143 }
144 spin_unlock_irqrestore(&list_lock, irqflags);
Arve Hjønnevåg1b074952009-12-02 18:22:00 -0800145 return 0;
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700146}
147
148static void wake_unlock_stat_locked(struct wake_lock *lock, int expired)
149{
150 ktime_t duration;
151 ktime_t now;
152 if (!(lock->flags & WAKE_LOCK_ACTIVE))
153 return;
154 if (get_expired_time(lock, &now))
155 expired = 1;
156 else
157 now = ktime_get();
158 lock->stat.count++;
159 if (expired)
160 lock->stat.expire_count++;
161 duration = ktime_sub(now, lock->stat.last_time);
162 lock->stat.total_time = ktime_add(lock->stat.total_time, duration);
163 if (ktime_to_ns(duration) > ktime_to_ns(lock->stat.max_time))
164 lock->stat.max_time = duration;
165 lock->stat.last_time = ktime_get();
166 if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND) {
167 duration = ktime_sub(now, last_sleep_time_update);
168 lock->stat.prevent_suspend_time = ktime_add(
169 lock->stat.prevent_suspend_time, duration);
170 lock->flags &= ~WAKE_LOCK_PREVENTING_SUSPEND;
171 }
172}
173
174static void update_sleep_wait_stats_locked(int done)
175{
176 struct wake_lock *lock;
177 ktime_t now, etime, elapsed, add;
178 int expired;
179
180 now = ktime_get();
181 elapsed = ktime_sub(now, last_sleep_time_update);
182 list_for_each_entry(lock, &active_wake_locks[WAKE_LOCK_SUSPEND], link) {
183 expired = get_expired_time(lock, &etime);
184 if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND) {
185 if (expired)
186 add = ktime_sub(etime, last_sleep_time_update);
187 else
188 add = elapsed;
189 lock->stat.prevent_suspend_time = ktime_add(
190 lock->stat.prevent_suspend_time, add);
191 }
192 if (done || expired)
193 lock->flags &= ~WAKE_LOCK_PREVENTING_SUSPEND;
194 else
195 lock->flags |= WAKE_LOCK_PREVENTING_SUSPEND;
196 }
197 last_sleep_time_update = now;
198}
199#endif
200
201
202static void expire_wake_lock(struct wake_lock *lock)
203{
204#ifdef CONFIG_WAKELOCK_STAT
205 wake_unlock_stat_locked(lock, 1);
206#endif
207 lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
208 list_del(&lock->link);
209 list_add(&lock->link, &inactive_locks);
210 if (debug_mask & (DEBUG_WAKE_LOCK | DEBUG_EXPIRE))
211 pr_info("expired wake lock %s\n", lock->name);
212}
213
Mike Chan97a0a742009-08-25 18:10:32 -0700214/* Caller must acquire the list_lock spinlock */
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700215static void print_active_locks(int type)
216{
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700217 struct wake_lock *lock;
Mike Chanaf62b252010-02-16 14:18:55 -0800218 bool print_expired = true;
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700219
220 BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700221 list_for_each_entry(lock, &active_wake_locks[type], link) {
222 if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
223 long timeout = lock->expires - jiffies;
Mike Chanaf62b252010-02-16 14:18:55 -0800224 if (timeout > 0)
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700225 pr_info("active wake lock %s, time left %ld\n",
226 lock->name, timeout);
Mike Chanaf62b252010-02-16 14:18:55 -0800227 else if (print_expired)
228 pr_info("wake lock %s, expired\n", lock->name);
229 } else {
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700230 pr_info("active wake lock %s\n", lock->name);
Colin Cross0c7841c2010-08-21 17:27:02 -0700231 if (!(debug_mask & DEBUG_EXPIRE))
Mike Chanaf62b252010-02-16 14:18:55 -0800232 print_expired = false;
233 }
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700234 }
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700235}
236
237static long has_wake_lock_locked(int type)
238{
239 struct wake_lock *lock, *n;
240 long max_timeout = 0;
241
242 BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
243 list_for_each_entry_safe(lock, n, &active_wake_locks[type], link) {
244 if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
245 long timeout = lock->expires - jiffies;
246 if (timeout <= 0)
247 expire_wake_lock(lock);
248 else if (timeout > max_timeout)
249 max_timeout = timeout;
250 } else
251 return -1;
252 }
253 return max_timeout;
254}
255
256long has_wake_lock(int type)
257{
258 long ret;
259 unsigned long irqflags;
260 spin_lock_irqsave(&list_lock, irqflags);
261 ret = has_wake_lock_locked(type);
Todd Poynorca64b0c2011-08-08 16:06:54 -0700262 if (ret && (debug_mask & DEBUG_WAKEUP) && type == WAKE_LOCK_SUSPEND)
Mike Chanaf62b252010-02-16 14:18:55 -0800263 print_active_locks(type);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700264 spin_unlock_irqrestore(&list_lock, irqflags);
265 return ret;
266}
267
Pratik Patel529461b2011-07-21 19:13:34 -0700268static void suspend_sys_sync(struct work_struct *work)
269{
270 if (debug_mask & DEBUG_SUSPEND)
271 pr_info("PM: Syncing filesystems...\n");
272
273 sys_sync();
274
275 if (debug_mask & DEBUG_SUSPEND)
276 pr_info("sync done.\n");
277
278 spin_lock(&suspend_sys_sync_lock);
279 suspend_sys_sync_count--;
280 spin_unlock(&suspend_sys_sync_lock);
281}
282static DECLARE_WORK(suspend_sys_sync_work, suspend_sys_sync);
283
284void suspend_sys_sync_queue(void)
285{
286 int ret;
287
288 spin_lock(&suspend_sys_sync_lock);
289 ret = queue_work(suspend_sys_sync_work_queue, &suspend_sys_sync_work);
290 if (ret)
291 suspend_sys_sync_count++;
292 spin_unlock(&suspend_sys_sync_lock);
293}
294
295static bool suspend_sys_sync_abort;
296static void suspend_sys_sync_handler(unsigned long);
297static DEFINE_TIMER(suspend_sys_sync_timer, suspend_sys_sync_handler, 0, 0);
298/* value should be less then half of input event wake lock timeout value
299 * which is currently set to 5*HZ (see drivers/input/evdev.c)
300 */
301#define SUSPEND_SYS_SYNC_TIMEOUT (HZ/4)
302static void suspend_sys_sync_handler(unsigned long arg)
303{
304 if (suspend_sys_sync_count == 0) {
305 complete(&suspend_sys_sync_comp);
306 } else if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
307 suspend_sys_sync_abort = true;
308 complete(&suspend_sys_sync_comp);
309 } else {
310 mod_timer(&suspend_sys_sync_timer, jiffies +
311 SUSPEND_SYS_SYNC_TIMEOUT);
312 }
313}
314
315int suspend_sys_sync_wait(void)
316{
317 suspend_sys_sync_abort = false;
318
319 if (suspend_sys_sync_count != 0) {
320 mod_timer(&suspend_sys_sync_timer, jiffies +
321 SUSPEND_SYS_SYNC_TIMEOUT);
322 wait_for_completion(&suspend_sys_sync_comp);
323 }
324 if (suspend_sys_sync_abort) {
325 pr_info("suspend aborted....while waiting for sys_sync\n");
326 return -EAGAIN;
327 }
328
329 return 0;
330}
331
Todd Poynor7013f492011-08-25 19:29:45 -0700332static void suspend_backoff(void)
333{
334 pr_info("suspend: too many immediate wakeups, back off\n");
335 wake_lock_timeout(&suspend_backoff_lock,
336 msecs_to_jiffies(SUSPEND_BACKOFF_INTERVAL));
337}
338
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700339static void suspend(struct work_struct *work)
340{
341 int ret;
342 int entry_event_num;
Todd Poynor7013f492011-08-25 19:29:45 -0700343 struct timespec ts_entry, ts_exit;
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700344
345 if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
346 if (debug_mask & DEBUG_SUSPEND)
347 pr_info("suspend: abort suspend\n");
348 return;
349 }
350
351 entry_event_num = current_event_num;
Bryan Huntsmand074fa22011-11-16 13:52:50 -0800352 suspend_sys_sync_queue();
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700353 if (debug_mask & DEBUG_SUSPEND)
354 pr_info("suspend: enter suspend\n");
Todd Poynor7013f492011-08-25 19:29:45 -0700355 getnstimeofday(&ts_entry);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700356 ret = pm_suspend(requested_suspend_state);
Todd Poynor7013f492011-08-25 19:29:45 -0700357 getnstimeofday(&ts_exit);
358
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700359 if (debug_mask & DEBUG_EXIT_SUSPEND) {
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700360 struct rtc_time tm;
Todd Poynor7013f492011-08-25 19:29:45 -0700361 rtc_time_to_tm(ts_exit.tv_sec, &tm);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700362 pr_info("suspend: exit suspend, ret = %d "
363 "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
364 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
Todd Poynor7013f492011-08-25 19:29:45 -0700365 tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700366 }
Todd Poynor7013f492011-08-25 19:29:45 -0700367
368 if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) {
369 ++suspend_short_count;
370
371 if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) {
372 suspend_backoff();
373 suspend_short_count = 0;
374 }
375 } else {
376 suspend_short_count = 0;
377 }
378
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700379 if (current_event_num == entry_event_num) {
380 if (debug_mask & DEBUG_SUSPEND)
381 pr_info("suspend: pm_suspend returned with no event\n");
382 wake_lock_timeout(&unknown_wakeup, HZ / 2);
383 }
384}
385static DECLARE_WORK(suspend_work, suspend);
386
387static void expire_wake_locks(unsigned long data)
388{
389 long has_lock;
390 unsigned long irqflags;
391 if (debug_mask & DEBUG_EXPIRE)
392 pr_info("expire_wake_locks: start\n");
Mike Chan97a0a742009-08-25 18:10:32 -0700393 spin_lock_irqsave(&list_lock, irqflags);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700394 if (debug_mask & DEBUG_SUSPEND)
395 print_active_locks(WAKE_LOCK_SUSPEND);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700396 has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);
397 if (debug_mask & DEBUG_EXPIRE)
398 pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock);
399 if (has_lock == 0)
400 queue_work(suspend_work_queue, &suspend_work);
401 spin_unlock_irqrestore(&list_lock, irqflags);
402}
403static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
404
405static int power_suspend_late(struct device *dev)
406{
407 int ret = has_wake_lock(WAKE_LOCK_SUSPEND) ? -EAGAIN : 0;
408#ifdef CONFIG_WAKELOCK_STAT
Todd Poynored27e532011-08-08 17:26:49 -0700409 wait_for_wakeup = !ret;
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700410#endif
411 if (debug_mask & DEBUG_SUSPEND)
412 pr_info("power_suspend_late return %d\n", ret);
413 return ret;
414}
415
416static struct dev_pm_ops power_driver_pm_ops = {
417 .suspend_noirq = power_suspend_late,
418};
419
420static struct platform_driver power_driver = {
421 .driver.name = "power",
422 .driver.pm = &power_driver_pm_ops,
423};
424static struct platform_device power_device = {
425 .name = "power",
426};
427
428void wake_lock_init(struct wake_lock *lock, int type, const char *name)
429{
430 unsigned long irqflags = 0;
431
432 if (name)
433 lock->name = name;
434 BUG_ON(!lock->name);
435
436 if (debug_mask & DEBUG_WAKE_LOCK)
437 pr_info("wake_lock_init name=%s\n", lock->name);
438#ifdef CONFIG_WAKELOCK_STAT
439 lock->stat.count = 0;
440 lock->stat.expire_count = 0;
441 lock->stat.wakeup_count = 0;
442 lock->stat.total_time = ktime_set(0, 0);
443 lock->stat.prevent_suspend_time = ktime_set(0, 0);
444 lock->stat.max_time = ktime_set(0, 0);
445 lock->stat.last_time = ktime_set(0, 0);
446#endif
447 lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;
448
449 INIT_LIST_HEAD(&lock->link);
450 spin_lock_irqsave(&list_lock, irqflags);
451 list_add(&lock->link, &inactive_locks);
452 spin_unlock_irqrestore(&list_lock, irqflags);
453}
454EXPORT_SYMBOL(wake_lock_init);
455
456void wake_lock_destroy(struct wake_lock *lock)
457{
458 unsigned long irqflags;
459 if (debug_mask & DEBUG_WAKE_LOCK)
460 pr_info("wake_lock_destroy name=%s\n", lock->name);
461 spin_lock_irqsave(&list_lock, irqflags);
462 lock->flags &= ~WAKE_LOCK_INITIALIZED;
463#ifdef CONFIG_WAKELOCK_STAT
464 if (lock->stat.count) {
465 deleted_wake_locks.stat.count += lock->stat.count;
466 deleted_wake_locks.stat.expire_count += lock->stat.expire_count;
467 deleted_wake_locks.stat.total_time =
468 ktime_add(deleted_wake_locks.stat.total_time,
469 lock->stat.total_time);
470 deleted_wake_locks.stat.prevent_suspend_time =
471 ktime_add(deleted_wake_locks.stat.prevent_suspend_time,
472 lock->stat.prevent_suspend_time);
473 deleted_wake_locks.stat.max_time =
474 ktime_add(deleted_wake_locks.stat.max_time,
475 lock->stat.max_time);
476 }
477#endif
478 list_del(&lock->link);
479 spin_unlock_irqrestore(&list_lock, irqflags);
480}
481EXPORT_SYMBOL(wake_lock_destroy);
482
483static void wake_lock_internal(
484 struct wake_lock *lock, long timeout, int has_timeout)
485{
486 int type;
487 unsigned long irqflags;
488 long expire_in;
489
490 spin_lock_irqsave(&list_lock, irqflags);
491 type = lock->flags & WAKE_LOCK_TYPE_MASK;
492 BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
493 BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));
494#ifdef CONFIG_WAKELOCK_STAT
495 if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {
496 if (debug_mask & DEBUG_WAKEUP)
497 pr_info("wakeup wake lock: %s\n", lock->name);
498 wait_for_wakeup = 0;
499 lock->stat.wakeup_count++;
500 }
501 if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&
502 (long)(lock->expires - jiffies) <= 0) {
503 wake_unlock_stat_locked(lock, 0);
504 lock->stat.last_time = ktime_get();
505 }
506#endif
507 if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
508 lock->flags |= WAKE_LOCK_ACTIVE;
509#ifdef CONFIG_WAKELOCK_STAT
510 lock->stat.last_time = ktime_get();
511#endif
512 }
513 list_del(&lock->link);
514 if (has_timeout) {
515 if (debug_mask & DEBUG_WAKE_LOCK)
516 pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",
517 lock->name, type, timeout / HZ,
518 (timeout % HZ) * MSEC_PER_SEC / HZ);
519 lock->expires = jiffies + timeout;
520 lock->flags |= WAKE_LOCK_AUTO_EXPIRE;
521 list_add_tail(&lock->link, &active_wake_locks[type]);
522 } else {
523 if (debug_mask & DEBUG_WAKE_LOCK)
524 pr_info("wake_lock: %s, type %d\n", lock->name, type);
525 lock->expires = LONG_MAX;
526 lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;
527 list_add(&lock->link, &active_wake_locks[type]);
528 }
529 if (type == WAKE_LOCK_SUSPEND) {
530 current_event_num++;
531#ifdef CONFIG_WAKELOCK_STAT
532 if (lock == &main_wake_lock)
533 update_sleep_wait_stats_locked(1);
534 else if (!wake_lock_active(&main_wake_lock))
535 update_sleep_wait_stats_locked(0);
536#endif
537 if (has_timeout)
538 expire_in = has_wake_lock_locked(type);
539 else
540 expire_in = -1;
541 if (expire_in > 0) {
542 if (debug_mask & DEBUG_EXPIRE)
543 pr_info("wake_lock: %s, start expire timer, "
544 "%ld\n", lock->name, expire_in);
545 mod_timer(&expire_timer, jiffies + expire_in);
546 } else {
547 if (del_timer(&expire_timer))
548 if (debug_mask & DEBUG_EXPIRE)
549 pr_info("wake_lock: %s, stop expire timer\n",
550 lock->name);
551 if (expire_in == 0)
552 queue_work(suspend_work_queue, &suspend_work);
553 }
554 }
555 spin_unlock_irqrestore(&list_lock, irqflags);
556}
557
558void wake_lock(struct wake_lock *lock)
559{
560 wake_lock_internal(lock, 0, 0);
561}
562EXPORT_SYMBOL(wake_lock);
563
564void wake_lock_timeout(struct wake_lock *lock, long timeout)
565{
566 wake_lock_internal(lock, timeout, 1);
567}
568EXPORT_SYMBOL(wake_lock_timeout);
569
570void wake_unlock(struct wake_lock *lock)
571{
572 int type;
573 unsigned long irqflags;
574 spin_lock_irqsave(&list_lock, irqflags);
575 type = lock->flags & WAKE_LOCK_TYPE_MASK;
576#ifdef CONFIG_WAKELOCK_STAT
577 wake_unlock_stat_locked(lock, 0);
578#endif
579 if (debug_mask & DEBUG_WAKE_LOCK)
580 pr_info("wake_unlock: %s\n", lock->name);
581 lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
582 list_del(&lock->link);
583 list_add(&lock->link, &inactive_locks);
584 if (type == WAKE_LOCK_SUSPEND) {
585 long has_lock = has_wake_lock_locked(type);
586 if (has_lock > 0) {
587 if (debug_mask & DEBUG_EXPIRE)
588 pr_info("wake_unlock: %s, start expire timer, "
589 "%ld\n", lock->name, has_lock);
590 mod_timer(&expire_timer, jiffies + has_lock);
591 } else {
592 if (del_timer(&expire_timer))
593 if (debug_mask & DEBUG_EXPIRE)
594 pr_info("wake_unlock: %s, stop expire "
595 "timer\n", lock->name);
596 if (has_lock == 0)
597 queue_work(suspend_work_queue, &suspend_work);
598 }
599 if (lock == &main_wake_lock) {
600 if (debug_mask & DEBUG_SUSPEND)
601 print_active_locks(WAKE_LOCK_SUSPEND);
602#ifdef CONFIG_WAKELOCK_STAT
603 update_sleep_wait_stats_locked(0);
604#endif
605 }
606 }
607 spin_unlock_irqrestore(&list_lock, irqflags);
608}
609EXPORT_SYMBOL(wake_unlock);
610
611int wake_lock_active(struct wake_lock *lock)
612{
613 return !!(lock->flags & WAKE_LOCK_ACTIVE);
614}
615EXPORT_SYMBOL(wake_lock_active);
616
Arve Hjønnevåg1b074952009-12-02 18:22:00 -0800617static int wakelock_stats_open(struct inode *inode, struct file *file)
618{
619 return single_open(file, wakelock_stats_show, NULL);
620}
621
622static const struct file_operations wakelock_stats_fops = {
623 .owner = THIS_MODULE,
624 .open = wakelock_stats_open,
625 .read = seq_read,
626 .llseek = seq_lseek,
627 .release = single_release,
628};
629
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700630static int __init wakelocks_init(void)
631{
632 int ret;
633 int i;
634
635 for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
636 INIT_LIST_HEAD(&active_wake_locks[i]);
637
638#ifdef CONFIG_WAKELOCK_STAT
639 wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,
640 "deleted_wake_locks");
641#endif
642 wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
643 wake_lock(&main_wake_lock);
644 wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
Todd Poynor7013f492011-08-25 19:29:45 -0700645 wake_lock_init(&suspend_backoff_lock, WAKE_LOCK_SUSPEND,
646 "suspend_backoff");
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700647
648 ret = platform_device_register(&power_device);
649 if (ret) {
650 pr_err("wakelocks_init: platform_device_register failed\n");
651 goto err_platform_device_register;
652 }
653 ret = platform_driver_register(&power_driver);
654 if (ret) {
655 pr_err("wakelocks_init: platform_driver_register failed\n");
656 goto err_platform_driver_register;
657 }
658
Bryan Huntsmand074fa22011-11-16 13:52:50 -0800659 INIT_COMPLETION(suspend_sys_sync_comp);
660 suspend_sys_sync_work_queue =
661 create_singlethread_workqueue("suspend_sys_sync");
662 if (suspend_sys_sync_work_queue == NULL) {
663 ret = -ENOMEM;
664 goto err_suspend_sys_sync_work_queue;
665 }
666
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700667 suspend_work_queue = create_singlethread_workqueue("suspend");
668 if (suspend_work_queue == NULL) {
669 ret = -ENOMEM;
670 goto err_suspend_work_queue;
671 }
672
673#ifdef CONFIG_WAKELOCK_STAT
Arve Hjønnevåg1b074952009-12-02 18:22:00 -0800674 proc_create("wakelocks", S_IRUGO, NULL, &wakelock_stats_fops);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700675#endif
676
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700677 return 0;
678
679err_suspend_work_queue:
Bryan Huntsmand074fa22011-11-16 13:52:50 -0800680err_suspend_sys_sync_work_queue:
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700681 platform_driver_unregister(&power_driver);
682err_platform_driver_register:
683 platform_device_unregister(&power_device);
684err_platform_device_register:
Todd Poynor7013f492011-08-25 19:29:45 -0700685 wake_lock_destroy(&suspend_backoff_lock);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700686 wake_lock_destroy(&unknown_wakeup);
687 wake_lock_destroy(&main_wake_lock);
688#ifdef CONFIG_WAKELOCK_STAT
689 wake_lock_destroy(&deleted_wake_locks);
690#endif
691 return ret;
692}
693
694static void __exit wakelocks_exit(void)
695{
696#ifdef CONFIG_WAKELOCK_STAT
697 remove_proc_entry("wakelocks", NULL);
698#endif
699 destroy_workqueue(suspend_work_queue);
Bryan Huntsmand074fa22011-11-16 13:52:50 -0800700 destroy_workqueue(suspend_sys_sync_work_queue);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700701 platform_driver_unregister(&power_driver);
702 platform_device_unregister(&power_device);
Todd Poynor7013f492011-08-25 19:29:45 -0700703 wake_lock_destroy(&suspend_backoff_lock);
Arve Hjønnevågfe6cd632008-09-09 22:14:34 -0700704 wake_lock_destroy(&unknown_wakeup);
705 wake_lock_destroy(&main_wake_lock);
706#ifdef CONFIG_WAKELOCK_STAT
707 wake_lock_destroy(&deleted_wake_locks);
708#endif
709}
710
711core_initcall(wakelocks_init);
712module_exit(wakelocks_exit);