Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * kernel/power/main.c - PM subsystem core functionality. | |
3 | * | |
4 | * Copyright (c) 2003 Patrick Mochel | |
5 | * Copyright (c) 2003 Open Source Development Lab | |
341d4166 | 6 | * |
1da177e4 LT |
7 | * This file is released under the GPLv2 |
8 | * | |
9 | */ | |
10 | ||
6e5fdeed | 11 | #include <linux/export.h> |
1da177e4 LT |
12 | #include <linux/kobject.h> |
13 | #include <linux/string.h> | |
431d452a | 14 | #include <linux/pm-trace.h> |
5e928f77 | 15 | #include <linux/workqueue.h> |
2a77c46d SL |
16 | #include <linux/debugfs.h> |
17 | #include <linux/seq_file.h> | |
1da177e4 LT |
18 | |
19 | #include "power.h" | |
20 | ||
a6d70980 | 21 | DEFINE_MUTEX(pm_mutex); |
1da177e4 | 22 | |
cd51e61c RW |
23 | #ifdef CONFIG_PM_SLEEP |
24 | ||
4bf236a3 BVA |
25 | void lock_system_sleep(void) |
26 | { | |
27 | current->flags |= PF_FREEZER_SKIP; | |
28 | mutex_lock(&pm_mutex); | |
29 | } | |
30 | EXPORT_SYMBOL_GPL(lock_system_sleep); | |
31 | ||
32 | void unlock_system_sleep(void) | |
33 | { | |
34 | /* | |
35 | * Don't use freezer_count() because we don't want the call to | |
36 | * try_to_freeze() here. | |
37 | * | |
38 | * Reason: | |
39 | * Fundamentally, we just don't need it, because freezing condition | |
40 | * doesn't come into effect until we release the pm_mutex lock, | |
41 | * since the freezer always works with pm_mutex held. | |
42 | * | |
43 | * More importantly, in the case of hibernation, | |
44 | * unlock_system_sleep() gets called in snapshot_read() and | |
45 | * snapshot_write() when the freezing condition is still in effect. | |
46 | * Which means, if we use try_to_freeze() here, it would make them | |
47 | * enter the refrigerator, thus causing hibernation to lockup. | |
48 | */ | |
49 | current->flags &= ~PF_FREEZER_SKIP; | |
50 | mutex_unlock(&pm_mutex); | |
51 | } | |
52 | EXPORT_SYMBOL_GPL(unlock_system_sleep); | |
53 | ||
82525756 AS |
54 | /* Routines for PM-transition notifications */ |
55 | ||
56 | static BLOCKING_NOTIFIER_HEAD(pm_chain_head); | |
57 | ||
58 | int register_pm_notifier(struct notifier_block *nb) | |
59 | { | |
60 | return blocking_notifier_chain_register(&pm_chain_head, nb); | |
61 | } | |
62 | EXPORT_SYMBOL_GPL(register_pm_notifier); | |
63 | ||
64 | int unregister_pm_notifier(struct notifier_block *nb) | |
65 | { | |
66 | return blocking_notifier_chain_unregister(&pm_chain_head, nb); | |
67 | } | |
68 | EXPORT_SYMBOL_GPL(unregister_pm_notifier); | |
69 | ||
ea00f4f4 | 70 | int __pm_notifier_call_chain(unsigned long val, int nr_to_call, int *nr_calls) |
82525756 | 71 | { |
ea00f4f4 LW |
72 | int ret; |
73 | ||
74 | ret = __blocking_notifier_call_chain(&pm_chain_head, val, NULL, | |
75 | nr_to_call, nr_calls); | |
f0c077a8 AM |
76 | |
77 | return notifier_to_errno(ret); | |
82525756 | 78 | } |
ea00f4f4 LW |
79 | int pm_notifier_call_chain(unsigned long val) |
80 | { | |
81 | return __pm_notifier_call_chain(val, -1, NULL); | |
82 | } | |
82525756 | 83 | |
0e06b4a8 RW |
84 | /* If set, devices may be suspended and resumed asynchronously. */ |
85 | int pm_async_enabled = 1; | |
86 | ||
87 | static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr, | |
88 | char *buf) | |
89 | { | |
90 | return sprintf(buf, "%d\n", pm_async_enabled); | |
91 | } | |
92 | ||
93 | static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr, | |
94 | const char *buf, size_t n) | |
95 | { | |
96 | unsigned long val; | |
97 | ||
883ee4f7 | 98 | if (kstrtoul(buf, 10, &val)) |
0e06b4a8 RW |
99 | return -EINVAL; |
100 | ||
101 | if (val > 1) | |
102 | return -EINVAL; | |
103 | ||
104 | pm_async_enabled = val; | |
105 | return n; | |
106 | } | |
107 | ||
108 | power_attr(pm_async); | |
109 | ||
406e7938 RW |
110 | #ifdef CONFIG_SUSPEND |
111 | static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr, | |
112 | char *buf) | |
113 | { | |
114 | char *s = buf; | |
115 | suspend_state_t i; | |
116 | ||
117 | for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) | |
118 | if (mem_sleep_states[i]) { | |
119 | const char *label = mem_sleep_states[i]; | |
120 | ||
121 | if (mem_sleep_current == i) | |
122 | s += sprintf(s, "[%s] ", label); | |
123 | else | |
124 | s += sprintf(s, "%s ", label); | |
125 | } | |
126 | ||
127 | /* Convert the last space to a newline if needed. */ | |
128 | if (s != buf) | |
129 | *(s-1) = '\n'; | |
130 | ||
131 | return (s - buf); | |
132 | } | |
133 | ||
134 | static suspend_state_t decode_suspend_state(const char *buf, size_t n) | |
135 | { | |
136 | suspend_state_t state; | |
137 | char *p; | |
138 | int len; | |
139 | ||
140 | p = memchr(buf, '\n', n); | |
141 | len = p ? p - buf : n; | |
142 | ||
143 | for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) { | |
144 | const char *label = mem_sleep_states[state]; | |
145 | ||
146 | if (label && len == strlen(label) && !strncmp(buf, label, len)) | |
147 | return state; | |
148 | } | |
149 | ||
150 | return PM_SUSPEND_ON; | |
151 | } | |
152 | ||
153 | static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr, | |
154 | const char *buf, size_t n) | |
155 | { | |
156 | suspend_state_t state; | |
157 | int error; | |
158 | ||
159 | error = pm_autosleep_lock(); | |
160 | if (error) | |
161 | return error; | |
162 | ||
163 | if (pm_autosleep_state() > PM_SUSPEND_ON) { | |
164 | error = -EBUSY; | |
165 | goto out; | |
166 | } | |
167 | ||
168 | state = decode_suspend_state(buf, n); | |
169 | if (state < PM_SUSPEND_MAX && state > PM_SUSPEND_ON) | |
170 | mem_sleep_current = state; | |
171 | else | |
172 | error = -EINVAL; | |
173 | ||
174 | out: | |
175 | pm_autosleep_unlock(); | |
176 | return error ? error : n; | |
177 | } | |
178 | ||
179 | power_attr(mem_sleep); | |
180 | #endif /* CONFIG_SUSPEND */ | |
181 | ||
e516a1db | 182 | #ifdef CONFIG_PM_SLEEP_DEBUG |
0e7d56e3 RW |
183 | int pm_test_level = TEST_NONE; |
184 | ||
0e7d56e3 RW |
185 | static const char * const pm_tests[__TEST_AFTER_LAST] = { |
186 | [TEST_NONE] = "none", | |
187 | [TEST_CORE] = "core", | |
188 | [TEST_CPUS] = "processors", | |
189 | [TEST_PLATFORM] = "platform", | |
190 | [TEST_DEVICES] = "devices", | |
191 | [TEST_FREEZER] = "freezer", | |
192 | }; | |
193 | ||
039a75c6 RW |
194 | static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr, |
195 | char *buf) | |
0e7d56e3 RW |
196 | { |
197 | char *s = buf; | |
198 | int level; | |
199 | ||
200 | for (level = TEST_FIRST; level <= TEST_MAX; level++) | |
201 | if (pm_tests[level]) { | |
202 | if (level == pm_test_level) | |
203 | s += sprintf(s, "[%s] ", pm_tests[level]); | |
204 | else | |
205 | s += sprintf(s, "%s ", pm_tests[level]); | |
206 | } | |
207 | ||
208 | if (s != buf) | |
209 | /* convert the last space to a newline */ | |
210 | *(s-1) = '\n'; | |
211 | ||
212 | return (s - buf); | |
213 | } | |
214 | ||
039a75c6 RW |
215 | static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, |
216 | const char *buf, size_t n) | |
0e7d56e3 RW |
217 | { |
218 | const char * const *s; | |
219 | int level; | |
220 | char *p; | |
221 | int len; | |
222 | int error = -EINVAL; | |
223 | ||
224 | p = memchr(buf, '\n', n); | |
225 | len = p ? p - buf : n; | |
226 | ||
bcda53fa | 227 | lock_system_sleep(); |
0e7d56e3 RW |
228 | |
229 | level = TEST_FIRST; | |
230 | for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++) | |
231 | if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) { | |
232 | pm_test_level = level; | |
233 | error = 0; | |
234 | break; | |
235 | } | |
236 | ||
bcda53fa | 237 | unlock_system_sleep(); |
0e7d56e3 RW |
238 | |
239 | return error ? error : n; | |
240 | } | |
241 | ||
242 | power_attr(pm_test); | |
e516a1db | 243 | #endif /* CONFIG_PM_SLEEP_DEBUG */ |
0e7d56e3 | 244 | |
2a77c46d SL |
245 | #ifdef CONFIG_DEBUG_FS |
246 | static char *suspend_step_name(enum suspend_stat_step step) | |
247 | { | |
248 | switch (step) { | |
249 | case SUSPEND_FREEZE: | |
250 | return "freeze"; | |
251 | case SUSPEND_PREPARE: | |
252 | return "prepare"; | |
253 | case SUSPEND_SUSPEND: | |
254 | return "suspend"; | |
255 | case SUSPEND_SUSPEND_NOIRQ: | |
256 | return "suspend_noirq"; | |
257 | case SUSPEND_RESUME_NOIRQ: | |
258 | return "resume_noirq"; | |
259 | case SUSPEND_RESUME: | |
260 | return "resume"; | |
261 | default: | |
262 | return ""; | |
263 | } | |
264 | } | |
265 | ||
266 | static int suspend_stats_show(struct seq_file *s, void *unused) | |
267 | { | |
268 | int i, index, last_dev, last_errno, last_step; | |
269 | ||
270 | last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; | |
271 | last_dev %= REC_FAILED_NUM; | |
272 | last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1; | |
273 | last_errno %= REC_FAILED_NUM; | |
274 | last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; | |
275 | last_step %= REC_FAILED_NUM; | |
cf579dfb RW |
276 | seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n" |
277 | "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n", | |
2a77c46d SL |
278 | "success", suspend_stats.success, |
279 | "fail", suspend_stats.fail, | |
280 | "failed_freeze", suspend_stats.failed_freeze, | |
281 | "failed_prepare", suspend_stats.failed_prepare, | |
282 | "failed_suspend", suspend_stats.failed_suspend, | |
cf579dfb RW |
283 | "failed_suspend_late", |
284 | suspend_stats.failed_suspend_late, | |
2a77c46d SL |
285 | "failed_suspend_noirq", |
286 | suspend_stats.failed_suspend_noirq, | |
287 | "failed_resume", suspend_stats.failed_resume, | |
cf579dfb RW |
288 | "failed_resume_early", |
289 | suspend_stats.failed_resume_early, | |
2a77c46d SL |
290 | "failed_resume_noirq", |
291 | suspend_stats.failed_resume_noirq); | |
292 | seq_printf(s, "failures:\n last_failed_dev:\t%-s\n", | |
293 | suspend_stats.failed_devs[last_dev]); | |
294 | for (i = 1; i < REC_FAILED_NUM; i++) { | |
295 | index = last_dev + REC_FAILED_NUM - i; | |
296 | index %= REC_FAILED_NUM; | |
297 | seq_printf(s, "\t\t\t%-s\n", | |
298 | suspend_stats.failed_devs[index]); | |
299 | } | |
300 | seq_printf(s, " last_failed_errno:\t%-d\n", | |
301 | suspend_stats.errno[last_errno]); | |
302 | for (i = 1; i < REC_FAILED_NUM; i++) { | |
303 | index = last_errno + REC_FAILED_NUM - i; | |
304 | index %= REC_FAILED_NUM; | |
305 | seq_printf(s, "\t\t\t%-d\n", | |
306 | suspend_stats.errno[index]); | |
307 | } | |
308 | seq_printf(s, " last_failed_step:\t%-s\n", | |
309 | suspend_step_name( | |
310 | suspend_stats.failed_steps[last_step])); | |
311 | for (i = 1; i < REC_FAILED_NUM; i++) { | |
312 | index = last_step + REC_FAILED_NUM - i; | |
313 | index %= REC_FAILED_NUM; | |
314 | seq_printf(s, "\t\t\t%-s\n", | |
315 | suspend_step_name( | |
316 | suspend_stats.failed_steps[index])); | |
317 | } | |
318 | ||
319 | return 0; | |
320 | } | |
321 | ||
322 | static int suspend_stats_open(struct inode *inode, struct file *file) | |
323 | { | |
324 | return single_open(file, suspend_stats_show, NULL); | |
325 | } | |
326 | ||
327 | static const struct file_operations suspend_stats_operations = { | |
328 | .open = suspend_stats_open, | |
329 | .read = seq_read, | |
330 | .llseek = seq_lseek, | |
331 | .release = single_release, | |
332 | }; | |
333 | ||
334 | static int __init pm_debugfs_init(void) | |
335 | { | |
336 | debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO, | |
337 | NULL, NULL, &suspend_stats_operations); | |
338 | return 0; | |
339 | } | |
340 | ||
341 | late_initcall(pm_debugfs_init); | |
342 | #endif /* CONFIG_DEBUG_FS */ | |
343 | ||
ca123102 RW |
344 | #endif /* CONFIG_PM_SLEEP */ |
345 | ||
b2df1d4f RW |
346 | #ifdef CONFIG_PM_SLEEP_DEBUG |
347 | /* | |
348 | * pm_print_times: print time taken by devices to suspend and resume. | |
349 | * | |
350 | * show() returns whether printing of suspend and resume times is enabled. | |
351 | * store() accepts 0 or 1. 0 disables printing and 1 enables it. | |
352 | */ | |
353 | bool pm_print_times_enabled; | |
354 | ||
355 | static ssize_t pm_print_times_show(struct kobject *kobj, | |
356 | struct kobj_attribute *attr, char *buf) | |
357 | { | |
358 | return sprintf(buf, "%d\n", pm_print_times_enabled); | |
359 | } | |
360 | ||
361 | static ssize_t pm_print_times_store(struct kobject *kobj, | |
362 | struct kobj_attribute *attr, | |
363 | const char *buf, size_t n) | |
364 | { | |
365 | unsigned long val; | |
366 | ||
367 | if (kstrtoul(buf, 10, &val)) | |
368 | return -EINVAL; | |
369 | ||
370 | if (val > 1) | |
371 | return -EINVAL; | |
372 | ||
373 | pm_print_times_enabled = !!val; | |
374 | return n; | |
375 | } | |
376 | ||
377 | power_attr(pm_print_times); | |
378 | ||
379 | static inline void pm_print_times_init(void) | |
380 | { | |
381 | pm_print_times_enabled = !!initcall_debug; | |
382 | } | |
a6f5f0dd AY |
383 | |
384 | static ssize_t pm_wakeup_irq_show(struct kobject *kobj, | |
385 | struct kobj_attribute *attr, | |
386 | char *buf) | |
387 | { | |
388 | return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA; | |
389 | } | |
390 | ||
a1e9ca69 | 391 | power_attr_ro(pm_wakeup_irq); |
a6f5f0dd | 392 | |
726fb6b4 | 393 | bool pm_debug_messages_on __read_mostly; |
8d8b2441 RW |
394 | |
395 | static ssize_t pm_debug_messages_show(struct kobject *kobj, | |
396 | struct kobj_attribute *attr, char *buf) | |
397 | { | |
398 | return sprintf(buf, "%d\n", pm_debug_messages_on); | |
399 | } | |
400 | ||
401 | static ssize_t pm_debug_messages_store(struct kobject *kobj, | |
402 | struct kobj_attribute *attr, | |
403 | const char *buf, size_t n) | |
404 | { | |
405 | unsigned long val; | |
406 | ||
407 | if (kstrtoul(buf, 10, &val)) | |
408 | return -EINVAL; | |
409 | ||
410 | if (val > 1) | |
411 | return -EINVAL; | |
412 | ||
413 | pm_debug_messages_on = !!val; | |
414 | return n; | |
415 | } | |
416 | ||
417 | power_attr(pm_debug_messages); | |
418 | ||
419 | /** | |
cb08e035 RW |
420 | * __pm_pr_dbg - Print a suspend debug message to the kernel log. |
421 | * @defer: Whether or not to use printk_deferred() to print the message. | |
8d8b2441 RW |
422 | * @fmt: Message format. |
423 | * | |
424 | * The message will be emitted if enabled through the pm_debug_messages | |
425 | * sysfs attribute. | |
426 | */ | |
cb08e035 | 427 | void __pm_pr_dbg(bool defer, const char *fmt, ...) |
8d8b2441 RW |
428 | { |
429 | struct va_format vaf; | |
430 | va_list args; | |
431 | ||
432 | if (!pm_debug_messages_on) | |
433 | return; | |
434 | ||
435 | va_start(args, fmt); | |
436 | ||
437 | vaf.fmt = fmt; | |
438 | vaf.va = &args; | |
439 | ||
cb08e035 RW |
440 | if (defer) |
441 | printk_deferred(KERN_DEBUG "PM: %pV", &vaf); | |
442 | else | |
443 | printk(KERN_DEBUG "PM: %pV", &vaf); | |
8d8b2441 RW |
444 | |
445 | va_end(args); | |
446 | } | |
447 | ||
819b1bb3 | 448 | #else /* !CONFIG_PM_SLEEP_DEBUG */ |
b2df1d4f RW |
449 | static inline void pm_print_times_init(void) {} |
450 | #endif /* CONFIG_PM_SLEEP_DEBUG */ | |
451 | ||
d76e15fb | 452 | struct kobject *power_kobj; |
1da177e4 LT |
453 | |
454 | /** | |
0399d4db | 455 | * state - control system sleep states. |
1da177e4 | 456 | * |
0399d4db RW |
457 | * show() returns available sleep state labels, which may be "mem", "standby", |
458 | * "freeze" and "disk" (hibernation). See Documentation/power/states.txt for a | |
459 | * description of what they mean. | |
1da177e4 | 460 | * |
0399d4db RW |
461 | * store() accepts one of those strings, translates it into the proper |
462 | * enumerated value, and initiates a suspend transition. | |
1da177e4 | 463 | */ |
386f275f KS |
464 | static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, |
465 | char *buf) | |
1da177e4 | 466 | { |
296699de RW |
467 | char *s = buf; |
468 | #ifdef CONFIG_SUSPEND | |
27ddcc65 RW |
469 | suspend_state_t i; |
470 | ||
471 | for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) | |
d431cbc5 RW |
472 | if (pm_states[i]) |
473 | s += sprintf(s,"%s ", pm_states[i]); | |
1da177e4 | 474 | |
296699de | 475 | #endif |
a6e15a39 KC |
476 | if (hibernation_available()) |
477 | s += sprintf(s, "disk "); | |
a3d25c27 RW |
478 | if (s != buf) |
479 | /* convert the last space to a newline */ | |
480 | *(s-1) = '\n'; | |
1da177e4 LT |
481 | return (s - buf); |
482 | } | |
483 | ||
7483b4a4 | 484 | static suspend_state_t decode_state(const char *buf, size_t n) |
1da177e4 | 485 | { |
296699de | 486 | #ifdef CONFIG_SUSPEND |
d431cbc5 | 487 | suspend_state_t state; |
296699de | 488 | #endif |
1da177e4 | 489 | char *p; |
1da177e4 LT |
490 | int len; |
491 | ||
492 | p = memchr(buf, '\n', n); | |
493 | len = p ? p - buf : n; | |
494 | ||
7483b4a4 RW |
495 | /* Check hibernation first. */ |
496 | if (len == 4 && !strncmp(buf, "disk", len)) | |
497 | return PM_SUSPEND_MAX; | |
a3d25c27 | 498 | |
296699de | 499 | #ifdef CONFIG_SUSPEND |
d431cbc5 RW |
500 | for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) { |
501 | const char *label = pm_states[state]; | |
502 | ||
503 | if (label && len == strlen(label) && !strncmp(buf, label, len)) | |
504 | return state; | |
505 | } | |
296699de RW |
506 | #endif |
507 | ||
7483b4a4 RW |
508 | return PM_SUSPEND_ON; |
509 | } | |
510 | ||
511 | static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, | |
512 | const char *buf, size_t n) | |
513 | { | |
514 | suspend_state_t state; | |
515 | int error; | |
516 | ||
517 | error = pm_autosleep_lock(); | |
518 | if (error) | |
519 | return error; | |
520 | ||
521 | if (pm_autosleep_state() > PM_SUSPEND_ON) { | |
522 | error = -EBUSY; | |
523 | goto out; | |
524 | } | |
525 | ||
526 | state = decode_state(buf, n); | |
406e7938 RW |
527 | if (state < PM_SUSPEND_MAX) { |
528 | if (state == PM_SUSPEND_MEM) | |
529 | state = mem_sleep_current; | |
530 | ||
7483b4a4 | 531 | error = pm_suspend(state); |
406e7938 | 532 | } else if (state == PM_SUSPEND_MAX) { |
7483b4a4 | 533 | error = hibernate(); |
406e7938 | 534 | } else { |
7483b4a4 | 535 | error = -EINVAL; |
406e7938 | 536 | } |
7483b4a4 RW |
537 | |
538 | out: | |
539 | pm_autosleep_unlock(); | |
1da177e4 LT |
540 | return error ? error : n; |
541 | } | |
542 | ||
543 | power_attr(state); | |
544 | ||
c125e96f RW |
545 | #ifdef CONFIG_PM_SLEEP |
546 | /* | |
547 | * The 'wakeup_count' attribute, along with the functions defined in | |
548 | * drivers/base/power/wakeup.c, provides a means by which wakeup events can be | |
549 | * handled in a non-racy way. | |
550 | * | |
551 | * If a wakeup event occurs when the system is in a sleep state, it simply is | |
552 | * woken up. In turn, if an event that would wake the system up from a sleep | |
553 | * state occurs when it is undergoing a transition to that sleep state, the | |
554 | * transition should be aborted. Moreover, if such an event occurs when the | |
555 | * system is in the working state, an attempt to start a transition to the | |
556 | * given sleep state should fail during certain period after the detection of | |
557 | * the event. Using the 'state' attribute alone is not sufficient to satisfy | |
558 | * these requirements, because a wakeup event may occur exactly when 'state' | |
559 | * is being written to and may be delivered to user space right before it is | |
560 | * frozen, so the event will remain only partially processed until the system is | |
561 | * woken up by another event. In particular, it won't cause the transition to | |
562 | * a sleep state to be aborted. | |
563 | * | |
564 | * This difficulty may be overcome if user space uses 'wakeup_count' before | |
565 | * writing to 'state'. It first should read from 'wakeup_count' and store | |
566 | * the read value. Then, after carrying out its own preparations for the system | |
567 | * transition to a sleep state, it should write the stored value to | |
25985edc | 568 | * 'wakeup_count'. If that fails, at least one wakeup event has occurred since |
c125e96f RW |
569 | * 'wakeup_count' was read and 'state' should not be written to. Otherwise, it |
570 | * is allowed to write to 'state', but the transition will be aborted if there | |
571 | * are any wakeup events detected after 'wakeup_count' was written to. | |
572 | */ | |
573 | ||
574 | static ssize_t wakeup_count_show(struct kobject *kobj, | |
575 | struct kobj_attribute *attr, | |
576 | char *buf) | |
577 | { | |
074037ec | 578 | unsigned int val; |
c125e96f | 579 | |
7483b4a4 RW |
580 | return pm_get_wakeup_count(&val, true) ? |
581 | sprintf(buf, "%u\n", val) : -EINTR; | |
c125e96f RW |
582 | } |
583 | ||
584 | static ssize_t wakeup_count_store(struct kobject *kobj, | |
585 | struct kobj_attribute *attr, | |
586 | const char *buf, size_t n) | |
587 | { | |
074037ec | 588 | unsigned int val; |
7483b4a4 RW |
589 | int error; |
590 | ||
591 | error = pm_autosleep_lock(); | |
592 | if (error) | |
593 | return error; | |
c125e96f | 594 | |
7483b4a4 RW |
595 | if (pm_autosleep_state() > PM_SUSPEND_ON) { |
596 | error = -EBUSY; | |
597 | goto out; | |
598 | } | |
599 | ||
600 | error = -EINVAL; | |
074037ec | 601 | if (sscanf(buf, "%u", &val) == 1) { |
c125e96f | 602 | if (pm_save_wakeup_count(val)) |
7483b4a4 | 603 | error = n; |
bb177fed JW |
604 | else |
605 | pm_print_active_wakeup_sources(); | |
c125e96f | 606 | } |
7483b4a4 RW |
607 | |
608 | out: | |
609 | pm_autosleep_unlock(); | |
610 | return error; | |
c125e96f RW |
611 | } |
612 | ||
613 | power_attr(wakeup_count); | |
7483b4a4 RW |
614 | |
615 | #ifdef CONFIG_PM_AUTOSLEEP | |
616 | static ssize_t autosleep_show(struct kobject *kobj, | |
617 | struct kobj_attribute *attr, | |
618 | char *buf) | |
619 | { | |
620 | suspend_state_t state = pm_autosleep_state(); | |
621 | ||
622 | if (state == PM_SUSPEND_ON) | |
623 | return sprintf(buf, "off\n"); | |
624 | ||
625 | #ifdef CONFIG_SUSPEND | |
626 | if (state < PM_SUSPEND_MAX) | |
d431cbc5 RW |
627 | return sprintf(buf, "%s\n", pm_states[state] ? |
628 | pm_states[state] : "error"); | |
7483b4a4 RW |
629 | #endif |
630 | #ifdef CONFIG_HIBERNATION | |
631 | return sprintf(buf, "disk\n"); | |
632 | #else | |
633 | return sprintf(buf, "error"); | |
634 | #endif | |
635 | } | |
636 | ||
637 | static ssize_t autosleep_store(struct kobject *kobj, | |
638 | struct kobj_attribute *attr, | |
639 | const char *buf, size_t n) | |
640 | { | |
641 | suspend_state_t state = decode_state(buf, n); | |
642 | int error; | |
643 | ||
644 | if (state == PM_SUSPEND_ON | |
040e5bf6 | 645 | && strcmp(buf, "off") && strcmp(buf, "off\n")) |
7483b4a4 RW |
646 | return -EINVAL; |
647 | ||
406e7938 RW |
648 | if (state == PM_SUSPEND_MEM) |
649 | state = mem_sleep_current; | |
650 | ||
7483b4a4 RW |
651 | error = pm_autosleep_set_state(state); |
652 | return error ? error : n; | |
653 | } | |
654 | ||
655 | power_attr(autosleep); | |
656 | #endif /* CONFIG_PM_AUTOSLEEP */ | |
b86ff982 RW |
657 | |
658 | #ifdef CONFIG_PM_WAKELOCKS | |
659 | static ssize_t wake_lock_show(struct kobject *kobj, | |
660 | struct kobj_attribute *attr, | |
661 | char *buf) | |
662 | { | |
663 | return pm_show_wakelocks(buf, true); | |
664 | } | |
665 | ||
666 | static ssize_t wake_lock_store(struct kobject *kobj, | |
667 | struct kobj_attribute *attr, | |
668 | const char *buf, size_t n) | |
669 | { | |
670 | int error = pm_wake_lock(buf); | |
671 | return error ? error : n; | |
672 | } | |
673 | ||
674 | power_attr(wake_lock); | |
675 | ||
676 | static ssize_t wake_unlock_show(struct kobject *kobj, | |
677 | struct kobj_attribute *attr, | |
678 | char *buf) | |
679 | { | |
680 | return pm_show_wakelocks(buf, false); | |
681 | } | |
682 | ||
683 | static ssize_t wake_unlock_store(struct kobject *kobj, | |
684 | struct kobj_attribute *attr, | |
685 | const char *buf, size_t n) | |
686 | { | |
687 | int error = pm_wake_unlock(buf); | |
688 | return error ? error : n; | |
689 | } | |
690 | ||
691 | power_attr(wake_unlock); | |
692 | ||
693 | #endif /* CONFIG_PM_WAKELOCKS */ | |
c125e96f RW |
694 | #endif /* CONFIG_PM_SLEEP */ |
695 | ||
c5c6ba4e RW |
696 | #ifdef CONFIG_PM_TRACE |
697 | int pm_trace_enabled; | |
698 | ||
386f275f KS |
699 | static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr, |
700 | char *buf) | |
c5c6ba4e RW |
701 | { |
702 | return sprintf(buf, "%d\n", pm_trace_enabled); | |
703 | } | |
704 | ||
705 | static ssize_t | |
386f275f KS |
706 | pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr, |
707 | const char *buf, size_t n) | |
c5c6ba4e RW |
708 | { |
709 | int val; | |
710 | ||
711 | if (sscanf(buf, "%d", &val) == 1) { | |
712 | pm_trace_enabled = !!val; | |
9dceefe4 SK |
713 | if (pm_trace_enabled) { |
714 | pr_warn("PM: Enabling pm_trace changes system date and time during resume.\n" | |
715 | "PM: Correct system time has to be restored manually after resume.\n"); | |
716 | } | |
c5c6ba4e RW |
717 | return n; |
718 | } | |
719 | return -EINVAL; | |
720 | } | |
721 | ||
722 | power_attr(pm_trace); | |
d33ac60b JH |
723 | |
724 | static ssize_t pm_trace_dev_match_show(struct kobject *kobj, | |
725 | struct kobj_attribute *attr, | |
726 | char *buf) | |
727 | { | |
728 | return show_trace_dev_match(buf, PAGE_SIZE); | |
729 | } | |
730 | ||
a1e9ca69 | 731 | power_attr_ro(pm_trace_dev_match); |
d33ac60b | 732 | |
0e7d56e3 | 733 | #endif /* CONFIG_PM_TRACE */ |
c5c6ba4e | 734 | |
957d1282 LF |
735 | #ifdef CONFIG_FREEZER |
736 | static ssize_t pm_freeze_timeout_show(struct kobject *kobj, | |
737 | struct kobj_attribute *attr, char *buf) | |
738 | { | |
739 | return sprintf(buf, "%u\n", freeze_timeout_msecs); | |
740 | } | |
741 | ||
742 | static ssize_t pm_freeze_timeout_store(struct kobject *kobj, | |
743 | struct kobj_attribute *attr, | |
744 | const char *buf, size_t n) | |
745 | { | |
746 | unsigned long val; | |
747 | ||
748 | if (kstrtoul(buf, 10, &val)) | |
749 | return -EINVAL; | |
750 | ||
751 | freeze_timeout_msecs = val; | |
752 | return n; | |
753 | } | |
754 | ||
755 | power_attr(pm_freeze_timeout); | |
756 | ||
757 | #endif /* CONFIG_FREEZER*/ | |
758 | ||
c5c6ba4e RW |
759 | static struct attribute * g[] = { |
760 | &state_attr.attr, | |
0e7d56e3 | 761 | #ifdef CONFIG_PM_TRACE |
c5c6ba4e | 762 | &pm_trace_attr.attr, |
d33ac60b | 763 | &pm_trace_dev_match_attr.attr, |
0e7d56e3 | 764 | #endif |
0e06b4a8 RW |
765 | #ifdef CONFIG_PM_SLEEP |
766 | &pm_async_attr.attr, | |
c125e96f | 767 | &wakeup_count_attr.attr, |
406e7938 RW |
768 | #ifdef CONFIG_SUSPEND |
769 | &mem_sleep_attr.attr, | |
770 | #endif | |
7483b4a4 RW |
771 | #ifdef CONFIG_PM_AUTOSLEEP |
772 | &autosleep_attr.attr, | |
773 | #endif | |
b86ff982 RW |
774 | #ifdef CONFIG_PM_WAKELOCKS |
775 | &wake_lock_attr.attr, | |
776 | &wake_unlock_attr.attr, | |
777 | #endif | |
b2df1d4f | 778 | #ifdef CONFIG_PM_SLEEP_DEBUG |
e516a1db | 779 | &pm_test_attr.attr, |
4b7760ba | 780 | &pm_print_times_attr.attr, |
a6f5f0dd | 781 | &pm_wakeup_irq_attr.attr, |
8d8b2441 | 782 | &pm_debug_messages_attr.attr, |
0e06b4a8 | 783 | #endif |
957d1282 LF |
784 | #endif |
785 | #ifdef CONFIG_FREEZER | |
786 | &pm_freeze_timeout_attr.attr, | |
0e7d56e3 | 787 | #endif |
c5c6ba4e RW |
788 | NULL, |
789 | }; | |
1da177e4 | 790 | |
1d0c6e59 | 791 | static const struct attribute_group attr_group = { |
1da177e4 LT |
792 | .attrs = g, |
793 | }; | |
794 | ||
5e928f77 | 795 | struct workqueue_struct *pm_wq; |
7b199ca2 | 796 | EXPORT_SYMBOL_GPL(pm_wq); |
5e928f77 RW |
797 | |
798 | static int __init pm_start_workqueue(void) | |
799 | { | |
58a69cb4 | 800 | pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0); |
5e928f77 RW |
801 | |
802 | return pm_wq ? 0 : -ENOMEM; | |
803 | } | |
5e928f77 | 804 | |
1da177e4 LT |
805 | static int __init pm_init(void) |
806 | { | |
5e928f77 RW |
807 | int error = pm_start_workqueue(); |
808 | if (error) | |
809 | return error; | |
ac5c24ec | 810 | hibernate_image_size_init(); |
ddeb6487 | 811 | hibernate_reserved_size_init(); |
fa7fd6fa | 812 | pm_states_init(); |
d76e15fb GKH |
813 | power_kobj = kobject_create_and_add("power", NULL); |
814 | if (!power_kobj) | |
039a5dcd | 815 | return -ENOMEM; |
7483b4a4 RW |
816 | error = sysfs_create_group(power_kobj, &attr_group); |
817 | if (error) | |
818 | return error; | |
b2df1d4f | 819 | pm_print_times_init(); |
7483b4a4 | 820 | return pm_autosleep_init(); |
1da177e4 LT |
821 | } |
822 | ||
823 | core_initcall(pm_init); |