1
2
3
4
5
6
7
8
9
10
11#include <linux/export.h>
12#include <linux/kobject.h>
13#include <linux/string.h>
14#include <linux/resume-trace.h>
15#include <linux/workqueue.h>
16#include <linux/debugfs.h>
17#include <linux/seq_file.h>
18
19#include "power.h"
20
21DEFINE_MUTEX(pm_mutex);
22
23#ifdef CONFIG_PM_SLEEP
24
25
26
27static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
28
29int register_pm_notifier(struct notifier_block *nb)
30{
31 return blocking_notifier_chain_register(&pm_chain_head, nb);
32}
33EXPORT_SYMBOL_GPL(register_pm_notifier);
34
35int unregister_pm_notifier(struct notifier_block *nb)
36{
37 return blocking_notifier_chain_unregister(&pm_chain_head, nb);
38}
39EXPORT_SYMBOL_GPL(unregister_pm_notifier);
40
41int pm_notifier_call_chain(unsigned long val)
42{
43 int ret = blocking_notifier_call_chain(&pm_chain_head, val, NULL);
44
45 return notifier_to_errno(ret);
46}
47
48
49int pm_async_enabled = 1;
50
51static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
52 char *buf)
53{
54 return sprintf(buf, "%d\n", pm_async_enabled);
55}
56
57static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
58 const char *buf, size_t n)
59{
60 unsigned long val;
61
62 if (strict_strtoul(buf, 10, &val))
63 return -EINVAL;
64
65 if (val > 1)
66 return -EINVAL;
67
68 pm_async_enabled = val;
69 return n;
70}
71
72power_attr(pm_async);
73
74#ifdef CONFIG_PM_DEBUG
75int pm_test_level = TEST_NONE;
76
77static const char * const pm_tests[__TEST_AFTER_LAST] = {
78 [TEST_NONE] = "none",
79 [TEST_CORE] = "core",
80 [TEST_CPUS] = "processors",
81 [TEST_PLATFORM] = "platform",
82 [TEST_DEVICES] = "devices",
83 [TEST_FREEZER] = "freezer",
84};
85
86static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
87 char *buf)
88{
89 char *s = buf;
90 int level;
91
92 for (level = TEST_FIRST; level <= TEST_MAX; level++)
93 if (pm_tests[level]) {
94 if (level == pm_test_level)
95 s += sprintf(s, "[%s] ", pm_tests[level]);
96 else
97 s += sprintf(s, "%s ", pm_tests[level]);
98 }
99
100 if (s != buf)
101
102 *(s-1) = '\n';
103
104 return (s - buf);
105}
106
107static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
108 const char *buf, size_t n)
109{
110 const char * const *s;
111 int level;
112 char *p;
113 int len;
114 int error = -EINVAL;
115
116 p = memchr(buf, '\n', n);
117 len = p ? p - buf : n;
118
119 lock_system_sleep();
120
121 level = TEST_FIRST;
122 for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
123 if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
124 pm_test_level = level;
125 error = 0;
126 break;
127 }
128
129 unlock_system_sleep();
130
131 return error ? error : n;
132}
133
134power_attr(pm_test);
135#endif
136
137#ifdef CONFIG_DEBUG_FS
138static char *suspend_step_name(enum suspend_stat_step step)
139{
140 switch (step) {
141 case SUSPEND_FREEZE:
142 return "freeze";
143 case SUSPEND_PREPARE:
144 return "prepare";
145 case SUSPEND_SUSPEND:
146 return "suspend";
147 case SUSPEND_SUSPEND_NOIRQ:
148 return "suspend_noirq";
149 case SUSPEND_RESUME_NOIRQ:
150 return "resume_noirq";
151 case SUSPEND_RESUME:
152 return "resume";
153 default:
154 return "";
155 }
156}
157
158static int suspend_stats_show(struct seq_file *s, void *unused)
159{
160 int i, index, last_dev, last_errno, last_step;
161
162 last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
163 last_dev %= REC_FAILED_NUM;
164 last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1;
165 last_errno %= REC_FAILED_NUM;
166 last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1;
167 last_step %= REC_FAILED_NUM;
168 seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n"
169 "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n",
170 "success", suspend_stats.success,
171 "fail", suspend_stats.fail,
172 "failed_freeze", suspend_stats.failed_freeze,
173 "failed_prepare", suspend_stats.failed_prepare,
174 "failed_suspend", suspend_stats.failed_suspend,
175 "failed_suspend_late",
176 suspend_stats.failed_suspend_late,
177 "failed_suspend_noirq",
178 suspend_stats.failed_suspend_noirq,
179 "failed_resume", suspend_stats.failed_resume,
180 "failed_resume_early",
181 suspend_stats.failed_resume_early,
182 "failed_resume_noirq",
183 suspend_stats.failed_resume_noirq);
184 seq_printf(s, "failures:\n last_failed_dev:\t%-s\n",
185 suspend_stats.failed_devs[last_dev]);
186 for (i = 1; i < REC_FAILED_NUM; i++) {
187 index = last_dev + REC_FAILED_NUM - i;
188 index %= REC_FAILED_NUM;
189 seq_printf(s, "\t\t\t%-s\n",
190 suspend_stats.failed_devs[index]);
191 }
192 seq_printf(s, " last_failed_errno:\t%-d\n",
193 suspend_stats.errno[last_errno]);
194 for (i = 1; i < REC_FAILED_NUM; i++) {
195 index = last_errno + REC_FAILED_NUM - i;
196 index %= REC_FAILED_NUM;
197 seq_printf(s, "\t\t\t%-d\n",
198 suspend_stats.errno[index]);
199 }
200 seq_printf(s, " last_failed_step:\t%-s\n",
201 suspend_step_name(
202 suspend_stats.failed_steps[last_step]));
203 for (i = 1; i < REC_FAILED_NUM; i++) {
204 index = last_step + REC_FAILED_NUM - i;
205 index %= REC_FAILED_NUM;
206 seq_printf(s, "\t\t\t%-s\n",
207 suspend_step_name(
208 suspend_stats.failed_steps[index]));
209 }
210
211 return 0;
212}
213
214static int suspend_stats_open(struct inode *inode, struct file *file)
215{
216 return single_open(file, suspend_stats_show, NULL);
217}
218
219static const struct file_operations suspend_stats_operations = {
220 .open = suspend_stats_open,
221 .read = seq_read,
222 .llseek = seq_lseek,
223 .release = single_release,
224};
225
226static int __init pm_debugfs_init(void)
227{
228 debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO,
229 NULL, NULL, &suspend_stats_operations);
230 return 0;
231}
232
233late_initcall(pm_debugfs_init);
234#endif
235
236#endif
237
238#ifdef CONFIG_PM_SLEEP_DEBUG
239
240
241
242
243
244
245bool pm_print_times_enabled;
246
247static ssize_t pm_print_times_show(struct kobject *kobj,
248 struct kobj_attribute *attr, char *buf)
249{
250 return sprintf(buf, "%d\n", pm_print_times_enabled);
251}
252
253static ssize_t pm_print_times_store(struct kobject *kobj,
254 struct kobj_attribute *attr,
255 const char *buf, size_t n)
256{
257 unsigned long val;
258
259 if (kstrtoul(buf, 10, &val))
260 return -EINVAL;
261
262 if (val > 1)
263 return -EINVAL;
264
265 pm_print_times_enabled = !!val;
266 return n;
267}
268
269power_attr(pm_print_times);
270
271static inline void pm_print_times_init(void)
272{
273 pm_print_times_enabled = !!initcall_debug;
274}
275#else
276static inline void pm_print_times_init(void) {}
277#endif
278
279struct kobject *power_kobj;
280
281
282
283
284
285
286
287
288
289
290
291static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
292 char *buf)
293{
294 char *s = buf;
295#ifdef CONFIG_SUSPEND
296 int i;
297
298 for (i = 0; i < PM_SUSPEND_MAX; i++) {
299 if (pm_states[i] && valid_state(i))
300 s += sprintf(s,"%s ", pm_states[i]);
301 }
302#endif
303#ifdef CONFIG_HIBERNATION
304 s += sprintf(s, "%s\n", "disk");
305#else
306 if (s != buf)
307
308 *(s-1) = '\n';
309#endif
310 return (s - buf);
311}
312
313static suspend_state_t decode_state(const char *buf, size_t n)
314{
315#ifdef CONFIG_SUSPEND
316 suspend_state_t state = PM_SUSPEND_STANDBY;
317 const char * const *s;
318#endif
319 char *p;
320 int len;
321
322 p = memchr(buf, '\n', n);
323 len = p ? p - buf : n;
324
325
326 if (len == 4 && !strncmp(buf, "disk", len))
327 return PM_SUSPEND_MAX;
328
329#ifdef CONFIG_SUSPEND
330 for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++)
331 if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
332 return state;
333#endif
334
335 return PM_SUSPEND_ON;
336}
337
338static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
339 const char *buf, size_t n)
340{
341 suspend_state_t state;
342 int error;
343
344 error = pm_autosleep_lock();
345 if (error)
346 return error;
347
348 if (pm_autosleep_state() > PM_SUSPEND_ON) {
349 error = -EBUSY;
350 goto out;
351 }
352
353 state = decode_state(buf, n);
354 if (state < PM_SUSPEND_MAX)
355 error = pm_suspend(state);
356 else if (state == PM_SUSPEND_MAX)
357 error = hibernate();
358 else
359 error = -EINVAL;
360
361 out:
362 pm_autosleep_unlock();
363 return error ? error : n;
364}
365
366power_attr(state);
367
368#ifdef CONFIG_PM_SLEEP
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397static ssize_t wakeup_count_show(struct kobject *kobj,
398 struct kobj_attribute *attr,
399 char *buf)
400{
401 unsigned int val;
402
403 return pm_get_wakeup_count(&val, true) ?
404 sprintf(buf, "%u\n", val) : -EINTR;
405}
406
407static ssize_t wakeup_count_store(struct kobject *kobj,
408 struct kobj_attribute *attr,
409 const char *buf, size_t n)
410{
411 unsigned int val;
412 int error;
413
414 error = pm_autosleep_lock();
415 if (error)
416 return error;
417
418 if (pm_autosleep_state() > PM_SUSPEND_ON) {
419 error = -EBUSY;
420 goto out;
421 }
422
423 error = -EINVAL;
424 if (sscanf(buf, "%u", &val) == 1) {
425 if (pm_save_wakeup_count(val))
426 error = n;
427 }
428
429 out:
430 pm_autosleep_unlock();
431 return error;
432}
433
434power_attr(wakeup_count);
435
436#ifdef CONFIG_PM_AUTOSLEEP
437static ssize_t autosleep_show(struct kobject *kobj,
438 struct kobj_attribute *attr,
439 char *buf)
440{
441 suspend_state_t state = pm_autosleep_state();
442
443 if (state == PM_SUSPEND_ON)
444 return sprintf(buf, "off\n");
445
446#ifdef CONFIG_SUSPEND
447 if (state < PM_SUSPEND_MAX)
448 return sprintf(buf, "%s\n", valid_state(state) ?
449 pm_states[state] : "error");
450#endif
451#ifdef CONFIG_HIBERNATION
452 return sprintf(buf, "disk\n");
453#else
454 return sprintf(buf, "error");
455#endif
456}
457
458static ssize_t autosleep_store(struct kobject *kobj,
459 struct kobj_attribute *attr,
460 const char *buf, size_t n)
461{
462 suspend_state_t state = decode_state(buf, n);
463 int error;
464
465 if (state == PM_SUSPEND_ON
466 && strcmp(buf, "off") && strcmp(buf, "off\n"))
467 return -EINVAL;
468
469 error = pm_autosleep_set_state(state);
470 return error ? error : n;
471}
472
473power_attr(autosleep);
474#endif
475
476#ifdef CONFIG_PM_WAKELOCKS
477static ssize_t wake_lock_show(struct kobject *kobj,
478 struct kobj_attribute *attr,
479 char *buf)
480{
481 return pm_show_wakelocks(buf, true);
482}
483
484static ssize_t wake_lock_store(struct kobject *kobj,
485 struct kobj_attribute *attr,
486 const char *buf, size_t n)
487{
488 int error = pm_wake_lock(buf);
489 return error ? error : n;
490}
491
492power_attr(wake_lock);
493
494static ssize_t wake_unlock_show(struct kobject *kobj,
495 struct kobj_attribute *attr,
496 char *buf)
497{
498 return pm_show_wakelocks(buf, false);
499}
500
501static ssize_t wake_unlock_store(struct kobject *kobj,
502 struct kobj_attribute *attr,
503 const char *buf, size_t n)
504{
505 int error = pm_wake_unlock(buf);
506 return error ? error : n;
507}
508
509power_attr(wake_unlock);
510
511#endif
512#endif
513
514#ifdef CONFIG_PM_TRACE
515int pm_trace_enabled;
516
517static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,
518 char *buf)
519{
520 return sprintf(buf, "%d\n", pm_trace_enabled);
521}
522
523static ssize_t
524pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
525 const char *buf, size_t n)
526{
527 int val;
528
529 if (sscanf(buf, "%d", &val) == 1) {
530 pm_trace_enabled = !!val;
531 return n;
532 }
533 return -EINVAL;
534}
535
536power_attr(pm_trace);
537
538static ssize_t pm_trace_dev_match_show(struct kobject *kobj,
539 struct kobj_attribute *attr,
540 char *buf)
541{
542 return show_trace_dev_match(buf, PAGE_SIZE);
543}
544
545static ssize_t
546pm_trace_dev_match_store(struct kobject *kobj, struct kobj_attribute *attr,
547 const char *buf, size_t n)
548{
549 return -EINVAL;
550}
551
552power_attr(pm_trace_dev_match);
553
554#endif
555
556static struct attribute * g[] = {
557 &state_attr.attr,
558#ifdef CONFIG_PM_TRACE
559 &pm_trace_attr.attr,
560 &pm_trace_dev_match_attr.attr,
561#endif
562#ifdef CONFIG_PM_SLEEP
563 &pm_async_attr.attr,
564 &wakeup_count_attr.attr,
565#ifdef CONFIG_PM_AUTOSLEEP
566 &autosleep_attr.attr,
567#endif
568#ifdef CONFIG_PM_WAKELOCKS
569 &wake_lock_attr.attr,
570 &wake_unlock_attr.attr,
571#endif
572#ifdef CONFIG_PM_DEBUG
573 &pm_test_attr.attr,
574#endif
575#ifdef CONFIG_PM_SLEEP_DEBUG
576 &pm_print_times_attr.attr,
577#endif
578#endif
579 NULL,
580};
581
582static struct attribute_group attr_group = {
583 .attrs = g,
584};
585
586#ifdef CONFIG_PM_RUNTIME
587struct workqueue_struct *pm_wq;
588EXPORT_SYMBOL_GPL(pm_wq);
589
590static int __init pm_start_workqueue(void)
591{
592 pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0);
593
594 return pm_wq ? 0 : -ENOMEM;
595}
596#else
597static inline int pm_start_workqueue(void) { return 0; }
598#endif
599
600static int __init pm_init(void)
601{
602 int error = pm_start_workqueue();
603 if (error)
604 return error;
605 hibernate_image_size_init();
606 hibernate_reserved_size_init();
607 power_kobj = kobject_create_and_add("power", NULL);
608 if (!power_kobj)
609 return -ENOMEM;
610 error = sysfs_create_group(power_kobj, &attr_group);
611 if (error)
612 return error;
613 pm_print_times_init();
614 return pm_autosleep_init();
615}
616
617core_initcall(pm_init);
618