xref: /linux-6.15/kernel/power/main.c (revision cb08e035)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * kernel/power/main.c - PM subsystem core functionality.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (c) 2003 Patrick Mochel
51da177e4SLinus Torvalds  * Copyright (c) 2003 Open Source Development Lab
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * This file is released under the GPLv2
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds 
116e5fdeedSPaul Gortmaker #include <linux/export.h>
121da177e4SLinus Torvalds #include <linux/kobject.h>
131da177e4SLinus Torvalds #include <linux/string.h>
14431d452aSZhonghui Fu #include <linux/pm-trace.h>
155e928f77SRafael J. Wysocki #include <linux/workqueue.h>
162a77c46dSShuoX Liu #include <linux/debugfs.h>
172a77c46dSShuoX Liu #include <linux/seq_file.h>
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds #include "power.h"
201da177e4SLinus Torvalds 
21296699deSRafael J. Wysocki DEFINE_MUTEX(pm_mutex);
22296699deSRafael J. Wysocki 
23cd51e61cSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
24cd51e61cSRafael J. Wysocki 
2582525756SAlan Stern /* Routines for PM-transition notifications */
2682525756SAlan Stern 
2782525756SAlan Stern static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
2882525756SAlan Stern 
2982525756SAlan Stern int register_pm_notifier(struct notifier_block *nb)
3082525756SAlan Stern {
3182525756SAlan Stern 	return blocking_notifier_chain_register(&pm_chain_head, nb);
3282525756SAlan Stern }
3382525756SAlan Stern EXPORT_SYMBOL_GPL(register_pm_notifier);
3482525756SAlan Stern 
3582525756SAlan Stern int unregister_pm_notifier(struct notifier_block *nb)
3682525756SAlan Stern {
3782525756SAlan Stern 	return blocking_notifier_chain_unregister(&pm_chain_head, nb);
3882525756SAlan Stern }
3982525756SAlan Stern EXPORT_SYMBOL_GPL(unregister_pm_notifier);
4082525756SAlan Stern 
41ea00f4f4SLianwei Wang int __pm_notifier_call_chain(unsigned long val, int nr_to_call, int *nr_calls)
4282525756SAlan Stern {
43ea00f4f4SLianwei Wang 	int ret;
44ea00f4f4SLianwei Wang 
45ea00f4f4SLianwei Wang 	ret = __blocking_notifier_call_chain(&pm_chain_head, val, NULL,
46ea00f4f4SLianwei Wang 						nr_to_call, nr_calls);
47f0c077a8SAkinobu Mita 
48f0c077a8SAkinobu Mita 	return notifier_to_errno(ret);
4982525756SAlan Stern }
50ea00f4f4SLianwei Wang int pm_notifier_call_chain(unsigned long val)
51ea00f4f4SLianwei Wang {
52ea00f4f4SLianwei Wang 	return __pm_notifier_call_chain(val, -1, NULL);
53ea00f4f4SLianwei Wang }
5482525756SAlan Stern 
550e06b4a8SRafael J. Wysocki /* If set, devices may be suspended and resumed asynchronously. */
560e06b4a8SRafael J. Wysocki int pm_async_enabled = 1;
570e06b4a8SRafael J. Wysocki 
580e06b4a8SRafael J. Wysocki static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
590e06b4a8SRafael J. Wysocki 			     char *buf)
600e06b4a8SRafael J. Wysocki {
610e06b4a8SRafael J. Wysocki 	return sprintf(buf, "%d\n", pm_async_enabled);
620e06b4a8SRafael J. Wysocki }
630e06b4a8SRafael J. Wysocki 
640e06b4a8SRafael J. Wysocki static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
650e06b4a8SRafael J. Wysocki 			      const char *buf, size_t n)
660e06b4a8SRafael J. Wysocki {
670e06b4a8SRafael J. Wysocki 	unsigned long val;
680e06b4a8SRafael J. Wysocki 
69883ee4f7SDaniel Walter 	if (kstrtoul(buf, 10, &val))
700e06b4a8SRafael J. Wysocki 		return -EINVAL;
710e06b4a8SRafael J. Wysocki 
720e06b4a8SRafael J. Wysocki 	if (val > 1)
730e06b4a8SRafael J. Wysocki 		return -EINVAL;
740e06b4a8SRafael J. Wysocki 
750e06b4a8SRafael J. Wysocki 	pm_async_enabled = val;
760e06b4a8SRafael J. Wysocki 	return n;
770e06b4a8SRafael J. Wysocki }
780e06b4a8SRafael J. Wysocki 
790e06b4a8SRafael J. Wysocki power_attr(pm_async);
800e06b4a8SRafael J. Wysocki 
81406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND
82406e7938SRafael J. Wysocki static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr,
83406e7938SRafael J. Wysocki 			      char *buf)
84406e7938SRafael J. Wysocki {
85406e7938SRafael J. Wysocki 	char *s = buf;
86406e7938SRafael J. Wysocki 	suspend_state_t i;
87406e7938SRafael J. Wysocki 
88406e7938SRafael J. Wysocki 	for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
89406e7938SRafael J. Wysocki 		if (mem_sleep_states[i]) {
90406e7938SRafael J. Wysocki 			const char *label = mem_sleep_states[i];
91406e7938SRafael J. Wysocki 
92406e7938SRafael J. Wysocki 			if (mem_sleep_current == i)
93406e7938SRafael J. Wysocki 				s += sprintf(s, "[%s] ", label);
94406e7938SRafael J. Wysocki 			else
95406e7938SRafael J. Wysocki 				s += sprintf(s, "%s ", label);
96406e7938SRafael J. Wysocki 		}
97406e7938SRafael J. Wysocki 
98406e7938SRafael J. Wysocki 	/* Convert the last space to a newline if needed. */
99406e7938SRafael J. Wysocki 	if (s != buf)
100406e7938SRafael J. Wysocki 		*(s-1) = '\n';
101406e7938SRafael J. Wysocki 
102406e7938SRafael J. Wysocki 	return (s - buf);
103406e7938SRafael J. Wysocki }
104406e7938SRafael J. Wysocki 
105406e7938SRafael J. Wysocki static suspend_state_t decode_suspend_state(const char *buf, size_t n)
106406e7938SRafael J. Wysocki {
107406e7938SRafael J. Wysocki 	suspend_state_t state;
108406e7938SRafael J. Wysocki 	char *p;
109406e7938SRafael J. Wysocki 	int len;
110406e7938SRafael J. Wysocki 
111406e7938SRafael J. Wysocki 	p = memchr(buf, '\n', n);
112406e7938SRafael J. Wysocki 	len = p ? p - buf : n;
113406e7938SRafael J. Wysocki 
114406e7938SRafael J. Wysocki 	for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) {
115406e7938SRafael J. Wysocki 		const char *label = mem_sleep_states[state];
116406e7938SRafael J. Wysocki 
117406e7938SRafael J. Wysocki 		if (label && len == strlen(label) && !strncmp(buf, label, len))
118406e7938SRafael J. Wysocki 			return state;
119406e7938SRafael J. Wysocki 	}
120406e7938SRafael J. Wysocki 
121406e7938SRafael J. Wysocki 	return PM_SUSPEND_ON;
122406e7938SRafael J. Wysocki }
123406e7938SRafael J. Wysocki 
124406e7938SRafael J. Wysocki static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr,
125406e7938SRafael J. Wysocki 			       const char *buf, size_t n)
126406e7938SRafael J. Wysocki {
127406e7938SRafael J. Wysocki 	suspend_state_t state;
128406e7938SRafael J. Wysocki 	int error;
129406e7938SRafael J. Wysocki 
130406e7938SRafael J. Wysocki 	error = pm_autosleep_lock();
131406e7938SRafael J. Wysocki 	if (error)
132406e7938SRafael J. Wysocki 		return error;
133406e7938SRafael J. Wysocki 
134406e7938SRafael J. Wysocki 	if (pm_autosleep_state() > PM_SUSPEND_ON) {
135406e7938SRafael J. Wysocki 		error = -EBUSY;
136406e7938SRafael J. Wysocki 		goto out;
137406e7938SRafael J. Wysocki 	}
138406e7938SRafael J. Wysocki 
139406e7938SRafael J. Wysocki 	state = decode_suspend_state(buf, n);
140406e7938SRafael J. Wysocki 	if (state < PM_SUSPEND_MAX && state > PM_SUSPEND_ON)
141406e7938SRafael J. Wysocki 		mem_sleep_current = state;
142406e7938SRafael J. Wysocki 	else
143406e7938SRafael J. Wysocki 		error = -EINVAL;
144406e7938SRafael J. Wysocki 
145406e7938SRafael J. Wysocki  out:
146406e7938SRafael J. Wysocki 	pm_autosleep_unlock();
147406e7938SRafael J. Wysocki 	return error ? error : n;
148406e7938SRafael J. Wysocki }
149406e7938SRafael J. Wysocki 
150406e7938SRafael J. Wysocki power_attr(mem_sleep);
151406e7938SRafael J. Wysocki #endif /* CONFIG_SUSPEND */
152406e7938SRafael J. Wysocki 
1530e7d56e3SRafael J. Wysocki #ifdef CONFIG_PM_DEBUG
1540e7d56e3SRafael J. Wysocki int pm_test_level = TEST_NONE;
1550e7d56e3SRafael J. Wysocki 
1560e7d56e3SRafael J. Wysocki static const char * const pm_tests[__TEST_AFTER_LAST] = {
1570e7d56e3SRafael J. Wysocki 	[TEST_NONE] = "none",
1580e7d56e3SRafael J. Wysocki 	[TEST_CORE] = "core",
1590e7d56e3SRafael J. Wysocki 	[TEST_CPUS] = "processors",
1600e7d56e3SRafael J. Wysocki 	[TEST_PLATFORM] = "platform",
1610e7d56e3SRafael J. Wysocki 	[TEST_DEVICES] = "devices",
1620e7d56e3SRafael J. Wysocki 	[TEST_FREEZER] = "freezer",
1630e7d56e3SRafael J. Wysocki };
1640e7d56e3SRafael J. Wysocki 
165039a75c6SRafael J. Wysocki static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
166039a75c6SRafael J. Wysocki 				char *buf)
1670e7d56e3SRafael J. Wysocki {
1680e7d56e3SRafael J. Wysocki 	char *s = buf;
1690e7d56e3SRafael J. Wysocki 	int level;
1700e7d56e3SRafael J. Wysocki 
1710e7d56e3SRafael J. Wysocki 	for (level = TEST_FIRST; level <= TEST_MAX; level++)
1720e7d56e3SRafael J. Wysocki 		if (pm_tests[level]) {
1730e7d56e3SRafael J. Wysocki 			if (level == pm_test_level)
1740e7d56e3SRafael J. Wysocki 				s += sprintf(s, "[%s] ", pm_tests[level]);
1750e7d56e3SRafael J. Wysocki 			else
1760e7d56e3SRafael J. Wysocki 				s += sprintf(s, "%s ", pm_tests[level]);
1770e7d56e3SRafael J. Wysocki 		}
1780e7d56e3SRafael J. Wysocki 
1790e7d56e3SRafael J. Wysocki 	if (s != buf)
1800e7d56e3SRafael J. Wysocki 		/* convert the last space to a newline */
1810e7d56e3SRafael J. Wysocki 		*(s-1) = '\n';
1820e7d56e3SRafael J. Wysocki 
1830e7d56e3SRafael J. Wysocki 	return (s - buf);
1840e7d56e3SRafael J. Wysocki }
1850e7d56e3SRafael J. Wysocki 
186039a75c6SRafael J. Wysocki static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
187039a75c6SRafael J. Wysocki 				const char *buf, size_t n)
1880e7d56e3SRafael J. Wysocki {
1890e7d56e3SRafael J. Wysocki 	const char * const *s;
1900e7d56e3SRafael J. Wysocki 	int level;
1910e7d56e3SRafael J. Wysocki 	char *p;
1920e7d56e3SRafael J. Wysocki 	int len;
1930e7d56e3SRafael J. Wysocki 	int error = -EINVAL;
1940e7d56e3SRafael J. Wysocki 
1950e7d56e3SRafael J. Wysocki 	p = memchr(buf, '\n', n);
1960e7d56e3SRafael J. Wysocki 	len = p ? p - buf : n;
1970e7d56e3SRafael J. Wysocki 
198bcda53faSSrivatsa S. Bhat 	lock_system_sleep();
1990e7d56e3SRafael J. Wysocki 
2000e7d56e3SRafael J. Wysocki 	level = TEST_FIRST;
2010e7d56e3SRafael J. Wysocki 	for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
2020e7d56e3SRafael J. Wysocki 		if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
2030e7d56e3SRafael J. Wysocki 			pm_test_level = level;
2040e7d56e3SRafael J. Wysocki 			error = 0;
2050e7d56e3SRafael J. Wysocki 			break;
2060e7d56e3SRafael J. Wysocki 		}
2070e7d56e3SRafael J. Wysocki 
208bcda53faSSrivatsa S. Bhat 	unlock_system_sleep();
2090e7d56e3SRafael J. Wysocki 
2100e7d56e3SRafael J. Wysocki 	return error ? error : n;
2110e7d56e3SRafael J. Wysocki }
2120e7d56e3SRafael J. Wysocki 
2130e7d56e3SRafael J. Wysocki power_attr(pm_test);
214091d71e0SRafael J. Wysocki #endif /* CONFIG_PM_DEBUG */
2150e7d56e3SRafael J. Wysocki 
2162a77c46dSShuoX Liu #ifdef CONFIG_DEBUG_FS
2172a77c46dSShuoX Liu static char *suspend_step_name(enum suspend_stat_step step)
2182a77c46dSShuoX Liu {
2192a77c46dSShuoX Liu 	switch (step) {
2202a77c46dSShuoX Liu 	case SUSPEND_FREEZE:
2212a77c46dSShuoX Liu 		return "freeze";
2222a77c46dSShuoX Liu 	case SUSPEND_PREPARE:
2232a77c46dSShuoX Liu 		return "prepare";
2242a77c46dSShuoX Liu 	case SUSPEND_SUSPEND:
2252a77c46dSShuoX Liu 		return "suspend";
2262a77c46dSShuoX Liu 	case SUSPEND_SUSPEND_NOIRQ:
2272a77c46dSShuoX Liu 		return "suspend_noirq";
2282a77c46dSShuoX Liu 	case SUSPEND_RESUME_NOIRQ:
2292a77c46dSShuoX Liu 		return "resume_noirq";
2302a77c46dSShuoX Liu 	case SUSPEND_RESUME:
2312a77c46dSShuoX Liu 		return "resume";
2322a77c46dSShuoX Liu 	default:
2332a77c46dSShuoX Liu 		return "";
2342a77c46dSShuoX Liu 	}
2352a77c46dSShuoX Liu }
2362a77c46dSShuoX Liu 
2372a77c46dSShuoX Liu static int suspend_stats_show(struct seq_file *s, void *unused)
2382a77c46dSShuoX Liu {
2392a77c46dSShuoX Liu 	int i, index, last_dev, last_errno, last_step;
2402a77c46dSShuoX Liu 
2412a77c46dSShuoX Liu 	last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
2422a77c46dSShuoX Liu 	last_dev %= REC_FAILED_NUM;
2432a77c46dSShuoX Liu 	last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1;
2442a77c46dSShuoX Liu 	last_errno %= REC_FAILED_NUM;
2452a77c46dSShuoX Liu 	last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1;
2462a77c46dSShuoX Liu 	last_step %= REC_FAILED_NUM;
247cf579dfbSRafael J. Wysocki 	seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n"
248cf579dfbSRafael J. Wysocki 			"%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n",
2492a77c46dSShuoX Liu 			"success", suspend_stats.success,
2502a77c46dSShuoX Liu 			"fail", suspend_stats.fail,
2512a77c46dSShuoX Liu 			"failed_freeze", suspend_stats.failed_freeze,
2522a77c46dSShuoX Liu 			"failed_prepare", suspend_stats.failed_prepare,
2532a77c46dSShuoX Liu 			"failed_suspend", suspend_stats.failed_suspend,
254cf579dfbSRafael J. Wysocki 			"failed_suspend_late",
255cf579dfbSRafael J. Wysocki 				suspend_stats.failed_suspend_late,
2562a77c46dSShuoX Liu 			"failed_suspend_noirq",
2572a77c46dSShuoX Liu 				suspend_stats.failed_suspend_noirq,
2582a77c46dSShuoX Liu 			"failed_resume", suspend_stats.failed_resume,
259cf579dfbSRafael J. Wysocki 			"failed_resume_early",
260cf579dfbSRafael J. Wysocki 				suspend_stats.failed_resume_early,
2612a77c46dSShuoX Liu 			"failed_resume_noirq",
2622a77c46dSShuoX Liu 				suspend_stats.failed_resume_noirq);
2632a77c46dSShuoX Liu 	seq_printf(s,	"failures:\n  last_failed_dev:\t%-s\n",
2642a77c46dSShuoX Liu 			suspend_stats.failed_devs[last_dev]);
2652a77c46dSShuoX Liu 	for (i = 1; i < REC_FAILED_NUM; i++) {
2662a77c46dSShuoX Liu 		index = last_dev + REC_FAILED_NUM - i;
2672a77c46dSShuoX Liu 		index %= REC_FAILED_NUM;
2682a77c46dSShuoX Liu 		seq_printf(s, "\t\t\t%-s\n",
2692a77c46dSShuoX Liu 			suspend_stats.failed_devs[index]);
2702a77c46dSShuoX Liu 	}
2712a77c46dSShuoX Liu 	seq_printf(s,	"  last_failed_errno:\t%-d\n",
2722a77c46dSShuoX Liu 			suspend_stats.errno[last_errno]);
2732a77c46dSShuoX Liu 	for (i = 1; i < REC_FAILED_NUM; i++) {
2742a77c46dSShuoX Liu 		index = last_errno + REC_FAILED_NUM - i;
2752a77c46dSShuoX Liu 		index %= REC_FAILED_NUM;
2762a77c46dSShuoX Liu 		seq_printf(s, "\t\t\t%-d\n",
2772a77c46dSShuoX Liu 			suspend_stats.errno[index]);
2782a77c46dSShuoX Liu 	}
2792a77c46dSShuoX Liu 	seq_printf(s,	"  last_failed_step:\t%-s\n",
2802a77c46dSShuoX Liu 			suspend_step_name(
2812a77c46dSShuoX Liu 				suspend_stats.failed_steps[last_step]));
2822a77c46dSShuoX Liu 	for (i = 1; i < REC_FAILED_NUM; i++) {
2832a77c46dSShuoX Liu 		index = last_step + REC_FAILED_NUM - i;
2842a77c46dSShuoX Liu 		index %= REC_FAILED_NUM;
2852a77c46dSShuoX Liu 		seq_printf(s, "\t\t\t%-s\n",
2862a77c46dSShuoX Liu 			suspend_step_name(
2872a77c46dSShuoX Liu 				suspend_stats.failed_steps[index]));
2882a77c46dSShuoX Liu 	}
2892a77c46dSShuoX Liu 
2902a77c46dSShuoX Liu 	return 0;
2912a77c46dSShuoX Liu }
2922a77c46dSShuoX Liu 
2932a77c46dSShuoX Liu static int suspend_stats_open(struct inode *inode, struct file *file)
2942a77c46dSShuoX Liu {
2952a77c46dSShuoX Liu 	return single_open(file, suspend_stats_show, NULL);
2962a77c46dSShuoX Liu }
2972a77c46dSShuoX Liu 
2982a77c46dSShuoX Liu static const struct file_operations suspend_stats_operations = {
2992a77c46dSShuoX Liu 	.open           = suspend_stats_open,
3002a77c46dSShuoX Liu 	.read           = seq_read,
3012a77c46dSShuoX Liu 	.llseek         = seq_lseek,
3022a77c46dSShuoX Liu 	.release        = single_release,
3032a77c46dSShuoX Liu };
3042a77c46dSShuoX Liu 
3052a77c46dSShuoX Liu static int __init pm_debugfs_init(void)
3062a77c46dSShuoX Liu {
3072a77c46dSShuoX Liu 	debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO,
3082a77c46dSShuoX Liu 			NULL, NULL, &suspend_stats_operations);
3092a77c46dSShuoX Liu 	return 0;
3102a77c46dSShuoX Liu }
3112a77c46dSShuoX Liu 
3122a77c46dSShuoX Liu late_initcall(pm_debugfs_init);
3132a77c46dSShuoX Liu #endif /* CONFIG_DEBUG_FS */
3142a77c46dSShuoX Liu 
315ca123102SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */
316ca123102SRafael J. Wysocki 
317b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG
318b2df1d4fSRafael J. Wysocki /*
319b2df1d4fSRafael J. Wysocki  * pm_print_times: print time taken by devices to suspend and resume.
320b2df1d4fSRafael J. Wysocki  *
321b2df1d4fSRafael J. Wysocki  * show() returns whether printing of suspend and resume times is enabled.
322b2df1d4fSRafael J. Wysocki  * store() accepts 0 or 1.  0 disables printing and 1 enables it.
323b2df1d4fSRafael J. Wysocki  */
324b2df1d4fSRafael J. Wysocki bool pm_print_times_enabled;
325b2df1d4fSRafael J. Wysocki 
326b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_show(struct kobject *kobj,
327b2df1d4fSRafael J. Wysocki 				   struct kobj_attribute *attr, char *buf)
328b2df1d4fSRafael J. Wysocki {
329b2df1d4fSRafael J. Wysocki 	return sprintf(buf, "%d\n", pm_print_times_enabled);
330b2df1d4fSRafael J. Wysocki }
331b2df1d4fSRafael J. Wysocki 
332b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_store(struct kobject *kobj,
333b2df1d4fSRafael J. Wysocki 				    struct kobj_attribute *attr,
334b2df1d4fSRafael J. Wysocki 				    const char *buf, size_t n)
335b2df1d4fSRafael J. Wysocki {
336b2df1d4fSRafael J. Wysocki 	unsigned long val;
337b2df1d4fSRafael J. Wysocki 
338b2df1d4fSRafael J. Wysocki 	if (kstrtoul(buf, 10, &val))
339b2df1d4fSRafael J. Wysocki 		return -EINVAL;
340b2df1d4fSRafael J. Wysocki 
341b2df1d4fSRafael J. Wysocki 	if (val > 1)
342b2df1d4fSRafael J. Wysocki 		return -EINVAL;
343b2df1d4fSRafael J. Wysocki 
344b2df1d4fSRafael J. Wysocki 	pm_print_times_enabled = !!val;
345b2df1d4fSRafael J. Wysocki 	return n;
346b2df1d4fSRafael J. Wysocki }
347b2df1d4fSRafael J. Wysocki 
348b2df1d4fSRafael J. Wysocki power_attr(pm_print_times);
349b2df1d4fSRafael J. Wysocki 
350b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void)
351b2df1d4fSRafael J. Wysocki {
352b2df1d4fSRafael J. Wysocki 	pm_print_times_enabled = !!initcall_debug;
353b2df1d4fSRafael J. Wysocki }
354a6f5f0ddSAlexandra Yates 
355a6f5f0ddSAlexandra Yates static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
356a6f5f0ddSAlexandra Yates 					struct kobj_attribute *attr,
357a6f5f0ddSAlexandra Yates 					char *buf)
358a6f5f0ddSAlexandra Yates {
359a6f5f0ddSAlexandra Yates 	return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA;
360a6f5f0ddSAlexandra Yates }
361a6f5f0ddSAlexandra Yates 
362a1e9ca69SRafael J. Wysocki power_attr_ro(pm_wakeup_irq);
363a6f5f0ddSAlexandra Yates 
3648d8b2441SRafael J. Wysocki static bool pm_debug_messages_on __read_mostly;
3658d8b2441SRafael J. Wysocki 
3668d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_show(struct kobject *kobj,
3678d8b2441SRafael J. Wysocki 				      struct kobj_attribute *attr, char *buf)
3688d8b2441SRafael J. Wysocki {
3698d8b2441SRafael J. Wysocki 	return sprintf(buf, "%d\n", pm_debug_messages_on);
3708d8b2441SRafael J. Wysocki }
3718d8b2441SRafael J. Wysocki 
3728d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_store(struct kobject *kobj,
3738d8b2441SRafael J. Wysocki 				       struct kobj_attribute *attr,
3748d8b2441SRafael J. Wysocki 				       const char *buf, size_t n)
3758d8b2441SRafael J. Wysocki {
3768d8b2441SRafael J. Wysocki 	unsigned long val;
3778d8b2441SRafael J. Wysocki 
3788d8b2441SRafael J. Wysocki 	if (kstrtoul(buf, 10, &val))
3798d8b2441SRafael J. Wysocki 		return -EINVAL;
3808d8b2441SRafael J. Wysocki 
3818d8b2441SRafael J. Wysocki 	if (val > 1)
3828d8b2441SRafael J. Wysocki 		return -EINVAL;
3838d8b2441SRafael J. Wysocki 
3848d8b2441SRafael J. Wysocki 	pm_debug_messages_on = !!val;
3858d8b2441SRafael J. Wysocki 	return n;
3868d8b2441SRafael J. Wysocki }
3878d8b2441SRafael J. Wysocki 
3888d8b2441SRafael J. Wysocki power_attr(pm_debug_messages);
3898d8b2441SRafael J. Wysocki 
3908d8b2441SRafael J. Wysocki /**
391*cb08e035SRafael J. Wysocki  * __pm_pr_dbg - Print a suspend debug message to the kernel log.
392*cb08e035SRafael J. Wysocki  * @defer: Whether or not to use printk_deferred() to print the message.
3938d8b2441SRafael J. Wysocki  * @fmt: Message format.
3948d8b2441SRafael J. Wysocki  *
3958d8b2441SRafael J. Wysocki  * The message will be emitted if enabled through the pm_debug_messages
3968d8b2441SRafael J. Wysocki  * sysfs attribute.
3978d8b2441SRafael J. Wysocki  */
398*cb08e035SRafael J. Wysocki void __pm_pr_dbg(bool defer, const char *fmt, ...)
3998d8b2441SRafael J. Wysocki {
4008d8b2441SRafael J. Wysocki 	struct va_format vaf;
4018d8b2441SRafael J. Wysocki 	va_list args;
4028d8b2441SRafael J. Wysocki 
4038d8b2441SRafael J. Wysocki 	if (!pm_debug_messages_on)
4048d8b2441SRafael J. Wysocki 		return;
4058d8b2441SRafael J. Wysocki 
4068d8b2441SRafael J. Wysocki 	va_start(args, fmt);
4078d8b2441SRafael J. Wysocki 
4088d8b2441SRafael J. Wysocki 	vaf.fmt = fmt;
4098d8b2441SRafael J. Wysocki 	vaf.va = &args;
4108d8b2441SRafael J. Wysocki 
411*cb08e035SRafael J. Wysocki 	if (defer)
412*cb08e035SRafael J. Wysocki 		printk_deferred(KERN_DEBUG "PM: %pV", &vaf);
413*cb08e035SRafael J. Wysocki 	else
4148d8b2441SRafael J. Wysocki 		printk(KERN_DEBUG "PM: %pV", &vaf);
4158d8b2441SRafael J. Wysocki 
4168d8b2441SRafael J. Wysocki 	va_end(args);
4178d8b2441SRafael J. Wysocki }
4188d8b2441SRafael J. Wysocki 
419819b1bb3SRafael J. Wysocki #else /* !CONFIG_PM_SLEEP_DEBUG */
420b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) {}
421b2df1d4fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */
422b2df1d4fSRafael J. Wysocki 
423d76e15fbSGreg Kroah-Hartman struct kobject *power_kobj;
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds /**
4260399d4dbSRafael J. Wysocki  * state - control system sleep states.
4271da177e4SLinus Torvalds  *
4280399d4dbSRafael J. Wysocki  * show() returns available sleep state labels, which may be "mem", "standby",
4290399d4dbSRafael J. Wysocki  * "freeze" and "disk" (hibernation).  See Documentation/power/states.txt for a
4300399d4dbSRafael J. Wysocki  * description of what they mean.
4311da177e4SLinus Torvalds  *
4320399d4dbSRafael J. Wysocki  * store() accepts one of those strings, translates it into the proper
4330399d4dbSRafael J. Wysocki  * enumerated value, and initiates a suspend transition.
4341da177e4SLinus Torvalds  */
435386f275fSKay Sievers static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
436386f275fSKay Sievers 			  char *buf)
4371da177e4SLinus Torvalds {
4381da177e4SLinus Torvalds 	char *s = buf;
439296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND
44027ddcc65SRafael J. Wysocki 	suspend_state_t i;
4411da177e4SLinus Torvalds 
44227ddcc65SRafael J. Wysocki 	for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
443d431cbc5SRafael J. Wysocki 		if (pm_states[i])
444d431cbc5SRafael J. Wysocki 			s += sprintf(s,"%s ", pm_states[i]);
44527ddcc65SRafael J. Wysocki 
446296699deSRafael J. Wysocki #endif
447a6e15a39SKees Cook 	if (hibernation_available())
448a6e15a39SKees Cook 		s += sprintf(s, "disk ");
449a3d25c27SRafael J. Wysocki 	if (s != buf)
450a3d25c27SRafael J. Wysocki 		/* convert the last space to a newline */
451a3d25c27SRafael J. Wysocki 		*(s-1) = '\n';
4521da177e4SLinus Torvalds 	return (s - buf);
4531da177e4SLinus Torvalds }
4541da177e4SLinus Torvalds 
4557483b4a4SRafael J. Wysocki static suspend_state_t decode_state(const char *buf, size_t n)
4561da177e4SLinus Torvalds {
457296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND
458d431cbc5SRafael J. Wysocki 	suspend_state_t state;
459296699deSRafael J. Wysocki #endif
4601da177e4SLinus Torvalds 	char *p;
4611da177e4SLinus Torvalds 	int len;
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 	p = memchr(buf, '\n', n);
4641da177e4SLinus Torvalds 	len = p ? p - buf : n;
4651da177e4SLinus Torvalds 
4667483b4a4SRafael J. Wysocki 	/* Check hibernation first. */
4677483b4a4SRafael J. Wysocki 	if (len == 4 && !strncmp(buf, "disk", len))
4687483b4a4SRafael J. Wysocki 		return PM_SUSPEND_MAX;
469a3d25c27SRafael J. Wysocki 
470296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND
471d431cbc5SRafael J. Wysocki 	for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) {
472d431cbc5SRafael J. Wysocki 		const char *label = pm_states[state];
473d431cbc5SRafael J. Wysocki 
474d431cbc5SRafael J. Wysocki 		if (label && len == strlen(label) && !strncmp(buf, label, len))
475d431cbc5SRafael J. Wysocki 			return state;
476d431cbc5SRafael J. Wysocki 	}
477296699deSRafael J. Wysocki #endif
478296699deSRafael J. Wysocki 
4797483b4a4SRafael J. Wysocki 	return PM_SUSPEND_ON;
4807483b4a4SRafael J. Wysocki }
4817483b4a4SRafael J. Wysocki 
4827483b4a4SRafael J. Wysocki static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
4837483b4a4SRafael J. Wysocki 			   const char *buf, size_t n)
4847483b4a4SRafael J. Wysocki {
4857483b4a4SRafael J. Wysocki 	suspend_state_t state;
4867483b4a4SRafael J. Wysocki 	int error;
4877483b4a4SRafael J. Wysocki 
4887483b4a4SRafael J. Wysocki 	error = pm_autosleep_lock();
4897483b4a4SRafael J. Wysocki 	if (error)
4907483b4a4SRafael J. Wysocki 		return error;
4917483b4a4SRafael J. Wysocki 
4927483b4a4SRafael J. Wysocki 	if (pm_autosleep_state() > PM_SUSPEND_ON) {
4937483b4a4SRafael J. Wysocki 		error = -EBUSY;
4947483b4a4SRafael J. Wysocki 		goto out;
4957483b4a4SRafael J. Wysocki 	}
4967483b4a4SRafael J. Wysocki 
4977483b4a4SRafael J. Wysocki 	state = decode_state(buf, n);
498406e7938SRafael J. Wysocki 	if (state < PM_SUSPEND_MAX) {
499406e7938SRafael J. Wysocki 		if (state == PM_SUSPEND_MEM)
500406e7938SRafael J. Wysocki 			state = mem_sleep_current;
501406e7938SRafael J. Wysocki 
5027483b4a4SRafael J. Wysocki 		error = pm_suspend(state);
503406e7938SRafael J. Wysocki 	} else if (state == PM_SUSPEND_MAX) {
5047483b4a4SRafael J. Wysocki 		error = hibernate();
505406e7938SRafael J. Wysocki 	} else {
5067483b4a4SRafael J. Wysocki 		error = -EINVAL;
507406e7938SRafael J. Wysocki 	}
5087483b4a4SRafael J. Wysocki 
5097483b4a4SRafael J. Wysocki  out:
5107483b4a4SRafael J. Wysocki 	pm_autosleep_unlock();
5111da177e4SLinus Torvalds 	return error ? error : n;
5121da177e4SLinus Torvalds }
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds power_attr(state);
5151da177e4SLinus Torvalds 
516c125e96fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
517c125e96fSRafael J. Wysocki /*
518c125e96fSRafael J. Wysocki  * The 'wakeup_count' attribute, along with the functions defined in
519c125e96fSRafael J. Wysocki  * drivers/base/power/wakeup.c, provides a means by which wakeup events can be
520c125e96fSRafael J. Wysocki  * handled in a non-racy way.
521c125e96fSRafael J. Wysocki  *
522c125e96fSRafael J. Wysocki  * If a wakeup event occurs when the system is in a sleep state, it simply is
523c125e96fSRafael J. Wysocki  * woken up.  In turn, if an event that would wake the system up from a sleep
524c125e96fSRafael J. Wysocki  * state occurs when it is undergoing a transition to that sleep state, the
525c125e96fSRafael J. Wysocki  * transition should be aborted.  Moreover, if such an event occurs when the
526c125e96fSRafael J. Wysocki  * system is in the working state, an attempt to start a transition to the
527c125e96fSRafael J. Wysocki  * given sleep state should fail during certain period after the detection of
528c125e96fSRafael J. Wysocki  * the event.  Using the 'state' attribute alone is not sufficient to satisfy
529c125e96fSRafael J. Wysocki  * these requirements, because a wakeup event may occur exactly when 'state'
530c125e96fSRafael J. Wysocki  * is being written to and may be delivered to user space right before it is
531c125e96fSRafael J. Wysocki  * frozen, so the event will remain only partially processed until the system is
532c125e96fSRafael J. Wysocki  * woken up by another event.  In particular, it won't cause the transition to
533c125e96fSRafael J. Wysocki  * a sleep state to be aborted.
534c125e96fSRafael J. Wysocki  *
535c125e96fSRafael J. Wysocki  * This difficulty may be overcome if user space uses 'wakeup_count' before
536c125e96fSRafael J. Wysocki  * writing to 'state'.  It first should read from 'wakeup_count' and store
537c125e96fSRafael J. Wysocki  * the read value.  Then, after carrying out its own preparations for the system
538c125e96fSRafael J. Wysocki  * transition to a sleep state, it should write the stored value to
53925985edcSLucas De Marchi  * 'wakeup_count'.  If that fails, at least one wakeup event has occurred since
540c125e96fSRafael J. Wysocki  * 'wakeup_count' was read and 'state' should not be written to.  Otherwise, it
541c125e96fSRafael J. Wysocki  * is allowed to write to 'state', but the transition will be aborted if there
542c125e96fSRafael J. Wysocki  * are any wakeup events detected after 'wakeup_count' was written to.
543c125e96fSRafael J. Wysocki  */
544c125e96fSRafael J. Wysocki 
545c125e96fSRafael J. Wysocki static ssize_t wakeup_count_show(struct kobject *kobj,
546c125e96fSRafael J. Wysocki 				struct kobj_attribute *attr,
547c125e96fSRafael J. Wysocki 				char *buf)
548c125e96fSRafael J. Wysocki {
549074037ecSRafael J. Wysocki 	unsigned int val;
550c125e96fSRafael J. Wysocki 
5517483b4a4SRafael J. Wysocki 	return pm_get_wakeup_count(&val, true) ?
5527483b4a4SRafael J. Wysocki 		sprintf(buf, "%u\n", val) : -EINTR;
553c125e96fSRafael J. Wysocki }
554c125e96fSRafael J. Wysocki 
555c125e96fSRafael J. Wysocki static ssize_t wakeup_count_store(struct kobject *kobj,
556c125e96fSRafael J. Wysocki 				struct kobj_attribute *attr,
557c125e96fSRafael J. Wysocki 				const char *buf, size_t n)
558c125e96fSRafael J. Wysocki {
559074037ecSRafael J. Wysocki 	unsigned int val;
5607483b4a4SRafael J. Wysocki 	int error;
561c125e96fSRafael J. Wysocki 
5627483b4a4SRafael J. Wysocki 	error = pm_autosleep_lock();
5637483b4a4SRafael J. Wysocki 	if (error)
5647483b4a4SRafael J. Wysocki 		return error;
5657483b4a4SRafael J. Wysocki 
5667483b4a4SRafael J. Wysocki 	if (pm_autosleep_state() > PM_SUSPEND_ON) {
5677483b4a4SRafael J. Wysocki 		error = -EBUSY;
5687483b4a4SRafael J. Wysocki 		goto out;
5697483b4a4SRafael J. Wysocki 	}
5707483b4a4SRafael J. Wysocki 
5717483b4a4SRafael J. Wysocki 	error = -EINVAL;
572074037ecSRafael J. Wysocki 	if (sscanf(buf, "%u", &val) == 1) {
573c125e96fSRafael J. Wysocki 		if (pm_save_wakeup_count(val))
5747483b4a4SRafael J. Wysocki 			error = n;
575bb177fedSJulius Werner 		else
576bb177fedSJulius Werner 			pm_print_active_wakeup_sources();
577c125e96fSRafael J. Wysocki 	}
5787483b4a4SRafael J. Wysocki 
5797483b4a4SRafael J. Wysocki  out:
5807483b4a4SRafael J. Wysocki 	pm_autosleep_unlock();
5817483b4a4SRafael J. Wysocki 	return error;
582c125e96fSRafael J. Wysocki }
583c125e96fSRafael J. Wysocki 
584c125e96fSRafael J. Wysocki power_attr(wakeup_count);
5857483b4a4SRafael J. Wysocki 
5867483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP
5877483b4a4SRafael J. Wysocki static ssize_t autosleep_show(struct kobject *kobj,
5887483b4a4SRafael J. Wysocki 			      struct kobj_attribute *attr,
5897483b4a4SRafael J. Wysocki 			      char *buf)
5907483b4a4SRafael J. Wysocki {
5917483b4a4SRafael J. Wysocki 	suspend_state_t state = pm_autosleep_state();
5927483b4a4SRafael J. Wysocki 
5937483b4a4SRafael J. Wysocki 	if (state == PM_SUSPEND_ON)
5947483b4a4SRafael J. Wysocki 		return sprintf(buf, "off\n");
5957483b4a4SRafael J. Wysocki 
5967483b4a4SRafael J. Wysocki #ifdef CONFIG_SUSPEND
5977483b4a4SRafael J. Wysocki 	if (state < PM_SUSPEND_MAX)
598d431cbc5SRafael J. Wysocki 		return sprintf(buf, "%s\n", pm_states[state] ?
599d431cbc5SRafael J. Wysocki 					pm_states[state] : "error");
6007483b4a4SRafael J. Wysocki #endif
6017483b4a4SRafael J. Wysocki #ifdef CONFIG_HIBERNATION
6027483b4a4SRafael J. Wysocki 	return sprintf(buf, "disk\n");
6037483b4a4SRafael J. Wysocki #else
6047483b4a4SRafael J. Wysocki 	return sprintf(buf, "error");
6057483b4a4SRafael J. Wysocki #endif
6067483b4a4SRafael J. Wysocki }
6077483b4a4SRafael J. Wysocki 
6087483b4a4SRafael J. Wysocki static ssize_t autosleep_store(struct kobject *kobj,
6097483b4a4SRafael J. Wysocki 			       struct kobj_attribute *attr,
6107483b4a4SRafael J. Wysocki 			       const char *buf, size_t n)
6117483b4a4SRafael J. Wysocki {
6127483b4a4SRafael J. Wysocki 	suspend_state_t state = decode_state(buf, n);
6137483b4a4SRafael J. Wysocki 	int error;
6147483b4a4SRafael J. Wysocki 
6157483b4a4SRafael J. Wysocki 	if (state == PM_SUSPEND_ON
616040e5bf6SArve Hjønnevåg 	    && strcmp(buf, "off") && strcmp(buf, "off\n"))
6177483b4a4SRafael J. Wysocki 		return -EINVAL;
6187483b4a4SRafael J. Wysocki 
619406e7938SRafael J. Wysocki 	if (state == PM_SUSPEND_MEM)
620406e7938SRafael J. Wysocki 		state = mem_sleep_current;
621406e7938SRafael J. Wysocki 
6227483b4a4SRafael J. Wysocki 	error = pm_autosleep_set_state(state);
6237483b4a4SRafael J. Wysocki 	return error ? error : n;
6247483b4a4SRafael J. Wysocki }
6257483b4a4SRafael J. Wysocki 
6267483b4a4SRafael J. Wysocki power_attr(autosleep);
6277483b4a4SRafael J. Wysocki #endif /* CONFIG_PM_AUTOSLEEP */
628b86ff982SRafael J. Wysocki 
629b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS
630b86ff982SRafael J. Wysocki static ssize_t wake_lock_show(struct kobject *kobj,
631b86ff982SRafael J. Wysocki 			      struct kobj_attribute *attr,
632b86ff982SRafael J. Wysocki 			      char *buf)
633b86ff982SRafael J. Wysocki {
634b86ff982SRafael J. Wysocki 	return pm_show_wakelocks(buf, true);
635b86ff982SRafael J. Wysocki }
636b86ff982SRafael J. Wysocki 
637b86ff982SRafael J. Wysocki static ssize_t wake_lock_store(struct kobject *kobj,
638b86ff982SRafael J. Wysocki 			       struct kobj_attribute *attr,
639b86ff982SRafael J. Wysocki 			       const char *buf, size_t n)
640b86ff982SRafael J. Wysocki {
641b86ff982SRafael J. Wysocki 	int error = pm_wake_lock(buf);
642b86ff982SRafael J. Wysocki 	return error ? error : n;
643b86ff982SRafael J. Wysocki }
644b86ff982SRafael J. Wysocki 
645b86ff982SRafael J. Wysocki power_attr(wake_lock);
646b86ff982SRafael J. Wysocki 
647b86ff982SRafael J. Wysocki static ssize_t wake_unlock_show(struct kobject *kobj,
648b86ff982SRafael J. Wysocki 				struct kobj_attribute *attr,
649b86ff982SRafael J. Wysocki 				char *buf)
650b86ff982SRafael J. Wysocki {
651b86ff982SRafael J. Wysocki 	return pm_show_wakelocks(buf, false);
652b86ff982SRafael J. Wysocki }
653b86ff982SRafael J. Wysocki 
654b86ff982SRafael J. Wysocki static ssize_t wake_unlock_store(struct kobject *kobj,
655b86ff982SRafael J. Wysocki 				 struct kobj_attribute *attr,
656b86ff982SRafael J. Wysocki 				 const char *buf, size_t n)
657b86ff982SRafael J. Wysocki {
658b86ff982SRafael J. Wysocki 	int error = pm_wake_unlock(buf);
659b86ff982SRafael J. Wysocki 	return error ? error : n;
660b86ff982SRafael J. Wysocki }
661b86ff982SRafael J. Wysocki 
662b86ff982SRafael J. Wysocki power_attr(wake_unlock);
663b86ff982SRafael J. Wysocki 
664b86ff982SRafael J. Wysocki #endif /* CONFIG_PM_WAKELOCKS */
665c125e96fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */
666c125e96fSRafael J. Wysocki 
667c5c6ba4eSRafael J. Wysocki #ifdef CONFIG_PM_TRACE
668c5c6ba4eSRafael J. Wysocki int pm_trace_enabled;
669c5c6ba4eSRafael J. Wysocki 
670386f275fSKay Sievers static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,
671386f275fSKay Sievers 			     char *buf)
672c5c6ba4eSRafael J. Wysocki {
673c5c6ba4eSRafael J. Wysocki 	return sprintf(buf, "%d\n", pm_trace_enabled);
674c5c6ba4eSRafael J. Wysocki }
675c5c6ba4eSRafael J. Wysocki 
676c5c6ba4eSRafael J. Wysocki static ssize_t
677386f275fSKay Sievers pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
678386f275fSKay Sievers 	       const char *buf, size_t n)
679c5c6ba4eSRafael J. Wysocki {
680c5c6ba4eSRafael J. Wysocki 	int val;
681c5c6ba4eSRafael J. Wysocki 
682c5c6ba4eSRafael J. Wysocki 	if (sscanf(buf, "%d", &val) == 1) {
683c5c6ba4eSRafael J. Wysocki 		pm_trace_enabled = !!val;
6849dceefe4SShuah Khan 		if (pm_trace_enabled) {
6859dceefe4SShuah Khan 			pr_warn("PM: Enabling pm_trace changes system date and time during resume.\n"
6869dceefe4SShuah Khan 				"PM: Correct system time has to be restored manually after resume.\n");
6879dceefe4SShuah Khan 		}
688c5c6ba4eSRafael J. Wysocki 		return n;
689c5c6ba4eSRafael J. Wysocki 	}
690c5c6ba4eSRafael J. Wysocki 	return -EINVAL;
691c5c6ba4eSRafael J. Wysocki }
692c5c6ba4eSRafael J. Wysocki 
693c5c6ba4eSRafael J. Wysocki power_attr(pm_trace);
694d33ac60bSJames Hogan 
695d33ac60bSJames Hogan static ssize_t pm_trace_dev_match_show(struct kobject *kobj,
696d33ac60bSJames Hogan 				       struct kobj_attribute *attr,
697d33ac60bSJames Hogan 				       char *buf)
698d33ac60bSJames Hogan {
699d33ac60bSJames Hogan 	return show_trace_dev_match(buf, PAGE_SIZE);
700d33ac60bSJames Hogan }
701d33ac60bSJames Hogan 
702a1e9ca69SRafael J. Wysocki power_attr_ro(pm_trace_dev_match);
703d33ac60bSJames Hogan 
7040e7d56e3SRafael J. Wysocki #endif /* CONFIG_PM_TRACE */
705c5c6ba4eSRafael J. Wysocki 
706957d1282SLi Fei #ifdef CONFIG_FREEZER
707957d1282SLi Fei static ssize_t pm_freeze_timeout_show(struct kobject *kobj,
708957d1282SLi Fei 				      struct kobj_attribute *attr, char *buf)
709957d1282SLi Fei {
710957d1282SLi Fei 	return sprintf(buf, "%u\n", freeze_timeout_msecs);
711957d1282SLi Fei }
712957d1282SLi Fei 
713957d1282SLi Fei static ssize_t pm_freeze_timeout_store(struct kobject *kobj,
714957d1282SLi Fei 				       struct kobj_attribute *attr,
715957d1282SLi Fei 				       const char *buf, size_t n)
716957d1282SLi Fei {
717957d1282SLi Fei 	unsigned long val;
718957d1282SLi Fei 
719957d1282SLi Fei 	if (kstrtoul(buf, 10, &val))
720957d1282SLi Fei 		return -EINVAL;
721957d1282SLi Fei 
722957d1282SLi Fei 	freeze_timeout_msecs = val;
723957d1282SLi Fei 	return n;
724957d1282SLi Fei }
725957d1282SLi Fei 
726957d1282SLi Fei power_attr(pm_freeze_timeout);
727957d1282SLi Fei 
728957d1282SLi Fei #endif	/* CONFIG_FREEZER*/
729957d1282SLi Fei 
730c5c6ba4eSRafael J. Wysocki static struct attribute * g[] = {
731c5c6ba4eSRafael J. Wysocki 	&state_attr.attr,
7320e7d56e3SRafael J. Wysocki #ifdef CONFIG_PM_TRACE
733c5c6ba4eSRafael J. Wysocki 	&pm_trace_attr.attr,
734d33ac60bSJames Hogan 	&pm_trace_dev_match_attr.attr,
7350e7d56e3SRafael J. Wysocki #endif
7360e06b4a8SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
7370e06b4a8SRafael J. Wysocki 	&pm_async_attr.attr,
738c125e96fSRafael J. Wysocki 	&wakeup_count_attr.attr,
739406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND
740406e7938SRafael J. Wysocki 	&mem_sleep_attr.attr,
741406e7938SRafael J. Wysocki #endif
7427483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP
7437483b4a4SRafael J. Wysocki 	&autosleep_attr.attr,
7447483b4a4SRafael J. Wysocki #endif
745b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS
746b86ff982SRafael J. Wysocki 	&wake_lock_attr.attr,
747b86ff982SRafael J. Wysocki 	&wake_unlock_attr.attr,
748b86ff982SRafael J. Wysocki #endif
7490e06b4a8SRafael J. Wysocki #ifdef CONFIG_PM_DEBUG
7500e7d56e3SRafael J. Wysocki 	&pm_test_attr.attr,
751b2df1d4fSRafael J. Wysocki #endif
752b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG
7534b7760baSSameer Nanda 	&pm_print_times_attr.attr,
754a6f5f0ddSAlexandra Yates 	&pm_wakeup_irq_attr.attr,
7558d8b2441SRafael J. Wysocki 	&pm_debug_messages_attr.attr,
7560e7d56e3SRafael J. Wysocki #endif
7570e06b4a8SRafael J. Wysocki #endif
758957d1282SLi Fei #ifdef CONFIG_FREEZER
759957d1282SLi Fei 	&pm_freeze_timeout_attr.attr,
760957d1282SLi Fei #endif
761c5c6ba4eSRafael J. Wysocki 	NULL,
762c5c6ba4eSRafael J. Wysocki };
7631da177e4SLinus Torvalds 
7641d0c6e59SArvind Yadav static const struct attribute_group attr_group = {
7651da177e4SLinus Torvalds 	.attrs = g,
7661da177e4SLinus Torvalds };
7671da177e4SLinus Torvalds 
7685e928f77SRafael J. Wysocki struct workqueue_struct *pm_wq;
7697b199ca2SAlan Stern EXPORT_SYMBOL_GPL(pm_wq);
7705e928f77SRafael J. Wysocki 
7715e928f77SRafael J. Wysocki static int __init pm_start_workqueue(void)
7725e928f77SRafael J. Wysocki {
77358a69cb4STejun Heo 	pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0);
7745e928f77SRafael J. Wysocki 
7755e928f77SRafael J. Wysocki 	return pm_wq ? 0 : -ENOMEM;
7765e928f77SRafael J. Wysocki }
7775e928f77SRafael J. Wysocki 
7781da177e4SLinus Torvalds static int __init pm_init(void)
7791da177e4SLinus Torvalds {
7805e928f77SRafael J. Wysocki 	int error = pm_start_workqueue();
7815e928f77SRafael J. Wysocki 	if (error)
7825e928f77SRafael J. Wysocki 		return error;
783ac5c24ecSRafael J. Wysocki 	hibernate_image_size_init();
784ddeb6487SRafael J. Wysocki 	hibernate_reserved_size_init();
785fa7fd6faSSudeep Holla 	pm_states_init();
786d76e15fbSGreg Kroah-Hartman 	power_kobj = kobject_create_and_add("power", NULL);
787d76e15fbSGreg Kroah-Hartman 	if (!power_kobj)
788039a5dcdSGreg Kroah-Hartman 		return -ENOMEM;
7897483b4a4SRafael J. Wysocki 	error = sysfs_create_group(power_kobj, &attr_group);
7907483b4a4SRafael J. Wysocki 	if (error)
7917483b4a4SRafael J. Wysocki 		return error;
792b2df1d4fSRafael J. Wysocki 	pm_print_times_init();
7937483b4a4SRafael J. Wysocki 	return pm_autosleep_init();
7941da177e4SLinus Torvalds }
7951da177e4SLinus Torvalds 
7961da177e4SLinus Torvalds core_initcall(pm_init);
797