xref: /linux-6.15/kernel/power/main.c (revision b5dee313)
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>
1855f2503cSPingfan Liu #include <linux/suspend.h>
19*b5dee313SHarry Pan #include <linux/syscalls.h>
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds #include "power.h"
221da177e4SLinus Torvalds 
23cd51e61cSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
24cd51e61cSRafael J. Wysocki 
254bf236a3SBart Van Assche void lock_system_sleep(void)
264bf236a3SBart Van Assche {
274bf236a3SBart Van Assche 	current->flags |= PF_FREEZER_SKIP;
2855f2503cSPingfan Liu 	mutex_lock(&system_transition_mutex);
294bf236a3SBart Van Assche }
304bf236a3SBart Van Assche EXPORT_SYMBOL_GPL(lock_system_sleep);
314bf236a3SBart Van Assche 
324bf236a3SBart Van Assche void unlock_system_sleep(void)
334bf236a3SBart Van Assche {
344bf236a3SBart Van Assche 	/*
354bf236a3SBart Van Assche 	 * Don't use freezer_count() because we don't want the call to
364bf236a3SBart Van Assche 	 * try_to_freeze() here.
374bf236a3SBart Van Assche 	 *
384bf236a3SBart Van Assche 	 * Reason:
394bf236a3SBart Van Assche 	 * Fundamentally, we just don't need it, because freezing condition
4055f2503cSPingfan Liu 	 * doesn't come into effect until we release the
4155f2503cSPingfan Liu 	 * system_transition_mutex lock, since the freezer always works with
4255f2503cSPingfan Liu 	 * system_transition_mutex held.
434bf236a3SBart Van Assche 	 *
444bf236a3SBart Van Assche 	 * More importantly, in the case of hibernation,
454bf236a3SBart Van Assche 	 * unlock_system_sleep() gets called in snapshot_read() and
464bf236a3SBart Van Assche 	 * snapshot_write() when the freezing condition is still in effect.
474bf236a3SBart Van Assche 	 * Which means, if we use try_to_freeze() here, it would make them
484bf236a3SBart Van Assche 	 * enter the refrigerator, thus causing hibernation to lockup.
494bf236a3SBart Van Assche 	 */
504bf236a3SBart Van Assche 	current->flags &= ~PF_FREEZER_SKIP;
5155f2503cSPingfan Liu 	mutex_unlock(&system_transition_mutex);
524bf236a3SBart Van Assche }
534bf236a3SBart Van Assche EXPORT_SYMBOL_GPL(unlock_system_sleep);
544bf236a3SBart Van Assche 
55*b5dee313SHarry Pan void ksys_sync_helper(void)
56*b5dee313SHarry Pan {
57*b5dee313SHarry Pan 	pr_info("Syncing filesystems ... ");
58*b5dee313SHarry Pan 	ksys_sync();
59*b5dee313SHarry Pan 	pr_cont("done.\n");
60*b5dee313SHarry Pan }
61*b5dee313SHarry Pan EXPORT_SYMBOL_GPL(ksys_sync_helper);
62*b5dee313SHarry Pan 
6382525756SAlan Stern /* Routines for PM-transition notifications */
6482525756SAlan Stern 
6582525756SAlan Stern static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
6682525756SAlan Stern 
6782525756SAlan Stern int register_pm_notifier(struct notifier_block *nb)
6882525756SAlan Stern {
6982525756SAlan Stern 	return blocking_notifier_chain_register(&pm_chain_head, nb);
7082525756SAlan Stern }
7182525756SAlan Stern EXPORT_SYMBOL_GPL(register_pm_notifier);
7282525756SAlan Stern 
7382525756SAlan Stern int unregister_pm_notifier(struct notifier_block *nb)
7482525756SAlan Stern {
7582525756SAlan Stern 	return blocking_notifier_chain_unregister(&pm_chain_head, nb);
7682525756SAlan Stern }
7782525756SAlan Stern EXPORT_SYMBOL_GPL(unregister_pm_notifier);
7882525756SAlan Stern 
79ea00f4f4SLianwei Wang int __pm_notifier_call_chain(unsigned long val, int nr_to_call, int *nr_calls)
8082525756SAlan Stern {
81ea00f4f4SLianwei Wang 	int ret;
82ea00f4f4SLianwei Wang 
83ea00f4f4SLianwei Wang 	ret = __blocking_notifier_call_chain(&pm_chain_head, val, NULL,
84ea00f4f4SLianwei Wang 						nr_to_call, nr_calls);
85f0c077a8SAkinobu Mita 
86f0c077a8SAkinobu Mita 	return notifier_to_errno(ret);
8782525756SAlan Stern }
88ea00f4f4SLianwei Wang int pm_notifier_call_chain(unsigned long val)
89ea00f4f4SLianwei Wang {
90ea00f4f4SLianwei Wang 	return __pm_notifier_call_chain(val, -1, NULL);
91ea00f4f4SLianwei Wang }
9282525756SAlan Stern 
930e06b4a8SRafael J. Wysocki /* If set, devices may be suspended and resumed asynchronously. */
940e06b4a8SRafael J. Wysocki int pm_async_enabled = 1;
950e06b4a8SRafael J. Wysocki 
960e06b4a8SRafael J. Wysocki static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
970e06b4a8SRafael J. Wysocki 			     char *buf)
980e06b4a8SRafael J. Wysocki {
990e06b4a8SRafael J. Wysocki 	return sprintf(buf, "%d\n", pm_async_enabled);
1000e06b4a8SRafael J. Wysocki }
1010e06b4a8SRafael J. Wysocki 
1020e06b4a8SRafael J. Wysocki static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
1030e06b4a8SRafael J. Wysocki 			      const char *buf, size_t n)
1040e06b4a8SRafael J. Wysocki {
1050e06b4a8SRafael J. Wysocki 	unsigned long val;
1060e06b4a8SRafael J. Wysocki 
107883ee4f7SDaniel Walter 	if (kstrtoul(buf, 10, &val))
1080e06b4a8SRafael J. Wysocki 		return -EINVAL;
1090e06b4a8SRafael J. Wysocki 
1100e06b4a8SRafael J. Wysocki 	if (val > 1)
1110e06b4a8SRafael J. Wysocki 		return -EINVAL;
1120e06b4a8SRafael J. Wysocki 
1130e06b4a8SRafael J. Wysocki 	pm_async_enabled = val;
1140e06b4a8SRafael J. Wysocki 	return n;
1150e06b4a8SRafael J. Wysocki }
1160e06b4a8SRafael J. Wysocki 
1170e06b4a8SRafael J. Wysocki power_attr(pm_async);
1180e06b4a8SRafael J. Wysocki 
119406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND
120406e7938SRafael J. Wysocki static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr,
121406e7938SRafael J. Wysocki 			      char *buf)
122406e7938SRafael J. Wysocki {
123406e7938SRafael J. Wysocki 	char *s = buf;
124406e7938SRafael J. Wysocki 	suspend_state_t i;
125406e7938SRafael J. Wysocki 
126406e7938SRafael J. Wysocki 	for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
127406e7938SRafael J. Wysocki 		if (mem_sleep_states[i]) {
128406e7938SRafael J. Wysocki 			const char *label = mem_sleep_states[i];
129406e7938SRafael J. Wysocki 
130406e7938SRafael J. Wysocki 			if (mem_sleep_current == i)
131406e7938SRafael J. Wysocki 				s += sprintf(s, "[%s] ", label);
132406e7938SRafael J. Wysocki 			else
133406e7938SRafael J. Wysocki 				s += sprintf(s, "%s ", label);
134406e7938SRafael J. Wysocki 		}
135406e7938SRafael J. Wysocki 
136406e7938SRafael J. Wysocki 	/* Convert the last space to a newline if needed. */
137406e7938SRafael J. Wysocki 	if (s != buf)
138406e7938SRafael J. Wysocki 		*(s-1) = '\n';
139406e7938SRafael J. Wysocki 
140406e7938SRafael J. Wysocki 	return (s - buf);
141406e7938SRafael J. Wysocki }
142406e7938SRafael J. Wysocki 
143406e7938SRafael J. Wysocki static suspend_state_t decode_suspend_state(const char *buf, size_t n)
144406e7938SRafael J. Wysocki {
145406e7938SRafael J. Wysocki 	suspend_state_t state;
146406e7938SRafael J. Wysocki 	char *p;
147406e7938SRafael J. Wysocki 	int len;
148406e7938SRafael J. Wysocki 
149406e7938SRafael J. Wysocki 	p = memchr(buf, '\n', n);
150406e7938SRafael J. Wysocki 	len = p ? p - buf : n;
151406e7938SRafael J. Wysocki 
152406e7938SRafael J. Wysocki 	for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) {
153406e7938SRafael J. Wysocki 		const char *label = mem_sleep_states[state];
154406e7938SRafael J. Wysocki 
155406e7938SRafael J. Wysocki 		if (label && len == strlen(label) && !strncmp(buf, label, len))
156406e7938SRafael J. Wysocki 			return state;
157406e7938SRafael J. Wysocki 	}
158406e7938SRafael J. Wysocki 
159406e7938SRafael J. Wysocki 	return PM_SUSPEND_ON;
160406e7938SRafael J. Wysocki }
161406e7938SRafael J. Wysocki 
162406e7938SRafael J. Wysocki static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr,
163406e7938SRafael J. Wysocki 			       const char *buf, size_t n)
164406e7938SRafael J. Wysocki {
165406e7938SRafael J. Wysocki 	suspend_state_t state;
166406e7938SRafael J. Wysocki 	int error;
167406e7938SRafael J. Wysocki 
168406e7938SRafael J. Wysocki 	error = pm_autosleep_lock();
169406e7938SRafael J. Wysocki 	if (error)
170406e7938SRafael J. Wysocki 		return error;
171406e7938SRafael J. Wysocki 
172406e7938SRafael J. Wysocki 	if (pm_autosleep_state() > PM_SUSPEND_ON) {
173406e7938SRafael J. Wysocki 		error = -EBUSY;
174406e7938SRafael J. Wysocki 		goto out;
175406e7938SRafael J. Wysocki 	}
176406e7938SRafael J. Wysocki 
177406e7938SRafael J. Wysocki 	state = decode_suspend_state(buf, n);
178406e7938SRafael J. Wysocki 	if (state < PM_SUSPEND_MAX && state > PM_SUSPEND_ON)
179406e7938SRafael J. Wysocki 		mem_sleep_current = state;
180406e7938SRafael J. Wysocki 	else
181406e7938SRafael J. Wysocki 		error = -EINVAL;
182406e7938SRafael J. Wysocki 
183406e7938SRafael J. Wysocki  out:
184406e7938SRafael J. Wysocki 	pm_autosleep_unlock();
185406e7938SRafael J. Wysocki 	return error ? error : n;
186406e7938SRafael J. Wysocki }
187406e7938SRafael J. Wysocki 
188406e7938SRafael J. Wysocki power_attr(mem_sleep);
189406e7938SRafael J. Wysocki #endif /* CONFIG_SUSPEND */
190406e7938SRafael J. Wysocki 
191e516a1dbSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG
1920e7d56e3SRafael J. Wysocki int pm_test_level = TEST_NONE;
1930e7d56e3SRafael J. Wysocki 
1940e7d56e3SRafael J. Wysocki static const char * const pm_tests[__TEST_AFTER_LAST] = {
1950e7d56e3SRafael J. Wysocki 	[TEST_NONE] = "none",
1960e7d56e3SRafael J. Wysocki 	[TEST_CORE] = "core",
1970e7d56e3SRafael J. Wysocki 	[TEST_CPUS] = "processors",
1980e7d56e3SRafael J. Wysocki 	[TEST_PLATFORM] = "platform",
1990e7d56e3SRafael J. Wysocki 	[TEST_DEVICES] = "devices",
2000e7d56e3SRafael J. Wysocki 	[TEST_FREEZER] = "freezer",
2010e7d56e3SRafael J. Wysocki };
2020e7d56e3SRafael J. Wysocki 
203039a75c6SRafael J. Wysocki static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
204039a75c6SRafael J. Wysocki 				char *buf)
2050e7d56e3SRafael J. Wysocki {
2060e7d56e3SRafael J. Wysocki 	char *s = buf;
2070e7d56e3SRafael J. Wysocki 	int level;
2080e7d56e3SRafael J. Wysocki 
2090e7d56e3SRafael J. Wysocki 	for (level = TEST_FIRST; level <= TEST_MAX; level++)
2100e7d56e3SRafael J. Wysocki 		if (pm_tests[level]) {
2110e7d56e3SRafael J. Wysocki 			if (level == pm_test_level)
2120e7d56e3SRafael J. Wysocki 				s += sprintf(s, "[%s] ", pm_tests[level]);
2130e7d56e3SRafael J. Wysocki 			else
2140e7d56e3SRafael J. Wysocki 				s += sprintf(s, "%s ", pm_tests[level]);
2150e7d56e3SRafael J. Wysocki 		}
2160e7d56e3SRafael J. Wysocki 
2170e7d56e3SRafael J. Wysocki 	if (s != buf)
2180e7d56e3SRafael J. Wysocki 		/* convert the last space to a newline */
2190e7d56e3SRafael J. Wysocki 		*(s-1) = '\n';
2200e7d56e3SRafael J. Wysocki 
2210e7d56e3SRafael J. Wysocki 	return (s - buf);
2220e7d56e3SRafael J. Wysocki }
2230e7d56e3SRafael J. Wysocki 
224039a75c6SRafael J. Wysocki static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
225039a75c6SRafael J. Wysocki 				const char *buf, size_t n)
2260e7d56e3SRafael J. Wysocki {
2270e7d56e3SRafael J. Wysocki 	const char * const *s;
2280e7d56e3SRafael J. Wysocki 	int level;
2290e7d56e3SRafael J. Wysocki 	char *p;
2300e7d56e3SRafael J. Wysocki 	int len;
2310e7d56e3SRafael J. Wysocki 	int error = -EINVAL;
2320e7d56e3SRafael J. Wysocki 
2330e7d56e3SRafael J. Wysocki 	p = memchr(buf, '\n', n);
2340e7d56e3SRafael J. Wysocki 	len = p ? p - buf : n;
2350e7d56e3SRafael J. Wysocki 
236bcda53faSSrivatsa S. Bhat 	lock_system_sleep();
2370e7d56e3SRafael J. Wysocki 
2380e7d56e3SRafael J. Wysocki 	level = TEST_FIRST;
2390e7d56e3SRafael J. Wysocki 	for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
2400e7d56e3SRafael J. Wysocki 		if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
2410e7d56e3SRafael J. Wysocki 			pm_test_level = level;
2420e7d56e3SRafael J. Wysocki 			error = 0;
2430e7d56e3SRafael J. Wysocki 			break;
2440e7d56e3SRafael J. Wysocki 		}
2450e7d56e3SRafael J. Wysocki 
246bcda53faSSrivatsa S. Bhat 	unlock_system_sleep();
2470e7d56e3SRafael J. Wysocki 
2480e7d56e3SRafael J. Wysocki 	return error ? error : n;
2490e7d56e3SRafael J. Wysocki }
2500e7d56e3SRafael J. Wysocki 
2510e7d56e3SRafael J. Wysocki power_attr(pm_test);
252e516a1dbSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */
2530e7d56e3SRafael J. Wysocki 
2542a77c46dSShuoX Liu #ifdef CONFIG_DEBUG_FS
2552a77c46dSShuoX Liu static char *suspend_step_name(enum suspend_stat_step step)
2562a77c46dSShuoX Liu {
2572a77c46dSShuoX Liu 	switch (step) {
2582a77c46dSShuoX Liu 	case SUSPEND_FREEZE:
2592a77c46dSShuoX Liu 		return "freeze";
2602a77c46dSShuoX Liu 	case SUSPEND_PREPARE:
2612a77c46dSShuoX Liu 		return "prepare";
2622a77c46dSShuoX Liu 	case SUSPEND_SUSPEND:
2632a77c46dSShuoX Liu 		return "suspend";
2642a77c46dSShuoX Liu 	case SUSPEND_SUSPEND_NOIRQ:
2652a77c46dSShuoX Liu 		return "suspend_noirq";
2662a77c46dSShuoX Liu 	case SUSPEND_RESUME_NOIRQ:
2672a77c46dSShuoX Liu 		return "resume_noirq";
2682a77c46dSShuoX Liu 	case SUSPEND_RESUME:
2692a77c46dSShuoX Liu 		return "resume";
2702a77c46dSShuoX Liu 	default:
2712a77c46dSShuoX Liu 		return "";
2722a77c46dSShuoX Liu 	}
2732a77c46dSShuoX Liu }
2742a77c46dSShuoX Liu 
2752a77c46dSShuoX Liu static int suspend_stats_show(struct seq_file *s, void *unused)
2762a77c46dSShuoX Liu {
2772a77c46dSShuoX Liu 	int i, index, last_dev, last_errno, last_step;
2782a77c46dSShuoX Liu 
2792a77c46dSShuoX Liu 	last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
2802a77c46dSShuoX Liu 	last_dev %= REC_FAILED_NUM;
2812a77c46dSShuoX Liu 	last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1;
2822a77c46dSShuoX Liu 	last_errno %= REC_FAILED_NUM;
2832a77c46dSShuoX Liu 	last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1;
2842a77c46dSShuoX Liu 	last_step %= REC_FAILED_NUM;
285cf579dfbSRafael J. Wysocki 	seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n"
286cf579dfbSRafael J. Wysocki 			"%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n",
2872a77c46dSShuoX Liu 			"success", suspend_stats.success,
2882a77c46dSShuoX Liu 			"fail", suspend_stats.fail,
2892a77c46dSShuoX Liu 			"failed_freeze", suspend_stats.failed_freeze,
2902a77c46dSShuoX Liu 			"failed_prepare", suspend_stats.failed_prepare,
2912a77c46dSShuoX Liu 			"failed_suspend", suspend_stats.failed_suspend,
292cf579dfbSRafael J. Wysocki 			"failed_suspend_late",
293cf579dfbSRafael J. Wysocki 				suspend_stats.failed_suspend_late,
2942a77c46dSShuoX Liu 			"failed_suspend_noirq",
2952a77c46dSShuoX Liu 				suspend_stats.failed_suspend_noirq,
2962a77c46dSShuoX Liu 			"failed_resume", suspend_stats.failed_resume,
297cf579dfbSRafael J. Wysocki 			"failed_resume_early",
298cf579dfbSRafael J. Wysocki 				suspend_stats.failed_resume_early,
2992a77c46dSShuoX Liu 			"failed_resume_noirq",
3002a77c46dSShuoX Liu 				suspend_stats.failed_resume_noirq);
3012a77c46dSShuoX Liu 	seq_printf(s,	"failures:\n  last_failed_dev:\t%-s\n",
3022a77c46dSShuoX Liu 			suspend_stats.failed_devs[last_dev]);
3032a77c46dSShuoX Liu 	for (i = 1; i < REC_FAILED_NUM; i++) {
3042a77c46dSShuoX Liu 		index = last_dev + REC_FAILED_NUM - i;
3052a77c46dSShuoX Liu 		index %= REC_FAILED_NUM;
3062a77c46dSShuoX Liu 		seq_printf(s, "\t\t\t%-s\n",
3072a77c46dSShuoX Liu 			suspend_stats.failed_devs[index]);
3082a77c46dSShuoX Liu 	}
3092a77c46dSShuoX Liu 	seq_printf(s,	"  last_failed_errno:\t%-d\n",
3102a77c46dSShuoX Liu 			suspend_stats.errno[last_errno]);
3112a77c46dSShuoX Liu 	for (i = 1; i < REC_FAILED_NUM; i++) {
3122a77c46dSShuoX Liu 		index = last_errno + REC_FAILED_NUM - i;
3132a77c46dSShuoX Liu 		index %= REC_FAILED_NUM;
3142a77c46dSShuoX Liu 		seq_printf(s, "\t\t\t%-d\n",
3152a77c46dSShuoX Liu 			suspend_stats.errno[index]);
3162a77c46dSShuoX Liu 	}
3172a77c46dSShuoX Liu 	seq_printf(s,	"  last_failed_step:\t%-s\n",
3182a77c46dSShuoX Liu 			suspend_step_name(
3192a77c46dSShuoX Liu 				suspend_stats.failed_steps[last_step]));
3202a77c46dSShuoX Liu 	for (i = 1; i < REC_FAILED_NUM; i++) {
3212a77c46dSShuoX Liu 		index = last_step + REC_FAILED_NUM - i;
3222a77c46dSShuoX Liu 		index %= REC_FAILED_NUM;
3232a77c46dSShuoX Liu 		seq_printf(s, "\t\t\t%-s\n",
3242a77c46dSShuoX Liu 			suspend_step_name(
3252a77c46dSShuoX Liu 				suspend_stats.failed_steps[index]));
3262a77c46dSShuoX Liu 	}
3272a77c46dSShuoX Liu 
3282a77c46dSShuoX Liu 	return 0;
3292a77c46dSShuoX Liu }
330943a10f8SYangtao Li DEFINE_SHOW_ATTRIBUTE(suspend_stats);
3312a77c46dSShuoX Liu 
3322a77c46dSShuoX Liu static int __init pm_debugfs_init(void)
3332a77c46dSShuoX Liu {
3342a77c46dSShuoX Liu 	debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO,
335943a10f8SYangtao Li 			NULL, NULL, &suspend_stats_fops);
3362a77c46dSShuoX Liu 	return 0;
3372a77c46dSShuoX Liu }
3382a77c46dSShuoX Liu 
3392a77c46dSShuoX Liu late_initcall(pm_debugfs_init);
3402a77c46dSShuoX Liu #endif /* CONFIG_DEBUG_FS */
3412a77c46dSShuoX Liu 
342ca123102SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */
343ca123102SRafael J. Wysocki 
344b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG
345b2df1d4fSRafael J. Wysocki /*
346b2df1d4fSRafael J. Wysocki  * pm_print_times: print time taken by devices to suspend and resume.
347b2df1d4fSRafael J. Wysocki  *
348b2df1d4fSRafael J. Wysocki  * show() returns whether printing of suspend and resume times is enabled.
349b2df1d4fSRafael J. Wysocki  * store() accepts 0 or 1.  0 disables printing and 1 enables it.
350b2df1d4fSRafael J. Wysocki  */
351b2df1d4fSRafael J. Wysocki bool pm_print_times_enabled;
352b2df1d4fSRafael J. Wysocki 
353b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_show(struct kobject *kobj,
354b2df1d4fSRafael J. Wysocki 				   struct kobj_attribute *attr, char *buf)
355b2df1d4fSRafael J. Wysocki {
356b2df1d4fSRafael J. Wysocki 	return sprintf(buf, "%d\n", pm_print_times_enabled);
357b2df1d4fSRafael J. Wysocki }
358b2df1d4fSRafael J. Wysocki 
359b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_store(struct kobject *kobj,
360b2df1d4fSRafael J. Wysocki 				    struct kobj_attribute *attr,
361b2df1d4fSRafael J. Wysocki 				    const char *buf, size_t n)
362b2df1d4fSRafael J. Wysocki {
363b2df1d4fSRafael J. Wysocki 	unsigned long val;
364b2df1d4fSRafael J. Wysocki 
365b2df1d4fSRafael J. Wysocki 	if (kstrtoul(buf, 10, &val))
366b2df1d4fSRafael J. Wysocki 		return -EINVAL;
367b2df1d4fSRafael J. Wysocki 
368b2df1d4fSRafael J. Wysocki 	if (val > 1)
369b2df1d4fSRafael J. Wysocki 		return -EINVAL;
370b2df1d4fSRafael J. Wysocki 
371b2df1d4fSRafael J. Wysocki 	pm_print_times_enabled = !!val;
372b2df1d4fSRafael J. Wysocki 	return n;
373b2df1d4fSRafael J. Wysocki }
374b2df1d4fSRafael J. Wysocki 
375b2df1d4fSRafael J. Wysocki power_attr(pm_print_times);
376b2df1d4fSRafael J. Wysocki 
377b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void)
378b2df1d4fSRafael J. Wysocki {
379b2df1d4fSRafael J. Wysocki 	pm_print_times_enabled = !!initcall_debug;
380b2df1d4fSRafael J. Wysocki }
381a6f5f0ddSAlexandra Yates 
382a6f5f0ddSAlexandra Yates static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
383a6f5f0ddSAlexandra Yates 					struct kobj_attribute *attr,
384a6f5f0ddSAlexandra Yates 					char *buf)
385a6f5f0ddSAlexandra Yates {
386a6f5f0ddSAlexandra Yates 	return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA;
387a6f5f0ddSAlexandra Yates }
388a6f5f0ddSAlexandra Yates 
389a1e9ca69SRafael J. Wysocki power_attr_ro(pm_wakeup_irq);
390a6f5f0ddSAlexandra Yates 
391726fb6b4SSrinivas Pandruvada bool pm_debug_messages_on __read_mostly;
3928d8b2441SRafael J. Wysocki 
3938d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_show(struct kobject *kobj,
3948d8b2441SRafael J. Wysocki 				      struct kobj_attribute *attr, char *buf)
3958d8b2441SRafael J. Wysocki {
3968d8b2441SRafael J. Wysocki 	return sprintf(buf, "%d\n", pm_debug_messages_on);
3978d8b2441SRafael J. Wysocki }
3988d8b2441SRafael J. Wysocki 
3998d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_store(struct kobject *kobj,
4008d8b2441SRafael J. Wysocki 				       struct kobj_attribute *attr,
4018d8b2441SRafael J. Wysocki 				       const char *buf, size_t n)
4028d8b2441SRafael J. Wysocki {
4038d8b2441SRafael J. Wysocki 	unsigned long val;
4048d8b2441SRafael J. Wysocki 
4058d8b2441SRafael J. Wysocki 	if (kstrtoul(buf, 10, &val))
4068d8b2441SRafael J. Wysocki 		return -EINVAL;
4078d8b2441SRafael J. Wysocki 
4088d8b2441SRafael J. Wysocki 	if (val > 1)
4098d8b2441SRafael J. Wysocki 		return -EINVAL;
4108d8b2441SRafael J. Wysocki 
4118d8b2441SRafael J. Wysocki 	pm_debug_messages_on = !!val;
4128d8b2441SRafael J. Wysocki 	return n;
4138d8b2441SRafael J. Wysocki }
4148d8b2441SRafael J. Wysocki 
4158d8b2441SRafael J. Wysocki power_attr(pm_debug_messages);
4168d8b2441SRafael J. Wysocki 
4178d8b2441SRafael J. Wysocki /**
418cb08e035SRafael J. Wysocki  * __pm_pr_dbg - Print a suspend debug message to the kernel log.
419cb08e035SRafael J. Wysocki  * @defer: Whether or not to use printk_deferred() to print the message.
4208d8b2441SRafael J. Wysocki  * @fmt: Message format.
4218d8b2441SRafael J. Wysocki  *
4228d8b2441SRafael J. Wysocki  * The message will be emitted if enabled through the pm_debug_messages
4238d8b2441SRafael J. Wysocki  * sysfs attribute.
4248d8b2441SRafael J. Wysocki  */
425cb08e035SRafael J. Wysocki void __pm_pr_dbg(bool defer, const char *fmt, ...)
4268d8b2441SRafael J. Wysocki {
4278d8b2441SRafael J. Wysocki 	struct va_format vaf;
4288d8b2441SRafael J. Wysocki 	va_list args;
4298d8b2441SRafael J. Wysocki 
4308d8b2441SRafael J. Wysocki 	if (!pm_debug_messages_on)
4318d8b2441SRafael J. Wysocki 		return;
4328d8b2441SRafael J. Wysocki 
4338d8b2441SRafael J. Wysocki 	va_start(args, fmt);
4348d8b2441SRafael J. Wysocki 
4358d8b2441SRafael J. Wysocki 	vaf.fmt = fmt;
4368d8b2441SRafael J. Wysocki 	vaf.va = &args;
4378d8b2441SRafael J. Wysocki 
438cb08e035SRafael J. Wysocki 	if (defer)
439cb08e035SRafael J. Wysocki 		printk_deferred(KERN_DEBUG "PM: %pV", &vaf);
440cb08e035SRafael J. Wysocki 	else
4418d8b2441SRafael J. Wysocki 		printk(KERN_DEBUG "PM: %pV", &vaf);
4428d8b2441SRafael J. Wysocki 
4438d8b2441SRafael J. Wysocki 	va_end(args);
4448d8b2441SRafael J. Wysocki }
4458d8b2441SRafael J. Wysocki 
446819b1bb3SRafael J. Wysocki #else /* !CONFIG_PM_SLEEP_DEBUG */
447b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) {}
448b2df1d4fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */
449b2df1d4fSRafael J. Wysocki 
450d76e15fbSGreg Kroah-Hartman struct kobject *power_kobj;
4511da177e4SLinus Torvalds 
4521da177e4SLinus Torvalds /**
4530399d4dbSRafael J. Wysocki  * state - control system sleep states.
4541da177e4SLinus Torvalds  *
4550399d4dbSRafael J. Wysocki  * show() returns available sleep state labels, which may be "mem", "standby",
45644348e8aSMauro Carvalho Chehab  * "freeze" and "disk" (hibernation).
45744348e8aSMauro Carvalho Chehab  * See Documentation/admin-guide/pm/sleep-states.rst for a description of
45844348e8aSMauro Carvalho Chehab  * what they mean.
4591da177e4SLinus Torvalds  *
4600399d4dbSRafael J. Wysocki  * store() accepts one of those strings, translates it into the proper
4610399d4dbSRafael J. Wysocki  * enumerated value, and initiates a suspend transition.
4621da177e4SLinus Torvalds  */
463386f275fSKay Sievers static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
464386f275fSKay Sievers 			  char *buf)
4651da177e4SLinus Torvalds {
4661da177e4SLinus Torvalds 	char *s = buf;
467296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND
46827ddcc65SRafael J. Wysocki 	suspend_state_t i;
4691da177e4SLinus Torvalds 
47027ddcc65SRafael J. Wysocki 	for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
471d431cbc5SRafael J. Wysocki 		if (pm_states[i])
472d431cbc5SRafael J. Wysocki 			s += sprintf(s,"%s ", pm_states[i]);
47327ddcc65SRafael J. Wysocki 
474296699deSRafael J. Wysocki #endif
475a6e15a39SKees Cook 	if (hibernation_available())
476a6e15a39SKees Cook 		s += sprintf(s, "disk ");
477a3d25c27SRafael J. Wysocki 	if (s != buf)
478a3d25c27SRafael J. Wysocki 		/* convert the last space to a newline */
479a3d25c27SRafael J. Wysocki 		*(s-1) = '\n';
4801da177e4SLinus Torvalds 	return (s - buf);
4811da177e4SLinus Torvalds }
4821da177e4SLinus Torvalds 
4837483b4a4SRafael J. Wysocki static suspend_state_t decode_state(const char *buf, size_t n)
4841da177e4SLinus Torvalds {
485296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND
486d431cbc5SRafael J. Wysocki 	suspend_state_t state;
487296699deSRafael J. Wysocki #endif
4881da177e4SLinus Torvalds 	char *p;
4891da177e4SLinus Torvalds 	int len;
4901da177e4SLinus Torvalds 
4911da177e4SLinus Torvalds 	p = memchr(buf, '\n', n);
4921da177e4SLinus Torvalds 	len = p ? p - buf : n;
4931da177e4SLinus Torvalds 
4947483b4a4SRafael J. Wysocki 	/* Check hibernation first. */
4957483b4a4SRafael J. Wysocki 	if (len == 4 && !strncmp(buf, "disk", len))
4967483b4a4SRafael J. Wysocki 		return PM_SUSPEND_MAX;
497a3d25c27SRafael J. Wysocki 
498296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND
499d431cbc5SRafael J. Wysocki 	for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) {
500d431cbc5SRafael J. Wysocki 		const char *label = pm_states[state];
501d431cbc5SRafael J. Wysocki 
502d431cbc5SRafael J. Wysocki 		if (label && len == strlen(label) && !strncmp(buf, label, len))
503d431cbc5SRafael J. Wysocki 			return state;
504d431cbc5SRafael J. Wysocki 	}
505296699deSRafael J. Wysocki #endif
506296699deSRafael J. Wysocki 
5077483b4a4SRafael J. Wysocki 	return PM_SUSPEND_ON;
5087483b4a4SRafael J. Wysocki }
5097483b4a4SRafael J. Wysocki 
5107483b4a4SRafael J. Wysocki static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
5117483b4a4SRafael J. Wysocki 			   const char *buf, size_t n)
5127483b4a4SRafael J. Wysocki {
5137483b4a4SRafael J. Wysocki 	suspend_state_t state;
5147483b4a4SRafael J. Wysocki 	int error;
5157483b4a4SRafael J. Wysocki 
5167483b4a4SRafael J. Wysocki 	error = pm_autosleep_lock();
5177483b4a4SRafael J. Wysocki 	if (error)
5187483b4a4SRafael J. Wysocki 		return error;
5197483b4a4SRafael J. Wysocki 
5207483b4a4SRafael J. Wysocki 	if (pm_autosleep_state() > PM_SUSPEND_ON) {
5217483b4a4SRafael J. Wysocki 		error = -EBUSY;
5227483b4a4SRafael J. Wysocki 		goto out;
5237483b4a4SRafael J. Wysocki 	}
5247483b4a4SRafael J. Wysocki 
5257483b4a4SRafael J. Wysocki 	state = decode_state(buf, n);
526406e7938SRafael J. Wysocki 	if (state < PM_SUSPEND_MAX) {
527406e7938SRafael J. Wysocki 		if (state == PM_SUSPEND_MEM)
528406e7938SRafael J. Wysocki 			state = mem_sleep_current;
529406e7938SRafael J. Wysocki 
5307483b4a4SRafael J. Wysocki 		error = pm_suspend(state);
531406e7938SRafael J. Wysocki 	} else if (state == PM_SUSPEND_MAX) {
5327483b4a4SRafael J. Wysocki 		error = hibernate();
533406e7938SRafael J. Wysocki 	} else {
5347483b4a4SRafael J. Wysocki 		error = -EINVAL;
535406e7938SRafael J. Wysocki 	}
5367483b4a4SRafael J. Wysocki 
5377483b4a4SRafael J. Wysocki  out:
5387483b4a4SRafael J. Wysocki 	pm_autosleep_unlock();
5391da177e4SLinus Torvalds 	return error ? error : n;
5401da177e4SLinus Torvalds }
5411da177e4SLinus Torvalds 
5421da177e4SLinus Torvalds power_attr(state);
5431da177e4SLinus Torvalds 
544c125e96fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
545c125e96fSRafael J. Wysocki /*
546c125e96fSRafael J. Wysocki  * The 'wakeup_count' attribute, along with the functions defined in
547c125e96fSRafael J. Wysocki  * drivers/base/power/wakeup.c, provides a means by which wakeup events can be
548c125e96fSRafael J. Wysocki  * handled in a non-racy way.
549c125e96fSRafael J. Wysocki  *
550c125e96fSRafael J. Wysocki  * If a wakeup event occurs when the system is in a sleep state, it simply is
551c125e96fSRafael J. Wysocki  * woken up.  In turn, if an event that would wake the system up from a sleep
552c125e96fSRafael J. Wysocki  * state occurs when it is undergoing a transition to that sleep state, the
553c125e96fSRafael J. Wysocki  * transition should be aborted.  Moreover, if such an event occurs when the
554c125e96fSRafael J. Wysocki  * system is in the working state, an attempt to start a transition to the
555c125e96fSRafael J. Wysocki  * given sleep state should fail during certain period after the detection of
556c125e96fSRafael J. Wysocki  * the event.  Using the 'state' attribute alone is not sufficient to satisfy
557c125e96fSRafael J. Wysocki  * these requirements, because a wakeup event may occur exactly when 'state'
558c125e96fSRafael J. Wysocki  * is being written to and may be delivered to user space right before it is
559c125e96fSRafael J. Wysocki  * frozen, so the event will remain only partially processed until the system is
560c125e96fSRafael J. Wysocki  * woken up by another event.  In particular, it won't cause the transition to
561c125e96fSRafael J. Wysocki  * a sleep state to be aborted.
562c125e96fSRafael J. Wysocki  *
563c125e96fSRafael J. Wysocki  * This difficulty may be overcome if user space uses 'wakeup_count' before
564c125e96fSRafael J. Wysocki  * writing to 'state'.  It first should read from 'wakeup_count' and store
565c125e96fSRafael J. Wysocki  * the read value.  Then, after carrying out its own preparations for the system
566c125e96fSRafael J. Wysocki  * transition to a sleep state, it should write the stored value to
56725985edcSLucas De Marchi  * 'wakeup_count'.  If that fails, at least one wakeup event has occurred since
568c125e96fSRafael J. Wysocki  * 'wakeup_count' was read and 'state' should not be written to.  Otherwise, it
569c125e96fSRafael J. Wysocki  * is allowed to write to 'state', but the transition will be aborted if there
570c125e96fSRafael J. Wysocki  * are any wakeup events detected after 'wakeup_count' was written to.
571c125e96fSRafael J. Wysocki  */
572c125e96fSRafael J. Wysocki 
573c125e96fSRafael J. Wysocki static ssize_t wakeup_count_show(struct kobject *kobj,
574c125e96fSRafael J. Wysocki 				struct kobj_attribute *attr,
575c125e96fSRafael J. Wysocki 				char *buf)
576c125e96fSRafael J. Wysocki {
577074037ecSRafael J. Wysocki 	unsigned int val;
578c125e96fSRafael J. Wysocki 
5797483b4a4SRafael J. Wysocki 	return pm_get_wakeup_count(&val, true) ?
5807483b4a4SRafael J. Wysocki 		sprintf(buf, "%u\n", val) : -EINTR;
581c125e96fSRafael J. Wysocki }
582c125e96fSRafael J. Wysocki 
583c125e96fSRafael J. Wysocki static ssize_t wakeup_count_store(struct kobject *kobj,
584c125e96fSRafael J. Wysocki 				struct kobj_attribute *attr,
585c125e96fSRafael J. Wysocki 				const char *buf, size_t n)
586c125e96fSRafael J. Wysocki {
587074037ecSRafael J. Wysocki 	unsigned int val;
5887483b4a4SRafael J. Wysocki 	int error;
589c125e96fSRafael J. Wysocki 
5907483b4a4SRafael J. Wysocki 	error = pm_autosleep_lock();
5917483b4a4SRafael J. Wysocki 	if (error)
5927483b4a4SRafael J. Wysocki 		return error;
5937483b4a4SRafael J. Wysocki 
5947483b4a4SRafael J. Wysocki 	if (pm_autosleep_state() > PM_SUSPEND_ON) {
5957483b4a4SRafael J. Wysocki 		error = -EBUSY;
5967483b4a4SRafael J. Wysocki 		goto out;
5977483b4a4SRafael J. Wysocki 	}
5987483b4a4SRafael J. Wysocki 
5997483b4a4SRafael J. Wysocki 	error = -EINVAL;
600074037ecSRafael J. Wysocki 	if (sscanf(buf, "%u", &val) == 1) {
601c125e96fSRafael J. Wysocki 		if (pm_save_wakeup_count(val))
6027483b4a4SRafael J. Wysocki 			error = n;
603bb177fedSJulius Werner 		else
604bb177fedSJulius Werner 			pm_print_active_wakeup_sources();
605c125e96fSRafael J. Wysocki 	}
6067483b4a4SRafael J. Wysocki 
6077483b4a4SRafael J. Wysocki  out:
6087483b4a4SRafael J. Wysocki 	pm_autosleep_unlock();
6097483b4a4SRafael J. Wysocki 	return error;
610c125e96fSRafael J. Wysocki }
611c125e96fSRafael J. Wysocki 
612c125e96fSRafael J. Wysocki power_attr(wakeup_count);
6137483b4a4SRafael J. Wysocki 
6147483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP
6157483b4a4SRafael J. Wysocki static ssize_t autosleep_show(struct kobject *kobj,
6167483b4a4SRafael J. Wysocki 			      struct kobj_attribute *attr,
6177483b4a4SRafael J. Wysocki 			      char *buf)
6187483b4a4SRafael J. Wysocki {
6197483b4a4SRafael J. Wysocki 	suspend_state_t state = pm_autosleep_state();
6207483b4a4SRafael J. Wysocki 
6217483b4a4SRafael J. Wysocki 	if (state == PM_SUSPEND_ON)
6227483b4a4SRafael J. Wysocki 		return sprintf(buf, "off\n");
6237483b4a4SRafael J. Wysocki 
6247483b4a4SRafael J. Wysocki #ifdef CONFIG_SUSPEND
6257483b4a4SRafael J. Wysocki 	if (state < PM_SUSPEND_MAX)
626d431cbc5SRafael J. Wysocki 		return sprintf(buf, "%s\n", pm_states[state] ?
627d431cbc5SRafael J. Wysocki 					pm_states[state] : "error");
6287483b4a4SRafael J. Wysocki #endif
6297483b4a4SRafael J. Wysocki #ifdef CONFIG_HIBERNATION
6307483b4a4SRafael J. Wysocki 	return sprintf(buf, "disk\n");
6317483b4a4SRafael J. Wysocki #else
6327483b4a4SRafael J. Wysocki 	return sprintf(buf, "error");
6337483b4a4SRafael J. Wysocki #endif
6347483b4a4SRafael J. Wysocki }
6357483b4a4SRafael J. Wysocki 
6367483b4a4SRafael J. Wysocki static ssize_t autosleep_store(struct kobject *kobj,
6377483b4a4SRafael J. Wysocki 			       struct kobj_attribute *attr,
6387483b4a4SRafael J. Wysocki 			       const char *buf, size_t n)
6397483b4a4SRafael J. Wysocki {
6407483b4a4SRafael J. Wysocki 	suspend_state_t state = decode_state(buf, n);
6417483b4a4SRafael J. Wysocki 	int error;
6427483b4a4SRafael J. Wysocki 
6437483b4a4SRafael J. Wysocki 	if (state == PM_SUSPEND_ON
644040e5bf6SArve Hjønnevåg 	    && strcmp(buf, "off") && strcmp(buf, "off\n"))
6457483b4a4SRafael J. Wysocki 		return -EINVAL;
6467483b4a4SRafael J. Wysocki 
647406e7938SRafael J. Wysocki 	if (state == PM_SUSPEND_MEM)
648406e7938SRafael J. Wysocki 		state = mem_sleep_current;
649406e7938SRafael J. Wysocki 
6507483b4a4SRafael J. Wysocki 	error = pm_autosleep_set_state(state);
6517483b4a4SRafael J. Wysocki 	return error ? error : n;
6527483b4a4SRafael J. Wysocki }
6537483b4a4SRafael J. Wysocki 
6547483b4a4SRafael J. Wysocki power_attr(autosleep);
6557483b4a4SRafael J. Wysocki #endif /* CONFIG_PM_AUTOSLEEP */
656b86ff982SRafael J. Wysocki 
657b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS
658b86ff982SRafael J. Wysocki static ssize_t wake_lock_show(struct kobject *kobj,
659b86ff982SRafael J. Wysocki 			      struct kobj_attribute *attr,
660b86ff982SRafael J. Wysocki 			      char *buf)
661b86ff982SRafael J. Wysocki {
662b86ff982SRafael J. Wysocki 	return pm_show_wakelocks(buf, true);
663b86ff982SRafael J. Wysocki }
664b86ff982SRafael J. Wysocki 
665b86ff982SRafael J. Wysocki static ssize_t wake_lock_store(struct kobject *kobj,
666b86ff982SRafael J. Wysocki 			       struct kobj_attribute *attr,
667b86ff982SRafael J. Wysocki 			       const char *buf, size_t n)
668b86ff982SRafael J. Wysocki {
669b86ff982SRafael J. Wysocki 	int error = pm_wake_lock(buf);
670b86ff982SRafael J. Wysocki 	return error ? error : n;
671b86ff982SRafael J. Wysocki }
672b86ff982SRafael J. Wysocki 
673b86ff982SRafael J. Wysocki power_attr(wake_lock);
674b86ff982SRafael J. Wysocki 
675b86ff982SRafael J. Wysocki static ssize_t wake_unlock_show(struct kobject *kobj,
676b86ff982SRafael J. Wysocki 				struct kobj_attribute *attr,
677b86ff982SRafael J. Wysocki 				char *buf)
678b86ff982SRafael J. Wysocki {
679b86ff982SRafael J. Wysocki 	return pm_show_wakelocks(buf, false);
680b86ff982SRafael J. Wysocki }
681b86ff982SRafael J. Wysocki 
682b86ff982SRafael J. Wysocki static ssize_t wake_unlock_store(struct kobject *kobj,
683b86ff982SRafael J. Wysocki 				 struct kobj_attribute *attr,
684b86ff982SRafael J. Wysocki 				 const char *buf, size_t n)
685b86ff982SRafael J. Wysocki {
686b86ff982SRafael J. Wysocki 	int error = pm_wake_unlock(buf);
687b86ff982SRafael J. Wysocki 	return error ? error : n;
688b86ff982SRafael J. Wysocki }
689b86ff982SRafael J. Wysocki 
690b86ff982SRafael J. Wysocki power_attr(wake_unlock);
691b86ff982SRafael J. Wysocki 
692b86ff982SRafael J. Wysocki #endif /* CONFIG_PM_WAKELOCKS */
693c125e96fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */
694c125e96fSRafael J. Wysocki 
695c5c6ba4eSRafael J. Wysocki #ifdef CONFIG_PM_TRACE
696c5c6ba4eSRafael J. Wysocki int pm_trace_enabled;
697c5c6ba4eSRafael J. Wysocki 
698386f275fSKay Sievers static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,
699386f275fSKay Sievers 			     char *buf)
700c5c6ba4eSRafael J. Wysocki {
701c5c6ba4eSRafael J. Wysocki 	return sprintf(buf, "%d\n", pm_trace_enabled);
702c5c6ba4eSRafael J. Wysocki }
703c5c6ba4eSRafael J. Wysocki 
704c5c6ba4eSRafael J. Wysocki static ssize_t
705386f275fSKay Sievers pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
706386f275fSKay Sievers 	       const char *buf, size_t n)
707c5c6ba4eSRafael J. Wysocki {
708c5c6ba4eSRafael J. Wysocki 	int val;
709c5c6ba4eSRafael J. Wysocki 
710c5c6ba4eSRafael J. Wysocki 	if (sscanf(buf, "%d", &val) == 1) {
711c5c6ba4eSRafael J. Wysocki 		pm_trace_enabled = !!val;
7129dceefe4SShuah Khan 		if (pm_trace_enabled) {
7139dceefe4SShuah Khan 			pr_warn("PM: Enabling pm_trace changes system date and time during resume.\n"
7149dceefe4SShuah Khan 				"PM: Correct system time has to be restored manually after resume.\n");
7159dceefe4SShuah Khan 		}
716c5c6ba4eSRafael J. Wysocki 		return n;
717c5c6ba4eSRafael J. Wysocki 	}
718c5c6ba4eSRafael J. Wysocki 	return -EINVAL;
719c5c6ba4eSRafael J. Wysocki }
720c5c6ba4eSRafael J. Wysocki 
721c5c6ba4eSRafael J. Wysocki power_attr(pm_trace);
722d33ac60bSJames Hogan 
723d33ac60bSJames Hogan static ssize_t pm_trace_dev_match_show(struct kobject *kobj,
724d33ac60bSJames Hogan 				       struct kobj_attribute *attr,
725d33ac60bSJames Hogan 				       char *buf)
726d33ac60bSJames Hogan {
727d33ac60bSJames Hogan 	return show_trace_dev_match(buf, PAGE_SIZE);
728d33ac60bSJames Hogan }
729d33ac60bSJames Hogan 
730a1e9ca69SRafael J. Wysocki power_attr_ro(pm_trace_dev_match);
731d33ac60bSJames Hogan 
7320e7d56e3SRafael J. Wysocki #endif /* CONFIG_PM_TRACE */
733c5c6ba4eSRafael J. Wysocki 
734957d1282SLi Fei #ifdef CONFIG_FREEZER
735957d1282SLi Fei static ssize_t pm_freeze_timeout_show(struct kobject *kobj,
736957d1282SLi Fei 				      struct kobj_attribute *attr, char *buf)
737957d1282SLi Fei {
738957d1282SLi Fei 	return sprintf(buf, "%u\n", freeze_timeout_msecs);
739957d1282SLi Fei }
740957d1282SLi Fei 
741957d1282SLi Fei static ssize_t pm_freeze_timeout_store(struct kobject *kobj,
742957d1282SLi Fei 				       struct kobj_attribute *attr,
743957d1282SLi Fei 				       const char *buf, size_t n)
744957d1282SLi Fei {
745957d1282SLi Fei 	unsigned long val;
746957d1282SLi Fei 
747957d1282SLi Fei 	if (kstrtoul(buf, 10, &val))
748957d1282SLi Fei 		return -EINVAL;
749957d1282SLi Fei 
750957d1282SLi Fei 	freeze_timeout_msecs = val;
751957d1282SLi Fei 	return n;
752957d1282SLi Fei }
753957d1282SLi Fei 
754957d1282SLi Fei power_attr(pm_freeze_timeout);
755957d1282SLi Fei 
756957d1282SLi Fei #endif	/* CONFIG_FREEZER*/
757957d1282SLi Fei 
758c5c6ba4eSRafael J. Wysocki static struct attribute * g[] = {
759c5c6ba4eSRafael J. Wysocki 	&state_attr.attr,
7600e7d56e3SRafael J. Wysocki #ifdef CONFIG_PM_TRACE
761c5c6ba4eSRafael J. Wysocki 	&pm_trace_attr.attr,
762d33ac60bSJames Hogan 	&pm_trace_dev_match_attr.attr,
7630e7d56e3SRafael J. Wysocki #endif
7640e06b4a8SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
7650e06b4a8SRafael J. Wysocki 	&pm_async_attr.attr,
766c125e96fSRafael J. Wysocki 	&wakeup_count_attr.attr,
767406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND
768406e7938SRafael J. Wysocki 	&mem_sleep_attr.attr,
769406e7938SRafael J. Wysocki #endif
7707483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP
7717483b4a4SRafael J. Wysocki 	&autosleep_attr.attr,
7727483b4a4SRafael J. Wysocki #endif
773b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS
774b86ff982SRafael J. Wysocki 	&wake_lock_attr.attr,
775b86ff982SRafael J. Wysocki 	&wake_unlock_attr.attr,
776b86ff982SRafael J. Wysocki #endif
777b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG
778e516a1dbSRafael J. Wysocki 	&pm_test_attr.attr,
7794b7760baSSameer Nanda 	&pm_print_times_attr.attr,
780a6f5f0ddSAlexandra Yates 	&pm_wakeup_irq_attr.attr,
7818d8b2441SRafael J. Wysocki 	&pm_debug_messages_attr.attr,
7820e7d56e3SRafael J. Wysocki #endif
7830e06b4a8SRafael J. Wysocki #endif
784957d1282SLi Fei #ifdef CONFIG_FREEZER
785957d1282SLi Fei 	&pm_freeze_timeout_attr.attr,
786957d1282SLi Fei #endif
787c5c6ba4eSRafael J. Wysocki 	NULL,
788c5c6ba4eSRafael J. Wysocki };
7891da177e4SLinus Torvalds 
7901d0c6e59SArvind Yadav static const struct attribute_group attr_group = {
7911da177e4SLinus Torvalds 	.attrs = g,
7921da177e4SLinus Torvalds };
7931da177e4SLinus Torvalds 
7945e928f77SRafael J. Wysocki struct workqueue_struct *pm_wq;
7957b199ca2SAlan Stern EXPORT_SYMBOL_GPL(pm_wq);
7965e928f77SRafael J. Wysocki 
7975e928f77SRafael J. Wysocki static int __init pm_start_workqueue(void)
7985e928f77SRafael J. Wysocki {
79958a69cb4STejun Heo 	pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0);
8005e928f77SRafael J. Wysocki 
8015e928f77SRafael J. Wysocki 	return pm_wq ? 0 : -ENOMEM;
8025e928f77SRafael J. Wysocki }
8035e928f77SRafael J. Wysocki 
8041da177e4SLinus Torvalds static int __init pm_init(void)
8051da177e4SLinus Torvalds {
8065e928f77SRafael J. Wysocki 	int error = pm_start_workqueue();
8075e928f77SRafael J. Wysocki 	if (error)
8085e928f77SRafael J. Wysocki 		return error;
809ac5c24ecSRafael J. Wysocki 	hibernate_image_size_init();
810ddeb6487SRafael J. Wysocki 	hibernate_reserved_size_init();
811fa7fd6faSSudeep Holla 	pm_states_init();
812d76e15fbSGreg Kroah-Hartman 	power_kobj = kobject_create_and_add("power", NULL);
813d76e15fbSGreg Kroah-Hartman 	if (!power_kobj)
814039a5dcdSGreg Kroah-Hartman 		return -ENOMEM;
8157483b4a4SRafael J. Wysocki 	error = sysfs_create_group(power_kobj, &attr_group);
8167483b4a4SRafael J. Wysocki 	if (error)
8177483b4a4SRafael J. Wysocki 		return error;
818b2df1d4fSRafael J. Wysocki 	pm_print_times_init();
8197483b4a4SRafael J. Wysocki 	return pm_autosleep_init();
8201da177e4SLinus Torvalds }
8211da177e4SLinus Torvalds 
8221da177e4SLinus Torvalds core_initcall(pm_init);
823