xref: /linux-6.15/kernel/power/main.c (revision a6d38e99)
155716d26SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * kernel/power/main.c - PM subsystem core functionality.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (c) 2003 Patrick Mochel
61da177e4SLinus Torvalds  * Copyright (c) 2003 Open Source Development Lab
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
9b52124a7SMario Limonciello #include <linux/acpi.h>
106e5fdeedSPaul Gortmaker #include <linux/export.h>
111da177e4SLinus Torvalds #include <linux/kobject.h>
121da177e4SLinus Torvalds #include <linux/string.h>
13431d452aSZhonghui Fu #include <linux/pm-trace.h>
145e928f77SRafael J. Wysocki #include <linux/workqueue.h>
152a77c46dSShuoX Liu #include <linux/debugfs.h>
162a77c46dSShuoX Liu #include <linux/seq_file.h>
1755f2503cSPingfan Liu #include <linux/suspend.h>
18b5dee313SHarry Pan #include <linux/syscalls.h>
19f49249d5SBen Dooks #include <linux/pm_runtime.h>
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds #include "power.h"
221da177e4SLinus Torvalds 
23cd51e61cSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
2407f44ac3SKefeng Wang /*
2507f44ac3SKefeng Wang  * The following functions are used by the suspend/hibernate code to temporarily
2607f44ac3SKefeng Wang  * change gfp_allowed_mask in order to avoid using I/O during memory allocations
2707f44ac3SKefeng Wang  * while devices are suspended.  To avoid races with the suspend/hibernate code,
2807f44ac3SKefeng Wang  * they should always be called with system_transition_mutex held
2907f44ac3SKefeng Wang  * (gfp_allowed_mask also should only be modified with system_transition_mutex
3007f44ac3SKefeng Wang  * held, unless the suspend/hibernate code is guaranteed not to run in parallel
3107f44ac3SKefeng Wang  * with that modification).
3207f44ac3SKefeng Wang  */
3307f44ac3SKefeng Wang static gfp_t saved_gfp_mask;
3407f44ac3SKefeng Wang 
3507f44ac3SKefeng Wang void pm_restore_gfp_mask(void)
3607f44ac3SKefeng Wang {
3707f44ac3SKefeng Wang 	WARN_ON(!mutex_is_locked(&system_transition_mutex));
3807f44ac3SKefeng Wang 	if (saved_gfp_mask) {
3907f44ac3SKefeng Wang 		gfp_allowed_mask = saved_gfp_mask;
4007f44ac3SKefeng Wang 		saved_gfp_mask = 0;
4107f44ac3SKefeng Wang 	}
4207f44ac3SKefeng Wang }
4307f44ac3SKefeng Wang 
4407f44ac3SKefeng Wang void pm_restrict_gfp_mask(void)
4507f44ac3SKefeng Wang {
4607f44ac3SKefeng Wang 	WARN_ON(!mutex_is_locked(&system_transition_mutex));
4707f44ac3SKefeng Wang 	WARN_ON(saved_gfp_mask);
4807f44ac3SKefeng Wang 	saved_gfp_mask = gfp_allowed_mask;
4907f44ac3SKefeng Wang 	gfp_allowed_mask &= ~(__GFP_IO | __GFP_FS);
5007f44ac3SKefeng Wang }
51cd51e61cSRafael J. Wysocki 
525950e5d5SPeter Zijlstra unsigned int lock_system_sleep(void)
534bf236a3SBart Van Assche {
545950e5d5SPeter Zijlstra 	unsigned int flags = current->flags;
55f5d39b02SPeter Zijlstra 	current->flags |= PF_NOFREEZE;
5655f2503cSPingfan Liu 	mutex_lock(&system_transition_mutex);
575950e5d5SPeter Zijlstra 	return flags;
584bf236a3SBart Van Assche }
594bf236a3SBart Van Assche EXPORT_SYMBOL_GPL(lock_system_sleep);
604bf236a3SBart Van Assche 
615950e5d5SPeter Zijlstra void unlock_system_sleep(unsigned int flags)
624bf236a3SBart Van Assche {
63f5d39b02SPeter Zijlstra 	if (!(flags & PF_NOFREEZE))
64f5d39b02SPeter Zijlstra 		current->flags &= ~PF_NOFREEZE;
6555f2503cSPingfan Liu 	mutex_unlock(&system_transition_mutex);
664bf236a3SBart Van Assche }
674bf236a3SBart Van Assche EXPORT_SYMBOL_GPL(unlock_system_sleep);
684bf236a3SBart Van Assche 
69b5dee313SHarry Pan void ksys_sync_helper(void)
70b5dee313SHarry Pan {
71c64546b1SHarry Pan 	ktime_t start;
72c64546b1SHarry Pan 	long elapsed_msecs;
73c64546b1SHarry Pan 
74c64546b1SHarry Pan 	start = ktime_get();
75b5dee313SHarry Pan 	ksys_sync();
76c64546b1SHarry Pan 	elapsed_msecs = ktime_to_ms(ktime_sub(ktime_get(), start));
77c64546b1SHarry Pan 	pr_info("Filesystems sync: %ld.%03ld seconds\n",
78c64546b1SHarry Pan 		elapsed_msecs / MSEC_PER_SEC, elapsed_msecs % MSEC_PER_SEC);
79b5dee313SHarry Pan }
80b5dee313SHarry Pan EXPORT_SYMBOL_GPL(ksys_sync_helper);
81b5dee313SHarry Pan 
8282525756SAlan Stern /* Routines for PM-transition notifications */
8382525756SAlan Stern 
8482525756SAlan Stern static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
8582525756SAlan Stern 
8682525756SAlan Stern int register_pm_notifier(struct notifier_block *nb)
8782525756SAlan Stern {
8882525756SAlan Stern 	return blocking_notifier_chain_register(&pm_chain_head, nb);
8982525756SAlan Stern }
9082525756SAlan Stern EXPORT_SYMBOL_GPL(register_pm_notifier);
9182525756SAlan Stern 
9282525756SAlan Stern int unregister_pm_notifier(struct notifier_block *nb)
9382525756SAlan Stern {
9482525756SAlan Stern 	return blocking_notifier_chain_unregister(&pm_chain_head, nb);
9582525756SAlan Stern }
9682525756SAlan Stern EXPORT_SYMBOL_GPL(unregister_pm_notifier);
9782525756SAlan Stern 
9870d93298SPeter Zijlstra int pm_notifier_call_chain_robust(unsigned long val_up, unsigned long val_down)
9982525756SAlan Stern {
100ea00f4f4SLianwei Wang 	int ret;
101ea00f4f4SLianwei Wang 
10270d93298SPeter Zijlstra 	ret = blocking_notifier_call_chain_robust(&pm_chain_head, val_up, val_down, NULL);
103f0c077a8SAkinobu Mita 
104f0c077a8SAkinobu Mita 	return notifier_to_errno(ret);
10582525756SAlan Stern }
10670d93298SPeter Zijlstra 
107ea00f4f4SLianwei Wang int pm_notifier_call_chain(unsigned long val)
108ea00f4f4SLianwei Wang {
10970d93298SPeter Zijlstra 	return blocking_notifier_call_chain(&pm_chain_head, val, NULL);
110ea00f4f4SLianwei Wang }
11182525756SAlan Stern 
1120e06b4a8SRafael J. Wysocki /* If set, devices may be suspended and resumed asynchronously. */
1130e06b4a8SRafael J. Wysocki int pm_async_enabled = 1;
1140e06b4a8SRafael J. Wysocki 
1150e06b4a8SRafael J. Wysocki static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
1160e06b4a8SRafael J. Wysocki 			     char *buf)
1170e06b4a8SRafael J. Wysocki {
1180e06b4a8SRafael J. Wysocki 	return sprintf(buf, "%d\n", pm_async_enabled);
1190e06b4a8SRafael J. Wysocki }
1200e06b4a8SRafael J. Wysocki 
1210e06b4a8SRafael J. Wysocki static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
1220e06b4a8SRafael J. Wysocki 			      const char *buf, size_t n)
1230e06b4a8SRafael J. Wysocki {
1240e06b4a8SRafael J. Wysocki 	unsigned long val;
1250e06b4a8SRafael J. Wysocki 
126883ee4f7SDaniel Walter 	if (kstrtoul(buf, 10, &val))
1270e06b4a8SRafael J. Wysocki 		return -EINVAL;
1280e06b4a8SRafael J. Wysocki 
1290e06b4a8SRafael J. Wysocki 	if (val > 1)
1300e06b4a8SRafael J. Wysocki 		return -EINVAL;
1310e06b4a8SRafael J. Wysocki 
1320e06b4a8SRafael J. Wysocki 	pm_async_enabled = val;
1330e06b4a8SRafael J. Wysocki 	return n;
1340e06b4a8SRafael J. Wysocki }
1350e06b4a8SRafael J. Wysocki 
1360e06b4a8SRafael J. Wysocki power_attr(pm_async);
1370e06b4a8SRafael J. Wysocki 
138406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND
139406e7938SRafael J. Wysocki static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr,
140406e7938SRafael J. Wysocki 			      char *buf)
141406e7938SRafael J. Wysocki {
142406e7938SRafael J. Wysocki 	char *s = buf;
143406e7938SRafael J. Wysocki 	suspend_state_t i;
144406e7938SRafael J. Wysocki 
1459ea4dcf4SDan Williams 	for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) {
1469ea4dcf4SDan Williams 		if (i >= PM_SUSPEND_MEM && cxl_mem_active())
1479ea4dcf4SDan Williams 			continue;
148406e7938SRafael J. Wysocki 		if (mem_sleep_states[i]) {
149406e7938SRafael J. Wysocki 			const char *label = mem_sleep_states[i];
150406e7938SRafael J. Wysocki 
151406e7938SRafael J. Wysocki 			if (mem_sleep_current == i)
152406e7938SRafael J. Wysocki 				s += sprintf(s, "[%s] ", label);
153406e7938SRafael J. Wysocki 			else
154406e7938SRafael J. Wysocki 				s += sprintf(s, "%s ", label);
155406e7938SRafael J. Wysocki 		}
1569ea4dcf4SDan Williams 	}
157406e7938SRafael J. Wysocki 
158406e7938SRafael J. Wysocki 	/* Convert the last space to a newline if needed. */
159406e7938SRafael J. Wysocki 	if (s != buf)
160406e7938SRafael J. Wysocki 		*(s-1) = '\n';
161406e7938SRafael J. Wysocki 
162406e7938SRafael J. Wysocki 	return (s - buf);
163406e7938SRafael J. Wysocki }
164406e7938SRafael J. Wysocki 
165406e7938SRafael J. Wysocki static suspend_state_t decode_suspend_state(const char *buf, size_t n)
166406e7938SRafael J. Wysocki {
167406e7938SRafael J. Wysocki 	suspend_state_t state;
168406e7938SRafael J. Wysocki 	char *p;
169406e7938SRafael J. Wysocki 	int len;
170406e7938SRafael J. Wysocki 
171406e7938SRafael J. Wysocki 	p = memchr(buf, '\n', n);
172406e7938SRafael J. Wysocki 	len = p ? p - buf : n;
173406e7938SRafael J. Wysocki 
174406e7938SRafael J. Wysocki 	for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) {
175406e7938SRafael J. Wysocki 		const char *label = mem_sleep_states[state];
176406e7938SRafael J. Wysocki 
177406e7938SRafael J. Wysocki 		if (label && len == strlen(label) && !strncmp(buf, label, len))
178406e7938SRafael J. Wysocki 			return state;
179406e7938SRafael J. Wysocki 	}
180406e7938SRafael J. Wysocki 
181406e7938SRafael J. Wysocki 	return PM_SUSPEND_ON;
182406e7938SRafael J. Wysocki }
183406e7938SRafael J. Wysocki 
184406e7938SRafael J. Wysocki static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr,
185406e7938SRafael J. Wysocki 			       const char *buf, size_t n)
186406e7938SRafael J. Wysocki {
187406e7938SRafael J. Wysocki 	suspend_state_t state;
188406e7938SRafael J. Wysocki 	int error;
189406e7938SRafael J. Wysocki 
190406e7938SRafael J. Wysocki 	error = pm_autosleep_lock();
191406e7938SRafael J. Wysocki 	if (error)
192406e7938SRafael J. Wysocki 		return error;
193406e7938SRafael J. Wysocki 
194406e7938SRafael J. Wysocki 	if (pm_autosleep_state() > PM_SUSPEND_ON) {
195406e7938SRafael J. Wysocki 		error = -EBUSY;
196406e7938SRafael J. Wysocki 		goto out;
197406e7938SRafael J. Wysocki 	}
198406e7938SRafael J. Wysocki 
199406e7938SRafael J. Wysocki 	state = decode_suspend_state(buf, n);
200406e7938SRafael J. Wysocki 	if (state < PM_SUSPEND_MAX && state > PM_SUSPEND_ON)
201406e7938SRafael J. Wysocki 		mem_sleep_current = state;
202406e7938SRafael J. Wysocki 	else
203406e7938SRafael J. Wysocki 		error = -EINVAL;
204406e7938SRafael J. Wysocki 
205406e7938SRafael J. Wysocki  out:
206406e7938SRafael J. Wysocki 	pm_autosleep_unlock();
207406e7938SRafael J. Wysocki 	return error ? error : n;
208406e7938SRafael J. Wysocki }
209406e7938SRafael J. Wysocki 
210406e7938SRafael J. Wysocki power_attr(mem_sleep);
211c052bf82SJonas Meurer 
212c052bf82SJonas Meurer /*
213c052bf82SJonas Meurer  * sync_on_suspend: invoke ksys_sync_helper() before suspend.
214c052bf82SJonas Meurer  *
215c052bf82SJonas Meurer  * show() returns whether ksys_sync_helper() is invoked before suspend.
216c052bf82SJonas Meurer  * store() accepts 0 or 1.  0 disables ksys_sync_helper() and 1 enables it.
217c052bf82SJonas Meurer  */
218c052bf82SJonas Meurer bool sync_on_suspend_enabled = !IS_ENABLED(CONFIG_SUSPEND_SKIP_SYNC);
219c052bf82SJonas Meurer 
220c052bf82SJonas Meurer static ssize_t sync_on_suspend_show(struct kobject *kobj,
221c052bf82SJonas Meurer 				   struct kobj_attribute *attr, char *buf)
222c052bf82SJonas Meurer {
223c052bf82SJonas Meurer 	return sprintf(buf, "%d\n", sync_on_suspend_enabled);
224c052bf82SJonas Meurer }
225c052bf82SJonas Meurer 
226c052bf82SJonas Meurer static ssize_t sync_on_suspend_store(struct kobject *kobj,
227c052bf82SJonas Meurer 				    struct kobj_attribute *attr,
228c052bf82SJonas Meurer 				    const char *buf, size_t n)
229c052bf82SJonas Meurer {
230c052bf82SJonas Meurer 	unsigned long val;
231c052bf82SJonas Meurer 
232c052bf82SJonas Meurer 	if (kstrtoul(buf, 10, &val))
233c052bf82SJonas Meurer 		return -EINVAL;
234c052bf82SJonas Meurer 
235c052bf82SJonas Meurer 	if (val > 1)
236c052bf82SJonas Meurer 		return -EINVAL;
237c052bf82SJonas Meurer 
238c052bf82SJonas Meurer 	sync_on_suspend_enabled = !!val;
239c052bf82SJonas Meurer 	return n;
240c052bf82SJonas Meurer }
241c052bf82SJonas Meurer 
242c052bf82SJonas Meurer power_attr(sync_on_suspend);
243406e7938SRafael J. Wysocki #endif /* CONFIG_SUSPEND */
244406e7938SRafael J. Wysocki 
245e516a1dbSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG
2460e7d56e3SRafael J. Wysocki int pm_test_level = TEST_NONE;
2470e7d56e3SRafael J. Wysocki 
2480e7d56e3SRafael J. Wysocki static const char * const pm_tests[__TEST_AFTER_LAST] = {
2490e7d56e3SRafael J. Wysocki 	[TEST_NONE] = "none",
2500e7d56e3SRafael J. Wysocki 	[TEST_CORE] = "core",
2510e7d56e3SRafael J. Wysocki 	[TEST_CPUS] = "processors",
2520e7d56e3SRafael J. Wysocki 	[TEST_PLATFORM] = "platform",
2530e7d56e3SRafael J. Wysocki 	[TEST_DEVICES] = "devices",
2540e7d56e3SRafael J. Wysocki 	[TEST_FREEZER] = "freezer",
2550e7d56e3SRafael J. Wysocki };
2560e7d56e3SRafael J. Wysocki 
257039a75c6SRafael J. Wysocki static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
258039a75c6SRafael J. Wysocki 				char *buf)
2590e7d56e3SRafael J. Wysocki {
2600e7d56e3SRafael J. Wysocki 	char *s = buf;
2610e7d56e3SRafael J. Wysocki 	int level;
2620e7d56e3SRafael J. Wysocki 
2630e7d56e3SRafael J. Wysocki 	for (level = TEST_FIRST; level <= TEST_MAX; level++)
2640e7d56e3SRafael J. Wysocki 		if (pm_tests[level]) {
2650e7d56e3SRafael J. Wysocki 			if (level == pm_test_level)
2660e7d56e3SRafael J. Wysocki 				s += sprintf(s, "[%s] ", pm_tests[level]);
2670e7d56e3SRafael J. Wysocki 			else
2680e7d56e3SRafael J. Wysocki 				s += sprintf(s, "%s ", pm_tests[level]);
2690e7d56e3SRafael J. Wysocki 		}
2700e7d56e3SRafael J. Wysocki 
2710e7d56e3SRafael J. Wysocki 	if (s != buf)
2720e7d56e3SRafael J. Wysocki 		/* convert the last space to a newline */
2730e7d56e3SRafael J. Wysocki 		*(s-1) = '\n';
2740e7d56e3SRafael J. Wysocki 
2750e7d56e3SRafael J. Wysocki 	return (s - buf);
2760e7d56e3SRafael J. Wysocki }
2770e7d56e3SRafael J. Wysocki 
278039a75c6SRafael J. Wysocki static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
279039a75c6SRafael J. Wysocki 				const char *buf, size_t n)
2800e7d56e3SRafael J. Wysocki {
2815950e5d5SPeter Zijlstra 	unsigned int sleep_flags;
2820e7d56e3SRafael J. Wysocki 	const char * const *s;
2835950e5d5SPeter Zijlstra 	int error = -EINVAL;
2840e7d56e3SRafael J. Wysocki 	int level;
2850e7d56e3SRafael J. Wysocki 	char *p;
2860e7d56e3SRafael J. Wysocki 	int len;
2870e7d56e3SRafael J. Wysocki 
2880e7d56e3SRafael J. Wysocki 	p = memchr(buf, '\n', n);
2890e7d56e3SRafael J. Wysocki 	len = p ? p - buf : n;
2900e7d56e3SRafael J. Wysocki 
2915950e5d5SPeter Zijlstra 	sleep_flags = lock_system_sleep();
2920e7d56e3SRafael J. Wysocki 
2930e7d56e3SRafael J. Wysocki 	level = TEST_FIRST;
2940e7d56e3SRafael J. Wysocki 	for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
2950e7d56e3SRafael J. Wysocki 		if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
2960e7d56e3SRafael J. Wysocki 			pm_test_level = level;
2970e7d56e3SRafael J. Wysocki 			error = 0;
2980e7d56e3SRafael J. Wysocki 			break;
2990e7d56e3SRafael J. Wysocki 		}
3000e7d56e3SRafael J. Wysocki 
3015950e5d5SPeter Zijlstra 	unlock_system_sleep(sleep_flags);
3020e7d56e3SRafael J. Wysocki 
3030e7d56e3SRafael J. Wysocki 	return error ? error : n;
3040e7d56e3SRafael J. Wysocki }
3050e7d56e3SRafael J. Wysocki 
3060e7d56e3SRafael J. Wysocki power_attr(pm_test);
307e516a1dbSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */
3080e7d56e3SRafael J. Wysocki 
3099ff544faSRafael J. Wysocki #define SUSPEND_NR_STEPS	SUSPEND_RESUME
3109ff544faSRafael J. Wysocki #define REC_FAILED_NUM		2
3119ff544faSRafael J. Wysocki 
3129ff544faSRafael J. Wysocki struct suspend_stats {
3139ff544faSRafael J. Wysocki 	unsigned int step_failures[SUSPEND_NR_STEPS];
3149ff544faSRafael J. Wysocki 	unsigned int success;
3159ff544faSRafael J. Wysocki 	unsigned int fail;
3169ff544faSRafael J. Wysocki 	int last_failed_dev;
3179ff544faSRafael J. Wysocki 	char failed_devs[REC_FAILED_NUM][40];
3189ff544faSRafael J. Wysocki 	int last_failed_errno;
3199ff544faSRafael J. Wysocki 	int errno[REC_FAILED_NUM];
3209ff544faSRafael J. Wysocki 	int last_failed_step;
3219ff544faSRafael J. Wysocki 	u64 last_hw_sleep;
3229ff544faSRafael J. Wysocki 	u64 total_hw_sleep;
3239ff544faSRafael J. Wysocki 	u64 max_hw_sleep;
3249ff544faSRafael J. Wysocki 	enum suspend_stat_step failed_steps[REC_FAILED_NUM];
3259ff544faSRafael J. Wysocki };
3269ff544faSRafael J. Wysocki 
3279ff544faSRafael J. Wysocki static struct suspend_stats suspend_stats;
328*a6d38e99SRafael J. Wysocki static DEFINE_MUTEX(suspend_stats_lock);
3299ff544faSRafael J. Wysocki 
3309ff544faSRafael J. Wysocki void dpm_save_failed_dev(const char *name)
3319ff544faSRafael J. Wysocki {
332*a6d38e99SRafael J. Wysocki 	mutex_lock(&suspend_stats_lock);
333*a6d38e99SRafael J. Wysocki 
3349ff544faSRafael J. Wysocki 	strscpy(suspend_stats.failed_devs[suspend_stats.last_failed_dev],
3359ff544faSRafael J. Wysocki 		name, sizeof(suspend_stats.failed_devs[0]));
3369ff544faSRafael J. Wysocki 	suspend_stats.last_failed_dev++;
3379ff544faSRafael J. Wysocki 	suspend_stats.last_failed_dev %= REC_FAILED_NUM;
338*a6d38e99SRafael J. Wysocki 
339*a6d38e99SRafael J. Wysocki 	mutex_unlock(&suspend_stats_lock);
3409ff544faSRafael J. Wysocki }
3419ff544faSRafael J. Wysocki 
3429ff544faSRafael J. Wysocki void dpm_save_failed_step(enum suspend_stat_step step)
3439ff544faSRafael J. Wysocki {
3449ff544faSRafael J. Wysocki 	suspend_stats.step_failures[step-1]++;
3459ff544faSRafael J. Wysocki 	suspend_stats.failed_steps[suspend_stats.last_failed_step] = step;
3469ff544faSRafael J. Wysocki 	suspend_stats.last_failed_step++;
3479ff544faSRafael J. Wysocki 	suspend_stats.last_failed_step %= REC_FAILED_NUM;
3489ff544faSRafael J. Wysocki }
3499ff544faSRafael J. Wysocki 
3509ff544faSRafael J. Wysocki void dpm_save_errno(int err)
3519ff544faSRafael J. Wysocki {
3529ff544faSRafael J. Wysocki 	if (!err) {
3539ff544faSRafael J. Wysocki 		suspend_stats.success++;
3549ff544faSRafael J. Wysocki 		return;
3559ff544faSRafael J. Wysocki 	}
3569ff544faSRafael J. Wysocki 
3579ff544faSRafael J. Wysocki 	suspend_stats.fail++;
3589ff544faSRafael J. Wysocki 
3599ff544faSRafael J. Wysocki 	suspend_stats.errno[suspend_stats.last_failed_errno] = err;
3609ff544faSRafael J. Wysocki 	suspend_stats.last_failed_errno++;
3619ff544faSRafael J. Wysocki 	suspend_stats.last_failed_errno %= REC_FAILED_NUM;
3629ff544faSRafael J. Wysocki }
3639ff544faSRafael J. Wysocki 
3649ff544faSRafael J. Wysocki void pm_report_hw_sleep_time(u64 t)
3659ff544faSRafael J. Wysocki {
3669ff544faSRafael J. Wysocki 	suspend_stats.last_hw_sleep = t;
3679ff544faSRafael J. Wysocki 	suspend_stats.total_hw_sleep += t;
3689ff544faSRafael J. Wysocki }
3699ff544faSRafael J. Wysocki EXPORT_SYMBOL_GPL(pm_report_hw_sleep_time);
3709ff544faSRafael J. Wysocki 
3719ff544faSRafael J. Wysocki void pm_report_max_hw_sleep(u64 t)
3729ff544faSRafael J. Wysocki {
3739ff544faSRafael J. Wysocki 	suspend_stats.max_hw_sleep = t;
3749ff544faSRafael J. Wysocki }
3759ff544faSRafael J. Wysocki EXPORT_SYMBOL_GPL(pm_report_max_hw_sleep);
3769ff544faSRafael J. Wysocki 
377bc88528cSRafael J. Wysocki static const char * const suspend_step_names[] = {
378bc88528cSRafael J. Wysocki 	[SUSPEND_WORKING] = "",
379bc88528cSRafael J. Wysocki 	[SUSPEND_FREEZE] = "freeze",
380bc88528cSRafael J. Wysocki 	[SUSPEND_PREPARE] = "prepare",
381bc88528cSRafael J. Wysocki 	[SUSPEND_SUSPEND] = "suspend",
382bc88528cSRafael J. Wysocki 	[SUSPEND_SUSPEND_LATE] = "suspend_late",
383bc88528cSRafael J. Wysocki 	[SUSPEND_SUSPEND_NOIRQ] = "suspend_noirq",
384bc88528cSRafael J. Wysocki 	[SUSPEND_RESUME_NOIRQ] = "resume_noirq",
385bc88528cSRafael J. Wysocki 	[SUSPEND_RESUME_EARLY] = "resume_early",
386bc88528cSRafael J. Wysocki 	[SUSPEND_RESUME] = "resume",
387bc88528cSRafael J. Wysocki };
3882a77c46dSShuoX Liu 
389b52124a7SMario Limonciello #define suspend_attr(_name, format_str)				\
3902c8db5beSKalesh Singh static ssize_t _name##_show(struct kobject *kobj,		\
3912c8db5beSKalesh Singh 		struct kobj_attribute *attr, char *buf)		\
3922c8db5beSKalesh Singh {								\
393b52124a7SMario Limonciello 	return sprintf(buf, format_str, suspend_stats._name);	\
3942c8db5beSKalesh Singh }								\
3952c8db5beSKalesh Singh static struct kobj_attribute _name = __ATTR_RO(_name)
3962c8db5beSKalesh Singh 
3972231f78dSRafael J. Wysocki suspend_attr(success, "%u\n");
3982231f78dSRafael J. Wysocki suspend_attr(fail, "%u\n");
399b52124a7SMario Limonciello suspend_attr(last_hw_sleep, "%llu\n");
400b52124a7SMario Limonciello suspend_attr(total_hw_sleep, "%llu\n");
401b52124a7SMario Limonciello suspend_attr(max_hw_sleep, "%llu\n");
4022c8db5beSKalesh Singh 
403b730bab0SRafael J. Wysocki #define suspend_step_attr(_name, step)		\
404b730bab0SRafael J. Wysocki static ssize_t _name##_show(struct kobject *kobj,		\
405b730bab0SRafael J. Wysocki 		struct kobj_attribute *attr, char *buf)		\
406b730bab0SRafael J. Wysocki {								\
407b730bab0SRafael J. Wysocki 	return sprintf(buf, "%u\n",				\
408b730bab0SRafael J. Wysocki 		       suspend_stats.step_failures[step-1]);	\
409b730bab0SRafael J. Wysocki }								\
410b730bab0SRafael J. Wysocki static struct kobj_attribute _name = __ATTR_RO(_name)
411b730bab0SRafael J. Wysocki 
412b730bab0SRafael J. Wysocki suspend_step_attr(failed_freeze, SUSPEND_FREEZE);
413b730bab0SRafael J. Wysocki suspend_step_attr(failed_prepare, SUSPEND_PREPARE);
414b730bab0SRafael J. Wysocki suspend_step_attr(failed_suspend, SUSPEND_SUSPEND);
415b730bab0SRafael J. Wysocki suspend_step_attr(failed_suspend_late, SUSPEND_SUSPEND_LATE);
416b730bab0SRafael J. Wysocki suspend_step_attr(failed_suspend_noirq, SUSPEND_SUSPEND_NOIRQ);
417b730bab0SRafael J. Wysocki suspend_step_attr(failed_resume, SUSPEND_RESUME);
418b730bab0SRafael J. Wysocki suspend_step_attr(failed_resume_early, SUSPEND_RESUME_EARLY);
419b730bab0SRafael J. Wysocki suspend_step_attr(failed_resume_noirq, SUSPEND_RESUME_NOIRQ);
420b730bab0SRafael J. Wysocki 
4212c8db5beSKalesh Singh static ssize_t last_failed_dev_show(struct kobject *kobj,
4222c8db5beSKalesh Singh 		struct kobj_attribute *attr, char *buf)
4232c8db5beSKalesh Singh {
4242c8db5beSKalesh Singh 	int index;
4252c8db5beSKalesh Singh 	char *last_failed_dev = NULL;
4262c8db5beSKalesh Singh 
4272c8db5beSKalesh Singh 	index = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
4282c8db5beSKalesh Singh 	index %= REC_FAILED_NUM;
4292c8db5beSKalesh Singh 	last_failed_dev = suspend_stats.failed_devs[index];
4302c8db5beSKalesh Singh 
4312c8db5beSKalesh Singh 	return sprintf(buf, "%s\n", last_failed_dev);
4322c8db5beSKalesh Singh }
4332c8db5beSKalesh Singh static struct kobj_attribute last_failed_dev = __ATTR_RO(last_failed_dev);
4342c8db5beSKalesh Singh 
4352c8db5beSKalesh Singh static ssize_t last_failed_errno_show(struct kobject *kobj,
4362c8db5beSKalesh Singh 		struct kobj_attribute *attr, char *buf)
4372c8db5beSKalesh Singh {
4382c8db5beSKalesh Singh 	int index;
4392c8db5beSKalesh Singh 	int last_failed_errno;
4402c8db5beSKalesh Singh 
4412c8db5beSKalesh Singh 	index = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1;
4422c8db5beSKalesh Singh 	index %= REC_FAILED_NUM;
4432c8db5beSKalesh Singh 	last_failed_errno = suspend_stats.errno[index];
4442c8db5beSKalesh Singh 
4452c8db5beSKalesh Singh 	return sprintf(buf, "%d\n", last_failed_errno);
4462c8db5beSKalesh Singh }
4472c8db5beSKalesh Singh static struct kobj_attribute last_failed_errno = __ATTR_RO(last_failed_errno);
4482c8db5beSKalesh Singh 
4492c8db5beSKalesh Singh static ssize_t last_failed_step_show(struct kobject *kobj,
4502c8db5beSKalesh Singh 		struct kobj_attribute *attr, char *buf)
4512c8db5beSKalesh Singh {
4522c8db5beSKalesh Singh 	enum suspend_stat_step step;
453bc88528cSRafael J. Wysocki 	int index;
4542c8db5beSKalesh Singh 
4552c8db5beSKalesh Singh 	index = suspend_stats.last_failed_step + REC_FAILED_NUM - 1;
4562c8db5beSKalesh Singh 	index %= REC_FAILED_NUM;
4572c8db5beSKalesh Singh 	step = suspend_stats.failed_steps[index];
4582c8db5beSKalesh Singh 
459bc88528cSRafael J. Wysocki 	return sprintf(buf, "%s\n", suspend_step_names[step]);
4602c8db5beSKalesh Singh }
4612c8db5beSKalesh Singh static struct kobj_attribute last_failed_step = __ATTR_RO(last_failed_step);
4622c8db5beSKalesh Singh 
4632c8db5beSKalesh Singh static struct attribute *suspend_attrs[] = {
4642c8db5beSKalesh Singh 	&success.attr,
4652c8db5beSKalesh Singh 	&fail.attr,
4662c8db5beSKalesh Singh 	&failed_freeze.attr,
4672c8db5beSKalesh Singh 	&failed_prepare.attr,
4682c8db5beSKalesh Singh 	&failed_suspend.attr,
4692c8db5beSKalesh Singh 	&failed_suspend_late.attr,
4702c8db5beSKalesh Singh 	&failed_suspend_noirq.attr,
4712c8db5beSKalesh Singh 	&failed_resume.attr,
4722c8db5beSKalesh Singh 	&failed_resume_early.attr,
4732c8db5beSKalesh Singh 	&failed_resume_noirq.attr,
4742c8db5beSKalesh Singh 	&last_failed_dev.attr,
4752c8db5beSKalesh Singh 	&last_failed_errno.attr,
4762c8db5beSKalesh Singh 	&last_failed_step.attr,
477b52124a7SMario Limonciello 	&last_hw_sleep.attr,
478b52124a7SMario Limonciello 	&total_hw_sleep.attr,
479b52124a7SMario Limonciello 	&max_hw_sleep.attr,
4802c8db5beSKalesh Singh 	NULL,
4812c8db5beSKalesh Singh };
4822c8db5beSKalesh Singh 
483b52124a7SMario Limonciello static umode_t suspend_attr_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
484b52124a7SMario Limonciello {
485b52124a7SMario Limonciello 	if (attr != &last_hw_sleep.attr &&
486b52124a7SMario Limonciello 	    attr != &total_hw_sleep.attr &&
487b52124a7SMario Limonciello 	    attr != &max_hw_sleep.attr)
488b52124a7SMario Limonciello 		return 0444;
489b52124a7SMario Limonciello 
490b52124a7SMario Limonciello #ifdef CONFIG_ACPI
491b52124a7SMario Limonciello 	if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)
492b52124a7SMario Limonciello 		return 0444;
493b52124a7SMario Limonciello #endif
494b52124a7SMario Limonciello 	return 0;
495b52124a7SMario Limonciello }
496b52124a7SMario Limonciello 
49715560574SRikard Falkeborn static const struct attribute_group suspend_attr_group = {
4982c8db5beSKalesh Singh 	.name = "suspend_stats",
4992c8db5beSKalesh Singh 	.attrs = suspend_attrs,
500b52124a7SMario Limonciello 	.is_visible = suspend_attr_is_visible,
5012c8db5beSKalesh Singh };
5022c8db5beSKalesh Singh 
5032c8db5beSKalesh Singh #ifdef CONFIG_DEBUG_FS
5042a77c46dSShuoX Liu static int suspend_stats_show(struct seq_file *s, void *unused)
5052a77c46dSShuoX Liu {
5062a77c46dSShuoX Liu 	int i, index, last_dev, last_errno, last_step;
507b730bab0SRafael J. Wysocki 	enum suspend_stat_step step;
5082a77c46dSShuoX Liu 
5092a77c46dSShuoX Liu 	last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
5102a77c46dSShuoX Liu 	last_dev %= REC_FAILED_NUM;
5112a77c46dSShuoX Liu 	last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1;
5122a77c46dSShuoX Liu 	last_errno %= REC_FAILED_NUM;
5132a77c46dSShuoX Liu 	last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1;
5142a77c46dSShuoX Liu 	last_step %= REC_FAILED_NUM;
515b730bab0SRafael J. Wysocki 
5162231f78dSRafael J. Wysocki 	seq_printf(s, "success: %u\nfail: %u\n",
517b730bab0SRafael J. Wysocki 		   suspend_stats.success, suspend_stats.fail);
518b730bab0SRafael J. Wysocki 
519b730bab0SRafael J. Wysocki 	for (step = SUSPEND_FREEZE; step <= SUSPEND_NR_STEPS; step++)
520b730bab0SRafael J. Wysocki 		seq_printf(s, "failed_%s: %u\n", suspend_step_names[step],
521b730bab0SRafael J. Wysocki 			   suspend_stats.step_failures[step-1]);
522b730bab0SRafael J. Wysocki 
5232a77c46dSShuoX Liu 	seq_printf(s,	"failures:\n  last_failed_dev:\t%-s\n",
5242a77c46dSShuoX Liu 		   suspend_stats.failed_devs[last_dev]);
5252a77c46dSShuoX Liu 	for (i = 1; i < REC_FAILED_NUM; i++) {
5262a77c46dSShuoX Liu 		index = last_dev + REC_FAILED_NUM - i;
5272a77c46dSShuoX Liu 		index %= REC_FAILED_NUM;
528bc88528cSRafael J. Wysocki 		seq_printf(s, "\t\t\t%-s\n", suspend_stats.failed_devs[index]);
5292a77c46dSShuoX Liu 	}
5302a77c46dSShuoX Liu 	seq_printf(s,	"  last_failed_errno:\t%-d\n",
5312a77c46dSShuoX Liu 			suspend_stats.errno[last_errno]);
5322a77c46dSShuoX Liu 	for (i = 1; i < REC_FAILED_NUM; i++) {
5332a77c46dSShuoX Liu 		index = last_errno + REC_FAILED_NUM - i;
5342a77c46dSShuoX Liu 		index %= REC_FAILED_NUM;
535bc88528cSRafael J. Wysocki 		seq_printf(s, "\t\t\t%-d\n", suspend_stats.errno[index]);
5362a77c46dSShuoX Liu 	}
5372a77c46dSShuoX Liu 	seq_printf(s,	"  last_failed_step:\t%-s\n",
538bc88528cSRafael J. Wysocki 		   suspend_step_names[suspend_stats.failed_steps[last_step]]);
5392a77c46dSShuoX Liu 	for (i = 1; i < REC_FAILED_NUM; i++) {
5402a77c46dSShuoX Liu 		index = last_step + REC_FAILED_NUM - i;
5412a77c46dSShuoX Liu 		index %= REC_FAILED_NUM;
5422a77c46dSShuoX Liu 		seq_printf(s, "\t\t\t%-s\n",
543bc88528cSRafael J. Wysocki 			   suspend_step_names[suspend_stats.failed_steps[index]]);
5442a77c46dSShuoX Liu 	}
5452a77c46dSShuoX Liu 
5462a77c46dSShuoX Liu 	return 0;
5472a77c46dSShuoX Liu }
548943a10f8SYangtao Li DEFINE_SHOW_ATTRIBUTE(suspend_stats);
5492a77c46dSShuoX Liu 
5502a77c46dSShuoX Liu static int __init pm_debugfs_init(void)
5512a77c46dSShuoX Liu {
5522a77c46dSShuoX Liu 	debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO,
553943a10f8SYangtao Li 			NULL, NULL, &suspend_stats_fops);
5542a77c46dSShuoX Liu 	return 0;
5552a77c46dSShuoX Liu }
5562a77c46dSShuoX Liu 
5572a77c46dSShuoX Liu late_initcall(pm_debugfs_init);
5582a77c46dSShuoX Liu #endif /* CONFIG_DEBUG_FS */
5592a77c46dSShuoX Liu 
560ca123102SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */
561ca123102SRafael J. Wysocki 
562b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG
563b2df1d4fSRafael J. Wysocki /*
564b2df1d4fSRafael J. Wysocki  * pm_print_times: print time taken by devices to suspend and resume.
565b2df1d4fSRafael J. Wysocki  *
566b2df1d4fSRafael J. Wysocki  * show() returns whether printing of suspend and resume times is enabled.
567b2df1d4fSRafael J. Wysocki  * store() accepts 0 or 1.  0 disables printing and 1 enables it.
568b2df1d4fSRafael J. Wysocki  */
569b2df1d4fSRafael J. Wysocki bool pm_print_times_enabled;
570b2df1d4fSRafael J. Wysocki 
571b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_show(struct kobject *kobj,
572b2df1d4fSRafael J. Wysocki 				   struct kobj_attribute *attr, char *buf)
573b2df1d4fSRafael J. Wysocki {
574b2df1d4fSRafael J. Wysocki 	return sprintf(buf, "%d\n", pm_print_times_enabled);
575b2df1d4fSRafael J. Wysocki }
576b2df1d4fSRafael J. Wysocki 
577b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_store(struct kobject *kobj,
578b2df1d4fSRafael J. Wysocki 				    struct kobj_attribute *attr,
579b2df1d4fSRafael J. Wysocki 				    const char *buf, size_t n)
580b2df1d4fSRafael J. Wysocki {
581b2df1d4fSRafael J. Wysocki 	unsigned long val;
582b2df1d4fSRafael J. Wysocki 
583b2df1d4fSRafael J. Wysocki 	if (kstrtoul(buf, 10, &val))
584b2df1d4fSRafael J. Wysocki 		return -EINVAL;
585b2df1d4fSRafael J. Wysocki 
586b2df1d4fSRafael J. Wysocki 	if (val > 1)
587b2df1d4fSRafael J. Wysocki 		return -EINVAL;
588b2df1d4fSRafael J. Wysocki 
589b2df1d4fSRafael J. Wysocki 	pm_print_times_enabled = !!val;
590b2df1d4fSRafael J. Wysocki 	return n;
591b2df1d4fSRafael J. Wysocki }
592b2df1d4fSRafael J. Wysocki 
593b2df1d4fSRafael J. Wysocki power_attr(pm_print_times);
594b2df1d4fSRafael J. Wysocki 
595b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void)
596b2df1d4fSRafael J. Wysocki {
597b2df1d4fSRafael J. Wysocki 	pm_print_times_enabled = !!initcall_debug;
598b2df1d4fSRafael J. Wysocki }
599a6f5f0ddSAlexandra Yates 
600a6f5f0ddSAlexandra Yates static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
601a6f5f0ddSAlexandra Yates 					struct kobj_attribute *attr,
602a6f5f0ddSAlexandra Yates 					char *buf)
603a6f5f0ddSAlexandra Yates {
604cb1f65c1SRafael J. Wysocki 	if (!pm_wakeup_irq())
605cb1f65c1SRafael J. Wysocki 		return -ENODATA;
606cb1f65c1SRafael J. Wysocki 
607cb1f65c1SRafael J. Wysocki 	return sprintf(buf, "%u\n", pm_wakeup_irq());
608a6f5f0ddSAlexandra Yates }
609a6f5f0ddSAlexandra Yates 
610a1e9ca69SRafael J. Wysocki power_attr_ro(pm_wakeup_irq);
611a6f5f0ddSAlexandra Yates 
612726fb6b4SSrinivas Pandruvada bool pm_debug_messages_on __read_mostly;
6138d8b2441SRafael J. Wysocki 
614cdb8c100SMario Limonciello bool pm_debug_messages_should_print(void)
615cdb8c100SMario Limonciello {
616cdb8c100SMario Limonciello 	return pm_debug_messages_on && pm_suspend_target_state != PM_SUSPEND_ON;
617cdb8c100SMario Limonciello }
618cdb8c100SMario Limonciello EXPORT_SYMBOL_GPL(pm_debug_messages_should_print);
619cdb8c100SMario Limonciello 
6208d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_show(struct kobject *kobj,
6218d8b2441SRafael J. Wysocki 				      struct kobj_attribute *attr, char *buf)
6228d8b2441SRafael J. Wysocki {
6238d8b2441SRafael J. Wysocki 	return sprintf(buf, "%d\n", pm_debug_messages_on);
6248d8b2441SRafael J. Wysocki }
6258d8b2441SRafael J. Wysocki 
6268d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_store(struct kobject *kobj,
6278d8b2441SRafael J. Wysocki 				       struct kobj_attribute *attr,
6288d8b2441SRafael J. Wysocki 				       const char *buf, size_t n)
6298d8b2441SRafael J. Wysocki {
6308d8b2441SRafael J. Wysocki 	unsigned long val;
6318d8b2441SRafael J. Wysocki 
6328d8b2441SRafael J. Wysocki 	if (kstrtoul(buf, 10, &val))
6338d8b2441SRafael J. Wysocki 		return -EINVAL;
6348d8b2441SRafael J. Wysocki 
6358d8b2441SRafael J. Wysocki 	if (val > 1)
6368d8b2441SRafael J. Wysocki 		return -EINVAL;
6378d8b2441SRafael J. Wysocki 
6388d8b2441SRafael J. Wysocki 	pm_debug_messages_on = !!val;
6398d8b2441SRafael J. Wysocki 	return n;
6408d8b2441SRafael J. Wysocki }
6418d8b2441SRafael J. Wysocki 
6428d8b2441SRafael J. Wysocki power_attr(pm_debug_messages);
6438d8b2441SRafael J. Wysocki 
644db96a759SChen Yu static int __init pm_debug_messages_setup(char *str)
645db96a759SChen Yu {
646db96a759SChen Yu 	pm_debug_messages_on = true;
647db96a759SChen Yu 	return 1;
648db96a759SChen Yu }
649db96a759SChen Yu __setup("pm_debug_messages", pm_debug_messages_setup);
650db96a759SChen Yu 
651819b1bb3SRafael J. Wysocki #else /* !CONFIG_PM_SLEEP_DEBUG */
652b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) {}
653b2df1d4fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */
654b2df1d4fSRafael J. Wysocki 
655d76e15fbSGreg Kroah-Hartman struct kobject *power_kobj;
6561da177e4SLinus Torvalds 
657dbcfa715SRandy Dunlap /*
6580399d4dbSRafael J. Wysocki  * state - control system sleep states.
6591da177e4SLinus Torvalds  *
6600399d4dbSRafael J. Wysocki  * show() returns available sleep state labels, which may be "mem", "standby",
66144348e8aSMauro Carvalho Chehab  * "freeze" and "disk" (hibernation).
66244348e8aSMauro Carvalho Chehab  * See Documentation/admin-guide/pm/sleep-states.rst for a description of
66344348e8aSMauro Carvalho Chehab  * what they mean.
6641da177e4SLinus Torvalds  *
6650399d4dbSRafael J. Wysocki  * store() accepts one of those strings, translates it into the proper
6660399d4dbSRafael J. Wysocki  * enumerated value, and initiates a suspend transition.
6671da177e4SLinus Torvalds  */
668386f275fSKay Sievers static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
669386f275fSKay Sievers 			  char *buf)
6701da177e4SLinus Torvalds {
6711da177e4SLinus Torvalds 	char *s = buf;
672296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND
67327ddcc65SRafael J. Wysocki 	suspend_state_t i;
6741da177e4SLinus Torvalds 
67527ddcc65SRafael J. Wysocki 	for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
676d431cbc5SRafael J. Wysocki 		if (pm_states[i])
677d431cbc5SRafael J. Wysocki 			s += sprintf(s,"%s ", pm_states[i]);
67827ddcc65SRafael J. Wysocki 
679296699deSRafael J. Wysocki #endif
680a6e15a39SKees Cook 	if (hibernation_available())
681a6e15a39SKees Cook 		s += sprintf(s, "disk ");
682a3d25c27SRafael J. Wysocki 	if (s != buf)
683a3d25c27SRafael J. Wysocki 		/* convert the last space to a newline */
684a3d25c27SRafael J. Wysocki 		*(s-1) = '\n';
6851da177e4SLinus Torvalds 	return (s - buf);
6861da177e4SLinus Torvalds }
6871da177e4SLinus Torvalds 
6887483b4a4SRafael J. Wysocki static suspend_state_t decode_state(const char *buf, size_t n)
6891da177e4SLinus Torvalds {
690296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND
691d431cbc5SRafael J. Wysocki 	suspend_state_t state;
692296699deSRafael J. Wysocki #endif
6931da177e4SLinus Torvalds 	char *p;
6941da177e4SLinus Torvalds 	int len;
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds 	p = memchr(buf, '\n', n);
6971da177e4SLinus Torvalds 	len = p ? p - buf : n;
6981da177e4SLinus Torvalds 
6997483b4a4SRafael J. Wysocki 	/* Check hibernation first. */
700d30bdfc0SChuhong Yuan 	if (len == 4 && str_has_prefix(buf, "disk"))
7017483b4a4SRafael J. Wysocki 		return PM_SUSPEND_MAX;
702a3d25c27SRafael J. Wysocki 
703296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND
704d431cbc5SRafael J. Wysocki 	for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) {
705d431cbc5SRafael J. Wysocki 		const char *label = pm_states[state];
706d431cbc5SRafael J. Wysocki 
707d431cbc5SRafael J. Wysocki 		if (label && len == strlen(label) && !strncmp(buf, label, len))
708d431cbc5SRafael J. Wysocki 			return state;
709d431cbc5SRafael J. Wysocki 	}
710296699deSRafael J. Wysocki #endif
711296699deSRafael J. Wysocki 
7127483b4a4SRafael J. Wysocki 	return PM_SUSPEND_ON;
7137483b4a4SRafael J. Wysocki }
7147483b4a4SRafael J. Wysocki 
7157483b4a4SRafael J. Wysocki static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
7167483b4a4SRafael J. Wysocki 			   const char *buf, size_t n)
7177483b4a4SRafael J. Wysocki {
7187483b4a4SRafael J. Wysocki 	suspend_state_t state;
7197483b4a4SRafael J. Wysocki 	int error;
7207483b4a4SRafael J. Wysocki 
7217483b4a4SRafael J. Wysocki 	error = pm_autosleep_lock();
7227483b4a4SRafael J. Wysocki 	if (error)
7237483b4a4SRafael J. Wysocki 		return error;
7247483b4a4SRafael J. Wysocki 
7257483b4a4SRafael J. Wysocki 	if (pm_autosleep_state() > PM_SUSPEND_ON) {
7267483b4a4SRafael J. Wysocki 		error = -EBUSY;
7277483b4a4SRafael J. Wysocki 		goto out;
7287483b4a4SRafael J. Wysocki 	}
7297483b4a4SRafael J. Wysocki 
7307483b4a4SRafael J. Wysocki 	state = decode_state(buf, n);
731406e7938SRafael J. Wysocki 	if (state < PM_SUSPEND_MAX) {
732406e7938SRafael J. Wysocki 		if (state == PM_SUSPEND_MEM)
733406e7938SRafael J. Wysocki 			state = mem_sleep_current;
734406e7938SRafael J. Wysocki 
7357483b4a4SRafael J. Wysocki 		error = pm_suspend(state);
736406e7938SRafael J. Wysocki 	} else if (state == PM_SUSPEND_MAX) {
7377483b4a4SRafael J. Wysocki 		error = hibernate();
738406e7938SRafael J. Wysocki 	} else {
7397483b4a4SRafael J. Wysocki 		error = -EINVAL;
740406e7938SRafael J. Wysocki 	}
7417483b4a4SRafael J. Wysocki 
7427483b4a4SRafael J. Wysocki  out:
7437483b4a4SRafael J. Wysocki 	pm_autosleep_unlock();
7441da177e4SLinus Torvalds 	return error ? error : n;
7451da177e4SLinus Torvalds }
7461da177e4SLinus Torvalds 
7471da177e4SLinus Torvalds power_attr(state);
7481da177e4SLinus Torvalds 
749c125e96fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
750c125e96fSRafael J. Wysocki /*
751c125e96fSRafael J. Wysocki  * The 'wakeup_count' attribute, along with the functions defined in
752c125e96fSRafael J. Wysocki  * drivers/base/power/wakeup.c, provides a means by which wakeup events can be
753c125e96fSRafael J. Wysocki  * handled in a non-racy way.
754c125e96fSRafael J. Wysocki  *
755c125e96fSRafael J. Wysocki  * If a wakeup event occurs when the system is in a sleep state, it simply is
756c125e96fSRafael J. Wysocki  * woken up.  In turn, if an event that would wake the system up from a sleep
757c125e96fSRafael J. Wysocki  * state occurs when it is undergoing a transition to that sleep state, the
758c125e96fSRafael J. Wysocki  * transition should be aborted.  Moreover, if such an event occurs when the
759c125e96fSRafael J. Wysocki  * system is in the working state, an attempt to start a transition to the
760c125e96fSRafael J. Wysocki  * given sleep state should fail during certain period after the detection of
761c125e96fSRafael J. Wysocki  * the event.  Using the 'state' attribute alone is not sufficient to satisfy
762c125e96fSRafael J. Wysocki  * these requirements, because a wakeup event may occur exactly when 'state'
763c125e96fSRafael J. Wysocki  * is being written to and may be delivered to user space right before it is
764c125e96fSRafael J. Wysocki  * frozen, so the event will remain only partially processed until the system is
765c125e96fSRafael J. Wysocki  * woken up by another event.  In particular, it won't cause the transition to
766c125e96fSRafael J. Wysocki  * a sleep state to be aborted.
767c125e96fSRafael J. Wysocki  *
768c125e96fSRafael J. Wysocki  * This difficulty may be overcome if user space uses 'wakeup_count' before
769c125e96fSRafael J. Wysocki  * writing to 'state'.  It first should read from 'wakeup_count' and store
770c125e96fSRafael J. Wysocki  * the read value.  Then, after carrying out its own preparations for the system
771c125e96fSRafael J. Wysocki  * transition to a sleep state, it should write the stored value to
77225985edcSLucas De Marchi  * 'wakeup_count'.  If that fails, at least one wakeup event has occurred since
773c125e96fSRafael J. Wysocki  * 'wakeup_count' was read and 'state' should not be written to.  Otherwise, it
774c125e96fSRafael J. Wysocki  * is allowed to write to 'state', but the transition will be aborted if there
775c125e96fSRafael J. Wysocki  * are any wakeup events detected after 'wakeup_count' was written to.
776c125e96fSRafael J. Wysocki  */
777c125e96fSRafael J. Wysocki 
778c125e96fSRafael J. Wysocki static ssize_t wakeup_count_show(struct kobject *kobj,
779c125e96fSRafael J. Wysocki 				struct kobj_attribute *attr,
780c125e96fSRafael J. Wysocki 				char *buf)
781c125e96fSRafael J. Wysocki {
782074037ecSRafael J. Wysocki 	unsigned int val;
783c125e96fSRafael J. Wysocki 
7847483b4a4SRafael J. Wysocki 	return pm_get_wakeup_count(&val, true) ?
7857483b4a4SRafael J. Wysocki 		sprintf(buf, "%u\n", val) : -EINTR;
786c125e96fSRafael J. Wysocki }
787c125e96fSRafael J. Wysocki 
788c125e96fSRafael J. Wysocki static ssize_t wakeup_count_store(struct kobject *kobj,
789c125e96fSRafael J. Wysocki 				struct kobj_attribute *attr,
790c125e96fSRafael J. Wysocki 				const char *buf, size_t n)
791c125e96fSRafael J. Wysocki {
792074037ecSRafael J. Wysocki 	unsigned int val;
7937483b4a4SRafael J. Wysocki 	int error;
794c125e96fSRafael J. Wysocki 
7957483b4a4SRafael J. Wysocki 	error = pm_autosleep_lock();
7967483b4a4SRafael J. Wysocki 	if (error)
7977483b4a4SRafael J. Wysocki 		return error;
7987483b4a4SRafael J. Wysocki 
7997483b4a4SRafael J. Wysocki 	if (pm_autosleep_state() > PM_SUSPEND_ON) {
8007483b4a4SRafael J. Wysocki 		error = -EBUSY;
8017483b4a4SRafael J. Wysocki 		goto out;
8027483b4a4SRafael J. Wysocki 	}
8037483b4a4SRafael J. Wysocki 
8047483b4a4SRafael J. Wysocki 	error = -EINVAL;
805074037ecSRafael J. Wysocki 	if (sscanf(buf, "%u", &val) == 1) {
806c125e96fSRafael J. Wysocki 		if (pm_save_wakeup_count(val))
8077483b4a4SRafael J. Wysocki 			error = n;
808bb177fedSJulius Werner 		else
809bb177fedSJulius Werner 			pm_print_active_wakeup_sources();
810c125e96fSRafael J. Wysocki 	}
8117483b4a4SRafael J. Wysocki 
8127483b4a4SRafael J. Wysocki  out:
8137483b4a4SRafael J. Wysocki 	pm_autosleep_unlock();
8147483b4a4SRafael J. Wysocki 	return error;
815c125e96fSRafael J. Wysocki }
816c125e96fSRafael J. Wysocki 
817c125e96fSRafael J. Wysocki power_attr(wakeup_count);
8187483b4a4SRafael J. Wysocki 
8197483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP
8207483b4a4SRafael J. Wysocki static ssize_t autosleep_show(struct kobject *kobj,
8217483b4a4SRafael J. Wysocki 			      struct kobj_attribute *attr,
8227483b4a4SRafael J. Wysocki 			      char *buf)
8237483b4a4SRafael J. Wysocki {
8247483b4a4SRafael J. Wysocki 	suspend_state_t state = pm_autosleep_state();
8257483b4a4SRafael J. Wysocki 
8267483b4a4SRafael J. Wysocki 	if (state == PM_SUSPEND_ON)
8277483b4a4SRafael J. Wysocki 		return sprintf(buf, "off\n");
8287483b4a4SRafael J. Wysocki 
8297483b4a4SRafael J. Wysocki #ifdef CONFIG_SUSPEND
8307483b4a4SRafael J. Wysocki 	if (state < PM_SUSPEND_MAX)
831d431cbc5SRafael J. Wysocki 		return sprintf(buf, "%s\n", pm_states[state] ?
832d431cbc5SRafael J. Wysocki 					pm_states[state] : "error");
8337483b4a4SRafael J. Wysocki #endif
8347483b4a4SRafael J. Wysocki #ifdef CONFIG_HIBERNATION
8357483b4a4SRafael J. Wysocki 	return sprintf(buf, "disk\n");
8367483b4a4SRafael J. Wysocki #else
8377483b4a4SRafael J. Wysocki 	return sprintf(buf, "error");
8387483b4a4SRafael J. Wysocki #endif
8397483b4a4SRafael J. Wysocki }
8407483b4a4SRafael J. Wysocki 
8417483b4a4SRafael J. Wysocki static ssize_t autosleep_store(struct kobject *kobj,
8427483b4a4SRafael J. Wysocki 			       struct kobj_attribute *attr,
8437483b4a4SRafael J. Wysocki 			       const char *buf, size_t n)
8447483b4a4SRafael J. Wysocki {
8457483b4a4SRafael J. Wysocki 	suspend_state_t state = decode_state(buf, n);
8467483b4a4SRafael J. Wysocki 	int error;
8477483b4a4SRafael J. Wysocki 
8487483b4a4SRafael J. Wysocki 	if (state == PM_SUSPEND_ON
849040e5bf6SArve Hjønnevåg 	    && strcmp(buf, "off") && strcmp(buf, "off\n"))
8507483b4a4SRafael J. Wysocki 		return -EINVAL;
8517483b4a4SRafael J. Wysocki 
852406e7938SRafael J. Wysocki 	if (state == PM_SUSPEND_MEM)
853406e7938SRafael J. Wysocki 		state = mem_sleep_current;
854406e7938SRafael J. Wysocki 
8557483b4a4SRafael J. Wysocki 	error = pm_autosleep_set_state(state);
8567483b4a4SRafael J. Wysocki 	return error ? error : n;
8577483b4a4SRafael J. Wysocki }
8587483b4a4SRafael J. Wysocki 
8597483b4a4SRafael J. Wysocki power_attr(autosleep);
8607483b4a4SRafael J. Wysocki #endif /* CONFIG_PM_AUTOSLEEP */
861b86ff982SRafael J. Wysocki 
862b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS
863b86ff982SRafael J. Wysocki static ssize_t wake_lock_show(struct kobject *kobj,
864b86ff982SRafael J. Wysocki 			      struct kobj_attribute *attr,
865b86ff982SRafael J. Wysocki 			      char *buf)
866b86ff982SRafael J. Wysocki {
867b86ff982SRafael J. Wysocki 	return pm_show_wakelocks(buf, true);
868b86ff982SRafael J. Wysocki }
869b86ff982SRafael J. Wysocki 
870b86ff982SRafael J. Wysocki static ssize_t wake_lock_store(struct kobject *kobj,
871b86ff982SRafael J. Wysocki 			       struct kobj_attribute *attr,
872b86ff982SRafael J. Wysocki 			       const char *buf, size_t n)
873b86ff982SRafael J. Wysocki {
874b86ff982SRafael J. Wysocki 	int error = pm_wake_lock(buf);
875b86ff982SRafael J. Wysocki 	return error ? error : n;
876b86ff982SRafael J. Wysocki }
877b86ff982SRafael J. Wysocki 
878b86ff982SRafael J. Wysocki power_attr(wake_lock);
879b86ff982SRafael J. Wysocki 
880b86ff982SRafael J. Wysocki static ssize_t wake_unlock_show(struct kobject *kobj,
881b86ff982SRafael J. Wysocki 				struct kobj_attribute *attr,
882b86ff982SRafael J. Wysocki 				char *buf)
883b86ff982SRafael J. Wysocki {
884b86ff982SRafael J. Wysocki 	return pm_show_wakelocks(buf, false);
885b86ff982SRafael J. Wysocki }
886b86ff982SRafael J. Wysocki 
887b86ff982SRafael J. Wysocki static ssize_t wake_unlock_store(struct kobject *kobj,
888b86ff982SRafael J. Wysocki 				 struct kobj_attribute *attr,
889b86ff982SRafael J. Wysocki 				 const char *buf, size_t n)
890b86ff982SRafael J. Wysocki {
891b86ff982SRafael J. Wysocki 	int error = pm_wake_unlock(buf);
892b86ff982SRafael J. Wysocki 	return error ? error : n;
893b86ff982SRafael J. Wysocki }
894b86ff982SRafael J. Wysocki 
895b86ff982SRafael J. Wysocki power_attr(wake_unlock);
896b86ff982SRafael J. Wysocki 
897b86ff982SRafael J. Wysocki #endif /* CONFIG_PM_WAKELOCKS */
898c125e96fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */
899c125e96fSRafael J. Wysocki 
900c5c6ba4eSRafael J. Wysocki #ifdef CONFIG_PM_TRACE
901c5c6ba4eSRafael J. Wysocki int pm_trace_enabled;
902c5c6ba4eSRafael J. Wysocki 
903386f275fSKay Sievers static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,
904386f275fSKay Sievers 			     char *buf)
905c5c6ba4eSRafael J. Wysocki {
906c5c6ba4eSRafael J. Wysocki 	return sprintf(buf, "%d\n", pm_trace_enabled);
907c5c6ba4eSRafael J. Wysocki }
908c5c6ba4eSRafael J. Wysocki 
909c5c6ba4eSRafael J. Wysocki static ssize_t
910386f275fSKay Sievers pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
911386f275fSKay Sievers 	       const char *buf, size_t n)
912c5c6ba4eSRafael J. Wysocki {
913c5c6ba4eSRafael J. Wysocki 	int val;
914c5c6ba4eSRafael J. Wysocki 
915c5c6ba4eSRafael J. Wysocki 	if (sscanf(buf, "%d", &val) == 1) {
916c5c6ba4eSRafael J. Wysocki 		pm_trace_enabled = !!val;
9179dceefe4SShuah Khan 		if (pm_trace_enabled) {
9189dceefe4SShuah Khan 			pr_warn("PM: Enabling pm_trace changes system date and time during resume.\n"
9199dceefe4SShuah Khan 				"PM: Correct system time has to be restored manually after resume.\n");
9209dceefe4SShuah Khan 		}
921c5c6ba4eSRafael J. Wysocki 		return n;
922c5c6ba4eSRafael J. Wysocki 	}
923c5c6ba4eSRafael J. Wysocki 	return -EINVAL;
924c5c6ba4eSRafael J. Wysocki }
925c5c6ba4eSRafael J. Wysocki 
926c5c6ba4eSRafael J. Wysocki power_attr(pm_trace);
927d33ac60bSJames Hogan 
928d33ac60bSJames Hogan static ssize_t pm_trace_dev_match_show(struct kobject *kobj,
929d33ac60bSJames Hogan 				       struct kobj_attribute *attr,
930d33ac60bSJames Hogan 				       char *buf)
931d33ac60bSJames Hogan {
932d33ac60bSJames Hogan 	return show_trace_dev_match(buf, PAGE_SIZE);
933d33ac60bSJames Hogan }
934d33ac60bSJames Hogan 
935a1e9ca69SRafael J. Wysocki power_attr_ro(pm_trace_dev_match);
936d33ac60bSJames Hogan 
9370e7d56e3SRafael J. Wysocki #endif /* CONFIG_PM_TRACE */
938c5c6ba4eSRafael J. Wysocki 
939957d1282SLi Fei #ifdef CONFIG_FREEZER
940957d1282SLi Fei static ssize_t pm_freeze_timeout_show(struct kobject *kobj,
941957d1282SLi Fei 				      struct kobj_attribute *attr, char *buf)
942957d1282SLi Fei {
943957d1282SLi Fei 	return sprintf(buf, "%u\n", freeze_timeout_msecs);
944957d1282SLi Fei }
945957d1282SLi Fei 
946957d1282SLi Fei static ssize_t pm_freeze_timeout_store(struct kobject *kobj,
947957d1282SLi Fei 				       struct kobj_attribute *attr,
948957d1282SLi Fei 				       const char *buf, size_t n)
949957d1282SLi Fei {
950957d1282SLi Fei 	unsigned long val;
951957d1282SLi Fei 
952957d1282SLi Fei 	if (kstrtoul(buf, 10, &val))
953957d1282SLi Fei 		return -EINVAL;
954957d1282SLi Fei 
955957d1282SLi Fei 	freeze_timeout_msecs = val;
956957d1282SLi Fei 	return n;
957957d1282SLi Fei }
958957d1282SLi Fei 
959957d1282SLi Fei power_attr(pm_freeze_timeout);
960957d1282SLi Fei 
961957d1282SLi Fei #endif	/* CONFIG_FREEZER*/
962957d1282SLi Fei 
963c5c6ba4eSRafael J. Wysocki static struct attribute * g[] = {
964c5c6ba4eSRafael J. Wysocki 	&state_attr.attr,
9650e7d56e3SRafael J. Wysocki #ifdef CONFIG_PM_TRACE
966c5c6ba4eSRafael J. Wysocki 	&pm_trace_attr.attr,
967d33ac60bSJames Hogan 	&pm_trace_dev_match_attr.attr,
9680e7d56e3SRafael J. Wysocki #endif
9690e06b4a8SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
9700e06b4a8SRafael J. Wysocki 	&pm_async_attr.attr,
971c125e96fSRafael J. Wysocki 	&wakeup_count_attr.attr,
972406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND
973406e7938SRafael J. Wysocki 	&mem_sleep_attr.attr,
974c052bf82SJonas Meurer 	&sync_on_suspend_attr.attr,
975406e7938SRafael J. Wysocki #endif
9767483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP
9777483b4a4SRafael J. Wysocki 	&autosleep_attr.attr,
9787483b4a4SRafael J. Wysocki #endif
979b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS
980b86ff982SRafael J. Wysocki 	&wake_lock_attr.attr,
981b86ff982SRafael J. Wysocki 	&wake_unlock_attr.attr,
982b86ff982SRafael J. Wysocki #endif
983b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG
984e516a1dbSRafael J. Wysocki 	&pm_test_attr.attr,
9854b7760baSSameer Nanda 	&pm_print_times_attr.attr,
986a6f5f0ddSAlexandra Yates 	&pm_wakeup_irq_attr.attr,
9878d8b2441SRafael J. Wysocki 	&pm_debug_messages_attr.attr,
9880e7d56e3SRafael J. Wysocki #endif
9890e06b4a8SRafael J. Wysocki #endif
990957d1282SLi Fei #ifdef CONFIG_FREEZER
991957d1282SLi Fei 	&pm_freeze_timeout_attr.attr,
992957d1282SLi Fei #endif
993c5c6ba4eSRafael J. Wysocki 	NULL,
994c5c6ba4eSRafael J. Wysocki };
9951da177e4SLinus Torvalds 
9961d0c6e59SArvind Yadav static const struct attribute_group attr_group = {
9971da177e4SLinus Torvalds 	.attrs = g,
9981da177e4SLinus Torvalds };
9991da177e4SLinus Torvalds 
10002c8db5beSKalesh Singh static const struct attribute_group *attr_groups[] = {
10012c8db5beSKalesh Singh 	&attr_group,
10022c8db5beSKalesh Singh #ifdef CONFIG_PM_SLEEP
10032c8db5beSKalesh Singh 	&suspend_attr_group,
10042c8db5beSKalesh Singh #endif
10052c8db5beSKalesh Singh 	NULL,
10062c8db5beSKalesh Singh };
10072c8db5beSKalesh Singh 
10085e928f77SRafael J. Wysocki struct workqueue_struct *pm_wq;
10097b199ca2SAlan Stern EXPORT_SYMBOL_GPL(pm_wq);
10105e928f77SRafael J. Wysocki 
10115e928f77SRafael J. Wysocki static int __init pm_start_workqueue(void)
10125e928f77SRafael J. Wysocki {
101358a69cb4STejun Heo 	pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0);
10145e928f77SRafael J. Wysocki 
10155e928f77SRafael J. Wysocki 	return pm_wq ? 0 : -ENOMEM;
10165e928f77SRafael J. Wysocki }
10175e928f77SRafael J. Wysocki 
10181da177e4SLinus Torvalds static int __init pm_init(void)
10191da177e4SLinus Torvalds {
10205e928f77SRafael J. Wysocki 	int error = pm_start_workqueue();
10215e928f77SRafael J. Wysocki 	if (error)
10225e928f77SRafael J. Wysocki 		return error;
1023ac5c24ecSRafael J. Wysocki 	hibernate_image_size_init();
1024ddeb6487SRafael J. Wysocki 	hibernate_reserved_size_init();
1025fa7fd6faSSudeep Holla 	pm_states_init();
1026d76e15fbSGreg Kroah-Hartman 	power_kobj = kobject_create_and_add("power", NULL);
1027d76e15fbSGreg Kroah-Hartman 	if (!power_kobj)
1028039a5dcdSGreg Kroah-Hartman 		return -ENOMEM;
10292c8db5beSKalesh Singh 	error = sysfs_create_groups(power_kobj, attr_groups);
10307483b4a4SRafael J. Wysocki 	if (error)
10317483b4a4SRafael J. Wysocki 		return error;
1032b2df1d4fSRafael J. Wysocki 	pm_print_times_init();
10337483b4a4SRafael J. Wysocki 	return pm_autosleep_init();
10341da177e4SLinus Torvalds }
10351da177e4SLinus Torvalds 
10361da177e4SLinus Torvalds core_initcall(pm_init);
1037