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 96e5fdeedSPaul Gortmaker #include <linux/export.h> 101da177e4SLinus Torvalds #include <linux/kobject.h> 111da177e4SLinus Torvalds #include <linux/string.h> 12431d452aSZhonghui Fu #include <linux/pm-trace.h> 135e928f77SRafael J. Wysocki #include <linux/workqueue.h> 142a77c46dSShuoX Liu #include <linux/debugfs.h> 152a77c46dSShuoX Liu #include <linux/seq_file.h> 1655f2503cSPingfan Liu #include <linux/suspend.h> 17b5dee313SHarry Pan #include <linux/syscalls.h> 18*f49249d5SBen Dooks #include <linux/pm_runtime.h> 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds #include "power.h" 211da177e4SLinus Torvalds 22cd51e61cSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 23cd51e61cSRafael J. Wysocki 244bf236a3SBart Van Assche void lock_system_sleep(void) 254bf236a3SBart Van Assche { 264bf236a3SBart Van Assche current->flags |= PF_FREEZER_SKIP; 2755f2503cSPingfan Liu mutex_lock(&system_transition_mutex); 284bf236a3SBart Van Assche } 294bf236a3SBart Van Assche EXPORT_SYMBOL_GPL(lock_system_sleep); 304bf236a3SBart Van Assche 314bf236a3SBart Van Assche void unlock_system_sleep(void) 324bf236a3SBart Van Assche { 334bf236a3SBart Van Assche /* 344bf236a3SBart Van Assche * Don't use freezer_count() because we don't want the call to 354bf236a3SBart Van Assche * try_to_freeze() here. 364bf236a3SBart Van Assche * 374bf236a3SBart Van Assche * Reason: 384bf236a3SBart Van Assche * Fundamentally, we just don't need it, because freezing condition 3955f2503cSPingfan Liu * doesn't come into effect until we release the 4055f2503cSPingfan Liu * system_transition_mutex lock, since the freezer always works with 4155f2503cSPingfan Liu * system_transition_mutex held. 424bf236a3SBart Van Assche * 434bf236a3SBart Van Assche * More importantly, in the case of hibernation, 444bf236a3SBart Van Assche * unlock_system_sleep() gets called in snapshot_read() and 454bf236a3SBart Van Assche * snapshot_write() when the freezing condition is still in effect. 464bf236a3SBart Van Assche * Which means, if we use try_to_freeze() here, it would make them 474bf236a3SBart Van Assche * enter the refrigerator, thus causing hibernation to lockup. 484bf236a3SBart Van Assche */ 494bf236a3SBart Van Assche current->flags &= ~PF_FREEZER_SKIP; 5055f2503cSPingfan Liu mutex_unlock(&system_transition_mutex); 514bf236a3SBart Van Assche } 524bf236a3SBart Van Assche EXPORT_SYMBOL_GPL(unlock_system_sleep); 534bf236a3SBart Van Assche 54b5dee313SHarry Pan void ksys_sync_helper(void) 55b5dee313SHarry Pan { 56c64546b1SHarry Pan ktime_t start; 57c64546b1SHarry Pan long elapsed_msecs; 58c64546b1SHarry Pan 59c64546b1SHarry Pan start = ktime_get(); 60b5dee313SHarry Pan ksys_sync(); 61c64546b1SHarry Pan elapsed_msecs = ktime_to_ms(ktime_sub(ktime_get(), start)); 62c64546b1SHarry Pan pr_info("Filesystems sync: %ld.%03ld seconds\n", 63c64546b1SHarry Pan elapsed_msecs / MSEC_PER_SEC, elapsed_msecs % MSEC_PER_SEC); 64b5dee313SHarry Pan } 65b5dee313SHarry Pan EXPORT_SYMBOL_GPL(ksys_sync_helper); 66b5dee313SHarry Pan 6782525756SAlan Stern /* Routines for PM-transition notifications */ 6882525756SAlan Stern 6982525756SAlan Stern static BLOCKING_NOTIFIER_HEAD(pm_chain_head); 7082525756SAlan Stern 7182525756SAlan Stern int register_pm_notifier(struct notifier_block *nb) 7282525756SAlan Stern { 7382525756SAlan Stern return blocking_notifier_chain_register(&pm_chain_head, nb); 7482525756SAlan Stern } 7582525756SAlan Stern EXPORT_SYMBOL_GPL(register_pm_notifier); 7682525756SAlan Stern 7782525756SAlan Stern int unregister_pm_notifier(struct notifier_block *nb) 7882525756SAlan Stern { 7982525756SAlan Stern return blocking_notifier_chain_unregister(&pm_chain_head, nb); 8082525756SAlan Stern } 8182525756SAlan Stern EXPORT_SYMBOL_GPL(unregister_pm_notifier); 8282525756SAlan Stern 83ea00f4f4SLianwei Wang int __pm_notifier_call_chain(unsigned long val, int nr_to_call, int *nr_calls) 8482525756SAlan Stern { 85ea00f4f4SLianwei Wang int ret; 86ea00f4f4SLianwei Wang 87ea00f4f4SLianwei Wang ret = __blocking_notifier_call_chain(&pm_chain_head, val, NULL, 88ea00f4f4SLianwei Wang nr_to_call, nr_calls); 89f0c077a8SAkinobu Mita 90f0c077a8SAkinobu Mita return notifier_to_errno(ret); 9182525756SAlan Stern } 92ea00f4f4SLianwei Wang int pm_notifier_call_chain(unsigned long val) 93ea00f4f4SLianwei Wang { 94ea00f4f4SLianwei Wang return __pm_notifier_call_chain(val, -1, NULL); 95ea00f4f4SLianwei Wang } 9682525756SAlan Stern 970e06b4a8SRafael J. Wysocki /* If set, devices may be suspended and resumed asynchronously. */ 980e06b4a8SRafael J. Wysocki int pm_async_enabled = 1; 990e06b4a8SRafael J. Wysocki 1000e06b4a8SRafael J. Wysocki static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr, 1010e06b4a8SRafael J. Wysocki char *buf) 1020e06b4a8SRafael J. Wysocki { 1030e06b4a8SRafael J. Wysocki return sprintf(buf, "%d\n", pm_async_enabled); 1040e06b4a8SRafael J. Wysocki } 1050e06b4a8SRafael J. Wysocki 1060e06b4a8SRafael J. Wysocki static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr, 1070e06b4a8SRafael J. Wysocki const char *buf, size_t n) 1080e06b4a8SRafael J. Wysocki { 1090e06b4a8SRafael J. Wysocki unsigned long val; 1100e06b4a8SRafael J. Wysocki 111883ee4f7SDaniel Walter if (kstrtoul(buf, 10, &val)) 1120e06b4a8SRafael J. Wysocki return -EINVAL; 1130e06b4a8SRafael J. Wysocki 1140e06b4a8SRafael J. Wysocki if (val > 1) 1150e06b4a8SRafael J. Wysocki return -EINVAL; 1160e06b4a8SRafael J. Wysocki 1170e06b4a8SRafael J. Wysocki pm_async_enabled = val; 1180e06b4a8SRafael J. Wysocki return n; 1190e06b4a8SRafael J. Wysocki } 1200e06b4a8SRafael J. Wysocki 1210e06b4a8SRafael J. Wysocki power_attr(pm_async); 1220e06b4a8SRafael J. Wysocki 123406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND 124406e7938SRafael J. Wysocki static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr, 125406e7938SRafael J. Wysocki char *buf) 126406e7938SRafael J. Wysocki { 127406e7938SRafael J. Wysocki char *s = buf; 128406e7938SRafael J. Wysocki suspend_state_t i; 129406e7938SRafael J. Wysocki 130406e7938SRafael J. Wysocki for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) 131406e7938SRafael J. Wysocki if (mem_sleep_states[i]) { 132406e7938SRafael J. Wysocki const char *label = mem_sleep_states[i]; 133406e7938SRafael J. Wysocki 134406e7938SRafael J. Wysocki if (mem_sleep_current == i) 135406e7938SRafael J. Wysocki s += sprintf(s, "[%s] ", label); 136406e7938SRafael J. Wysocki else 137406e7938SRafael J. Wysocki s += sprintf(s, "%s ", label); 138406e7938SRafael J. Wysocki } 139406e7938SRafael J. Wysocki 140406e7938SRafael J. Wysocki /* Convert the last space to a newline if needed. */ 141406e7938SRafael J. Wysocki if (s != buf) 142406e7938SRafael J. Wysocki *(s-1) = '\n'; 143406e7938SRafael J. Wysocki 144406e7938SRafael J. Wysocki return (s - buf); 145406e7938SRafael J. Wysocki } 146406e7938SRafael J. Wysocki 147406e7938SRafael J. Wysocki static suspend_state_t decode_suspend_state(const char *buf, size_t n) 148406e7938SRafael J. Wysocki { 149406e7938SRafael J. Wysocki suspend_state_t state; 150406e7938SRafael J. Wysocki char *p; 151406e7938SRafael J. Wysocki int len; 152406e7938SRafael J. Wysocki 153406e7938SRafael J. Wysocki p = memchr(buf, '\n', n); 154406e7938SRafael J. Wysocki len = p ? p - buf : n; 155406e7938SRafael J. Wysocki 156406e7938SRafael J. Wysocki for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) { 157406e7938SRafael J. Wysocki const char *label = mem_sleep_states[state]; 158406e7938SRafael J. Wysocki 159406e7938SRafael J. Wysocki if (label && len == strlen(label) && !strncmp(buf, label, len)) 160406e7938SRafael J. Wysocki return state; 161406e7938SRafael J. Wysocki } 162406e7938SRafael J. Wysocki 163406e7938SRafael J. Wysocki return PM_SUSPEND_ON; 164406e7938SRafael J. Wysocki } 165406e7938SRafael J. Wysocki 166406e7938SRafael J. Wysocki static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr, 167406e7938SRafael J. Wysocki const char *buf, size_t n) 168406e7938SRafael J. Wysocki { 169406e7938SRafael J. Wysocki suspend_state_t state; 170406e7938SRafael J. Wysocki int error; 171406e7938SRafael J. Wysocki 172406e7938SRafael J. Wysocki error = pm_autosleep_lock(); 173406e7938SRafael J. Wysocki if (error) 174406e7938SRafael J. Wysocki return error; 175406e7938SRafael J. Wysocki 176406e7938SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 177406e7938SRafael J. Wysocki error = -EBUSY; 178406e7938SRafael J. Wysocki goto out; 179406e7938SRafael J. Wysocki } 180406e7938SRafael J. Wysocki 181406e7938SRafael J. Wysocki state = decode_suspend_state(buf, n); 182406e7938SRafael J. Wysocki if (state < PM_SUSPEND_MAX && state > PM_SUSPEND_ON) 183406e7938SRafael J. Wysocki mem_sleep_current = state; 184406e7938SRafael J. Wysocki else 185406e7938SRafael J. Wysocki error = -EINVAL; 186406e7938SRafael J. Wysocki 187406e7938SRafael J. Wysocki out: 188406e7938SRafael J. Wysocki pm_autosleep_unlock(); 189406e7938SRafael J. Wysocki return error ? error : n; 190406e7938SRafael J. Wysocki } 191406e7938SRafael J. Wysocki 192406e7938SRafael J. Wysocki power_attr(mem_sleep); 193406e7938SRafael J. Wysocki #endif /* CONFIG_SUSPEND */ 194406e7938SRafael J. Wysocki 195e516a1dbSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 1960e7d56e3SRafael J. Wysocki int pm_test_level = TEST_NONE; 1970e7d56e3SRafael J. Wysocki 1980e7d56e3SRafael J. Wysocki static const char * const pm_tests[__TEST_AFTER_LAST] = { 1990e7d56e3SRafael J. Wysocki [TEST_NONE] = "none", 2000e7d56e3SRafael J. Wysocki [TEST_CORE] = "core", 2010e7d56e3SRafael J. Wysocki [TEST_CPUS] = "processors", 2020e7d56e3SRafael J. Wysocki [TEST_PLATFORM] = "platform", 2030e7d56e3SRafael J. Wysocki [TEST_DEVICES] = "devices", 2040e7d56e3SRafael J. Wysocki [TEST_FREEZER] = "freezer", 2050e7d56e3SRafael J. Wysocki }; 2060e7d56e3SRafael J. Wysocki 207039a75c6SRafael J. Wysocki static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr, 208039a75c6SRafael J. Wysocki char *buf) 2090e7d56e3SRafael J. Wysocki { 2100e7d56e3SRafael J. Wysocki char *s = buf; 2110e7d56e3SRafael J. Wysocki int level; 2120e7d56e3SRafael J. Wysocki 2130e7d56e3SRafael J. Wysocki for (level = TEST_FIRST; level <= TEST_MAX; level++) 2140e7d56e3SRafael J. Wysocki if (pm_tests[level]) { 2150e7d56e3SRafael J. Wysocki if (level == pm_test_level) 2160e7d56e3SRafael J. Wysocki s += sprintf(s, "[%s] ", pm_tests[level]); 2170e7d56e3SRafael J. Wysocki else 2180e7d56e3SRafael J. Wysocki s += sprintf(s, "%s ", pm_tests[level]); 2190e7d56e3SRafael J. Wysocki } 2200e7d56e3SRafael J. Wysocki 2210e7d56e3SRafael J. Wysocki if (s != buf) 2220e7d56e3SRafael J. Wysocki /* convert the last space to a newline */ 2230e7d56e3SRafael J. Wysocki *(s-1) = '\n'; 2240e7d56e3SRafael J. Wysocki 2250e7d56e3SRafael J. Wysocki return (s - buf); 2260e7d56e3SRafael J. Wysocki } 2270e7d56e3SRafael J. Wysocki 228039a75c6SRafael J. Wysocki static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, 229039a75c6SRafael J. Wysocki const char *buf, size_t n) 2300e7d56e3SRafael J. Wysocki { 2310e7d56e3SRafael J. Wysocki const char * const *s; 2320e7d56e3SRafael J. Wysocki int level; 2330e7d56e3SRafael J. Wysocki char *p; 2340e7d56e3SRafael J. Wysocki int len; 2350e7d56e3SRafael J. Wysocki int error = -EINVAL; 2360e7d56e3SRafael J. Wysocki 2370e7d56e3SRafael J. Wysocki p = memchr(buf, '\n', n); 2380e7d56e3SRafael J. Wysocki len = p ? p - buf : n; 2390e7d56e3SRafael J. Wysocki 240bcda53faSSrivatsa S. Bhat lock_system_sleep(); 2410e7d56e3SRafael J. Wysocki 2420e7d56e3SRafael J. Wysocki level = TEST_FIRST; 2430e7d56e3SRafael J. Wysocki for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++) 2440e7d56e3SRafael J. Wysocki if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) { 2450e7d56e3SRafael J. Wysocki pm_test_level = level; 2460e7d56e3SRafael J. Wysocki error = 0; 2470e7d56e3SRafael J. Wysocki break; 2480e7d56e3SRafael J. Wysocki } 2490e7d56e3SRafael J. Wysocki 250bcda53faSSrivatsa S. Bhat unlock_system_sleep(); 2510e7d56e3SRafael J. Wysocki 2520e7d56e3SRafael J. Wysocki return error ? error : n; 2530e7d56e3SRafael J. Wysocki } 2540e7d56e3SRafael J. Wysocki 2550e7d56e3SRafael J. Wysocki power_attr(pm_test); 256e516a1dbSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */ 2570e7d56e3SRafael J. Wysocki 2582a77c46dSShuoX Liu static char *suspend_step_name(enum suspend_stat_step step) 2592a77c46dSShuoX Liu { 2602a77c46dSShuoX Liu switch (step) { 2612a77c46dSShuoX Liu case SUSPEND_FREEZE: 2622a77c46dSShuoX Liu return "freeze"; 2632a77c46dSShuoX Liu case SUSPEND_PREPARE: 2642a77c46dSShuoX Liu return "prepare"; 2652a77c46dSShuoX Liu case SUSPEND_SUSPEND: 2662a77c46dSShuoX Liu return "suspend"; 2672a77c46dSShuoX Liu case SUSPEND_SUSPEND_NOIRQ: 2682a77c46dSShuoX Liu return "suspend_noirq"; 2692a77c46dSShuoX Liu case SUSPEND_RESUME_NOIRQ: 2702a77c46dSShuoX Liu return "resume_noirq"; 2712a77c46dSShuoX Liu case SUSPEND_RESUME: 2722a77c46dSShuoX Liu return "resume"; 2732a77c46dSShuoX Liu default: 2742a77c46dSShuoX Liu return ""; 2752a77c46dSShuoX Liu } 2762a77c46dSShuoX Liu } 2772a77c46dSShuoX Liu 2782c8db5beSKalesh Singh #define suspend_attr(_name) \ 2792c8db5beSKalesh Singh static ssize_t _name##_show(struct kobject *kobj, \ 2802c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) \ 2812c8db5beSKalesh Singh { \ 2822c8db5beSKalesh Singh return sprintf(buf, "%d\n", suspend_stats._name); \ 2832c8db5beSKalesh Singh } \ 2842c8db5beSKalesh Singh static struct kobj_attribute _name = __ATTR_RO(_name) 2852c8db5beSKalesh Singh 2862c8db5beSKalesh Singh suspend_attr(success); 2872c8db5beSKalesh Singh suspend_attr(fail); 2882c8db5beSKalesh Singh suspend_attr(failed_freeze); 2892c8db5beSKalesh Singh suspend_attr(failed_prepare); 2902c8db5beSKalesh Singh suspend_attr(failed_suspend); 2912c8db5beSKalesh Singh suspend_attr(failed_suspend_late); 2922c8db5beSKalesh Singh suspend_attr(failed_suspend_noirq); 2932c8db5beSKalesh Singh suspend_attr(failed_resume); 2942c8db5beSKalesh Singh suspend_attr(failed_resume_early); 2952c8db5beSKalesh Singh suspend_attr(failed_resume_noirq); 2962c8db5beSKalesh Singh 2972c8db5beSKalesh Singh static ssize_t last_failed_dev_show(struct kobject *kobj, 2982c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 2992c8db5beSKalesh Singh { 3002c8db5beSKalesh Singh int index; 3012c8db5beSKalesh Singh char *last_failed_dev = NULL; 3022c8db5beSKalesh Singh 3032c8db5beSKalesh Singh index = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; 3042c8db5beSKalesh Singh index %= REC_FAILED_NUM; 3052c8db5beSKalesh Singh last_failed_dev = suspend_stats.failed_devs[index]; 3062c8db5beSKalesh Singh 3072c8db5beSKalesh Singh return sprintf(buf, "%s\n", last_failed_dev); 3082c8db5beSKalesh Singh } 3092c8db5beSKalesh Singh static struct kobj_attribute last_failed_dev = __ATTR_RO(last_failed_dev); 3102c8db5beSKalesh Singh 3112c8db5beSKalesh Singh static ssize_t last_failed_errno_show(struct kobject *kobj, 3122c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 3132c8db5beSKalesh Singh { 3142c8db5beSKalesh Singh int index; 3152c8db5beSKalesh Singh int last_failed_errno; 3162c8db5beSKalesh Singh 3172c8db5beSKalesh Singh index = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1; 3182c8db5beSKalesh Singh index %= REC_FAILED_NUM; 3192c8db5beSKalesh Singh last_failed_errno = suspend_stats.errno[index]; 3202c8db5beSKalesh Singh 3212c8db5beSKalesh Singh return sprintf(buf, "%d\n", last_failed_errno); 3222c8db5beSKalesh Singh } 3232c8db5beSKalesh Singh static struct kobj_attribute last_failed_errno = __ATTR_RO(last_failed_errno); 3242c8db5beSKalesh Singh 3252c8db5beSKalesh Singh static ssize_t last_failed_step_show(struct kobject *kobj, 3262c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 3272c8db5beSKalesh Singh { 3282c8db5beSKalesh Singh int index; 3292c8db5beSKalesh Singh enum suspend_stat_step step; 3302c8db5beSKalesh Singh char *last_failed_step = NULL; 3312c8db5beSKalesh Singh 3322c8db5beSKalesh Singh index = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; 3332c8db5beSKalesh Singh index %= REC_FAILED_NUM; 3342c8db5beSKalesh Singh step = suspend_stats.failed_steps[index]; 3352c8db5beSKalesh Singh last_failed_step = suspend_step_name(step); 3362c8db5beSKalesh Singh 3372c8db5beSKalesh Singh return sprintf(buf, "%s\n", last_failed_step); 3382c8db5beSKalesh Singh } 3392c8db5beSKalesh Singh static struct kobj_attribute last_failed_step = __ATTR_RO(last_failed_step); 3402c8db5beSKalesh Singh 3412c8db5beSKalesh Singh static struct attribute *suspend_attrs[] = { 3422c8db5beSKalesh Singh &success.attr, 3432c8db5beSKalesh Singh &fail.attr, 3442c8db5beSKalesh Singh &failed_freeze.attr, 3452c8db5beSKalesh Singh &failed_prepare.attr, 3462c8db5beSKalesh Singh &failed_suspend.attr, 3472c8db5beSKalesh Singh &failed_suspend_late.attr, 3482c8db5beSKalesh Singh &failed_suspend_noirq.attr, 3492c8db5beSKalesh Singh &failed_resume.attr, 3502c8db5beSKalesh Singh &failed_resume_early.attr, 3512c8db5beSKalesh Singh &failed_resume_noirq.attr, 3522c8db5beSKalesh Singh &last_failed_dev.attr, 3532c8db5beSKalesh Singh &last_failed_errno.attr, 3542c8db5beSKalesh Singh &last_failed_step.attr, 3552c8db5beSKalesh Singh NULL, 3562c8db5beSKalesh Singh }; 3572c8db5beSKalesh Singh 3582c8db5beSKalesh Singh static struct attribute_group suspend_attr_group = { 3592c8db5beSKalesh Singh .name = "suspend_stats", 3602c8db5beSKalesh Singh .attrs = suspend_attrs, 3612c8db5beSKalesh Singh }; 3622c8db5beSKalesh Singh 3632c8db5beSKalesh Singh #ifdef CONFIG_DEBUG_FS 3642a77c46dSShuoX Liu static int suspend_stats_show(struct seq_file *s, void *unused) 3652a77c46dSShuoX Liu { 3662a77c46dSShuoX Liu int i, index, last_dev, last_errno, last_step; 3672a77c46dSShuoX Liu 3682a77c46dSShuoX Liu last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; 3692a77c46dSShuoX Liu last_dev %= REC_FAILED_NUM; 3702a77c46dSShuoX Liu last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1; 3712a77c46dSShuoX Liu last_errno %= REC_FAILED_NUM; 3722a77c46dSShuoX Liu last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; 3732a77c46dSShuoX Liu last_step %= REC_FAILED_NUM; 374cf579dfbSRafael J. Wysocki seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n" 375cf579dfbSRafael J. Wysocki "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n", 3762a77c46dSShuoX Liu "success", suspend_stats.success, 3772a77c46dSShuoX Liu "fail", suspend_stats.fail, 3782a77c46dSShuoX Liu "failed_freeze", suspend_stats.failed_freeze, 3792a77c46dSShuoX Liu "failed_prepare", suspend_stats.failed_prepare, 3802a77c46dSShuoX Liu "failed_suspend", suspend_stats.failed_suspend, 381cf579dfbSRafael J. Wysocki "failed_suspend_late", 382cf579dfbSRafael J. Wysocki suspend_stats.failed_suspend_late, 3832a77c46dSShuoX Liu "failed_suspend_noirq", 3842a77c46dSShuoX Liu suspend_stats.failed_suspend_noirq, 3852a77c46dSShuoX Liu "failed_resume", suspend_stats.failed_resume, 386cf579dfbSRafael J. Wysocki "failed_resume_early", 387cf579dfbSRafael J. Wysocki suspend_stats.failed_resume_early, 3882a77c46dSShuoX Liu "failed_resume_noirq", 3892a77c46dSShuoX Liu suspend_stats.failed_resume_noirq); 3902a77c46dSShuoX Liu seq_printf(s, "failures:\n last_failed_dev:\t%-s\n", 3912a77c46dSShuoX Liu suspend_stats.failed_devs[last_dev]); 3922a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 3932a77c46dSShuoX Liu index = last_dev + REC_FAILED_NUM - i; 3942a77c46dSShuoX Liu index %= REC_FAILED_NUM; 3952a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-s\n", 3962a77c46dSShuoX Liu suspend_stats.failed_devs[index]); 3972a77c46dSShuoX Liu } 3982a77c46dSShuoX Liu seq_printf(s, " last_failed_errno:\t%-d\n", 3992a77c46dSShuoX Liu suspend_stats.errno[last_errno]); 4002a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4012a77c46dSShuoX Liu index = last_errno + REC_FAILED_NUM - i; 4022a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4032a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-d\n", 4042a77c46dSShuoX Liu suspend_stats.errno[index]); 4052a77c46dSShuoX Liu } 4062a77c46dSShuoX Liu seq_printf(s, " last_failed_step:\t%-s\n", 4072a77c46dSShuoX Liu suspend_step_name( 4082a77c46dSShuoX Liu suspend_stats.failed_steps[last_step])); 4092a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4102a77c46dSShuoX Liu index = last_step + REC_FAILED_NUM - i; 4112a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4122a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-s\n", 4132a77c46dSShuoX Liu suspend_step_name( 4142a77c46dSShuoX Liu suspend_stats.failed_steps[index])); 4152a77c46dSShuoX Liu } 4162a77c46dSShuoX Liu 4172a77c46dSShuoX Liu return 0; 4182a77c46dSShuoX Liu } 419943a10f8SYangtao Li DEFINE_SHOW_ATTRIBUTE(suspend_stats); 4202a77c46dSShuoX Liu 4212a77c46dSShuoX Liu static int __init pm_debugfs_init(void) 4222a77c46dSShuoX Liu { 4232a77c46dSShuoX Liu debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO, 424943a10f8SYangtao Li NULL, NULL, &suspend_stats_fops); 4252a77c46dSShuoX Liu return 0; 4262a77c46dSShuoX Liu } 4272a77c46dSShuoX Liu 4282a77c46dSShuoX Liu late_initcall(pm_debugfs_init); 4292a77c46dSShuoX Liu #endif /* CONFIG_DEBUG_FS */ 4302a77c46dSShuoX Liu 431ca123102SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 432ca123102SRafael J. Wysocki 433b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 434b2df1d4fSRafael J. Wysocki /* 435b2df1d4fSRafael J. Wysocki * pm_print_times: print time taken by devices to suspend and resume. 436b2df1d4fSRafael J. Wysocki * 437b2df1d4fSRafael J. Wysocki * show() returns whether printing of suspend and resume times is enabled. 438b2df1d4fSRafael J. Wysocki * store() accepts 0 or 1. 0 disables printing and 1 enables it. 439b2df1d4fSRafael J. Wysocki */ 440b2df1d4fSRafael J. Wysocki bool pm_print_times_enabled; 441b2df1d4fSRafael J. Wysocki 442b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_show(struct kobject *kobj, 443b2df1d4fSRafael J. Wysocki struct kobj_attribute *attr, char *buf) 444b2df1d4fSRafael J. Wysocki { 445b2df1d4fSRafael J. Wysocki return sprintf(buf, "%d\n", pm_print_times_enabled); 446b2df1d4fSRafael J. Wysocki } 447b2df1d4fSRafael J. Wysocki 448b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_store(struct kobject *kobj, 449b2df1d4fSRafael J. Wysocki struct kobj_attribute *attr, 450b2df1d4fSRafael J. Wysocki const char *buf, size_t n) 451b2df1d4fSRafael J. Wysocki { 452b2df1d4fSRafael J. Wysocki unsigned long val; 453b2df1d4fSRafael J. Wysocki 454b2df1d4fSRafael J. Wysocki if (kstrtoul(buf, 10, &val)) 455b2df1d4fSRafael J. Wysocki return -EINVAL; 456b2df1d4fSRafael J. Wysocki 457b2df1d4fSRafael J. Wysocki if (val > 1) 458b2df1d4fSRafael J. Wysocki return -EINVAL; 459b2df1d4fSRafael J. Wysocki 460b2df1d4fSRafael J. Wysocki pm_print_times_enabled = !!val; 461b2df1d4fSRafael J. Wysocki return n; 462b2df1d4fSRafael J. Wysocki } 463b2df1d4fSRafael J. Wysocki 464b2df1d4fSRafael J. Wysocki power_attr(pm_print_times); 465b2df1d4fSRafael J. Wysocki 466b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) 467b2df1d4fSRafael J. Wysocki { 468b2df1d4fSRafael J. Wysocki pm_print_times_enabled = !!initcall_debug; 469b2df1d4fSRafael J. Wysocki } 470a6f5f0ddSAlexandra Yates 471a6f5f0ddSAlexandra Yates static ssize_t pm_wakeup_irq_show(struct kobject *kobj, 472a6f5f0ddSAlexandra Yates struct kobj_attribute *attr, 473a6f5f0ddSAlexandra Yates char *buf) 474a6f5f0ddSAlexandra Yates { 475a6f5f0ddSAlexandra Yates return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA; 476a6f5f0ddSAlexandra Yates } 477a6f5f0ddSAlexandra Yates 478a1e9ca69SRafael J. Wysocki power_attr_ro(pm_wakeup_irq); 479a6f5f0ddSAlexandra Yates 480726fb6b4SSrinivas Pandruvada bool pm_debug_messages_on __read_mostly; 4818d8b2441SRafael J. Wysocki 4828d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_show(struct kobject *kobj, 4838d8b2441SRafael J. Wysocki struct kobj_attribute *attr, char *buf) 4848d8b2441SRafael J. Wysocki { 4858d8b2441SRafael J. Wysocki return sprintf(buf, "%d\n", pm_debug_messages_on); 4868d8b2441SRafael J. Wysocki } 4878d8b2441SRafael J. Wysocki 4888d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_store(struct kobject *kobj, 4898d8b2441SRafael J. Wysocki struct kobj_attribute *attr, 4908d8b2441SRafael J. Wysocki const char *buf, size_t n) 4918d8b2441SRafael J. Wysocki { 4928d8b2441SRafael J. Wysocki unsigned long val; 4938d8b2441SRafael J. Wysocki 4948d8b2441SRafael J. Wysocki if (kstrtoul(buf, 10, &val)) 4958d8b2441SRafael J. Wysocki return -EINVAL; 4968d8b2441SRafael J. Wysocki 4978d8b2441SRafael J. Wysocki if (val > 1) 4988d8b2441SRafael J. Wysocki return -EINVAL; 4998d8b2441SRafael J. Wysocki 5008d8b2441SRafael J. Wysocki pm_debug_messages_on = !!val; 5018d8b2441SRafael J. Wysocki return n; 5028d8b2441SRafael J. Wysocki } 5038d8b2441SRafael J. Wysocki 5048d8b2441SRafael J. Wysocki power_attr(pm_debug_messages); 5058d8b2441SRafael J. Wysocki 5068d8b2441SRafael J. Wysocki /** 507cb08e035SRafael J. Wysocki * __pm_pr_dbg - Print a suspend debug message to the kernel log. 508cb08e035SRafael J. Wysocki * @defer: Whether or not to use printk_deferred() to print the message. 5098d8b2441SRafael J. Wysocki * @fmt: Message format. 5108d8b2441SRafael J. Wysocki * 5118d8b2441SRafael J. Wysocki * The message will be emitted if enabled through the pm_debug_messages 5128d8b2441SRafael J. Wysocki * sysfs attribute. 5138d8b2441SRafael J. Wysocki */ 514cb08e035SRafael J. Wysocki void __pm_pr_dbg(bool defer, const char *fmt, ...) 5158d8b2441SRafael J. Wysocki { 5168d8b2441SRafael J. Wysocki struct va_format vaf; 5178d8b2441SRafael J. Wysocki va_list args; 5188d8b2441SRafael J. Wysocki 5198d8b2441SRafael J. Wysocki if (!pm_debug_messages_on) 5208d8b2441SRafael J. Wysocki return; 5218d8b2441SRafael J. Wysocki 5228d8b2441SRafael J. Wysocki va_start(args, fmt); 5238d8b2441SRafael J. Wysocki 5248d8b2441SRafael J. Wysocki vaf.fmt = fmt; 5258d8b2441SRafael J. Wysocki vaf.va = &args; 5268d8b2441SRafael J. Wysocki 527cb08e035SRafael J. Wysocki if (defer) 528cb08e035SRafael J. Wysocki printk_deferred(KERN_DEBUG "PM: %pV", &vaf); 529cb08e035SRafael J. Wysocki else 5308d8b2441SRafael J. Wysocki printk(KERN_DEBUG "PM: %pV", &vaf); 5318d8b2441SRafael J. Wysocki 5328d8b2441SRafael J. Wysocki va_end(args); 5338d8b2441SRafael J. Wysocki } 5348d8b2441SRafael J. Wysocki 535819b1bb3SRafael J. Wysocki #else /* !CONFIG_PM_SLEEP_DEBUG */ 536b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) {} 537b2df1d4fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */ 538b2df1d4fSRafael J. Wysocki 539d76e15fbSGreg Kroah-Hartman struct kobject *power_kobj; 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds /** 5420399d4dbSRafael J. Wysocki * state - control system sleep states. 5431da177e4SLinus Torvalds * 5440399d4dbSRafael J. Wysocki * show() returns available sleep state labels, which may be "mem", "standby", 54544348e8aSMauro Carvalho Chehab * "freeze" and "disk" (hibernation). 54644348e8aSMauro Carvalho Chehab * See Documentation/admin-guide/pm/sleep-states.rst for a description of 54744348e8aSMauro Carvalho Chehab * what they mean. 5481da177e4SLinus Torvalds * 5490399d4dbSRafael J. Wysocki * store() accepts one of those strings, translates it into the proper 5500399d4dbSRafael J. Wysocki * enumerated value, and initiates a suspend transition. 5511da177e4SLinus Torvalds */ 552386f275fSKay Sievers static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, 553386f275fSKay Sievers char *buf) 5541da177e4SLinus Torvalds { 5551da177e4SLinus Torvalds char *s = buf; 556296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 55727ddcc65SRafael J. Wysocki suspend_state_t i; 5581da177e4SLinus Torvalds 55927ddcc65SRafael J. Wysocki for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) 560d431cbc5SRafael J. Wysocki if (pm_states[i]) 561d431cbc5SRafael J. Wysocki s += sprintf(s,"%s ", pm_states[i]); 56227ddcc65SRafael J. Wysocki 563296699deSRafael J. Wysocki #endif 564a6e15a39SKees Cook if (hibernation_available()) 565a6e15a39SKees Cook s += sprintf(s, "disk "); 566a3d25c27SRafael J. Wysocki if (s != buf) 567a3d25c27SRafael J. Wysocki /* convert the last space to a newline */ 568a3d25c27SRafael J. Wysocki *(s-1) = '\n'; 5691da177e4SLinus Torvalds return (s - buf); 5701da177e4SLinus Torvalds } 5711da177e4SLinus Torvalds 5727483b4a4SRafael J. Wysocki static suspend_state_t decode_state(const char *buf, size_t n) 5731da177e4SLinus Torvalds { 574296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 575d431cbc5SRafael J. Wysocki suspend_state_t state; 576296699deSRafael J. Wysocki #endif 5771da177e4SLinus Torvalds char *p; 5781da177e4SLinus Torvalds int len; 5791da177e4SLinus Torvalds 5801da177e4SLinus Torvalds p = memchr(buf, '\n', n); 5811da177e4SLinus Torvalds len = p ? p - buf : n; 5821da177e4SLinus Torvalds 5837483b4a4SRafael J. Wysocki /* Check hibernation first. */ 584d30bdfc0SChuhong Yuan if (len == 4 && str_has_prefix(buf, "disk")) 5857483b4a4SRafael J. Wysocki return PM_SUSPEND_MAX; 586a3d25c27SRafael J. Wysocki 587296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 588d431cbc5SRafael J. Wysocki for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) { 589d431cbc5SRafael J. Wysocki const char *label = pm_states[state]; 590d431cbc5SRafael J. Wysocki 591d431cbc5SRafael J. Wysocki if (label && len == strlen(label) && !strncmp(buf, label, len)) 592d431cbc5SRafael J. Wysocki return state; 593d431cbc5SRafael J. Wysocki } 594296699deSRafael J. Wysocki #endif 595296699deSRafael J. Wysocki 5967483b4a4SRafael J. Wysocki return PM_SUSPEND_ON; 5977483b4a4SRafael J. Wysocki } 5987483b4a4SRafael J. Wysocki 5997483b4a4SRafael J. Wysocki static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, 6007483b4a4SRafael J. Wysocki const char *buf, size_t n) 6017483b4a4SRafael J. Wysocki { 6027483b4a4SRafael J. Wysocki suspend_state_t state; 6037483b4a4SRafael J. Wysocki int error; 6047483b4a4SRafael J. Wysocki 6057483b4a4SRafael J. Wysocki error = pm_autosleep_lock(); 6067483b4a4SRafael J. Wysocki if (error) 6077483b4a4SRafael J. Wysocki return error; 6087483b4a4SRafael J. Wysocki 6097483b4a4SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 6107483b4a4SRafael J. Wysocki error = -EBUSY; 6117483b4a4SRafael J. Wysocki goto out; 6127483b4a4SRafael J. Wysocki } 6137483b4a4SRafael J. Wysocki 6147483b4a4SRafael J. Wysocki state = decode_state(buf, n); 615406e7938SRafael J. Wysocki if (state < PM_SUSPEND_MAX) { 616406e7938SRafael J. Wysocki if (state == PM_SUSPEND_MEM) 617406e7938SRafael J. Wysocki state = mem_sleep_current; 618406e7938SRafael J. Wysocki 6197483b4a4SRafael J. Wysocki error = pm_suspend(state); 620406e7938SRafael J. Wysocki } else if (state == PM_SUSPEND_MAX) { 6217483b4a4SRafael J. Wysocki error = hibernate(); 622406e7938SRafael J. Wysocki } else { 6237483b4a4SRafael J. Wysocki error = -EINVAL; 624406e7938SRafael J. Wysocki } 6257483b4a4SRafael J. Wysocki 6267483b4a4SRafael J. Wysocki out: 6277483b4a4SRafael J. Wysocki pm_autosleep_unlock(); 6281da177e4SLinus Torvalds return error ? error : n; 6291da177e4SLinus Torvalds } 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds power_attr(state); 6321da177e4SLinus Torvalds 633c125e96fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 634c125e96fSRafael J. Wysocki /* 635c125e96fSRafael J. Wysocki * The 'wakeup_count' attribute, along with the functions defined in 636c125e96fSRafael J. Wysocki * drivers/base/power/wakeup.c, provides a means by which wakeup events can be 637c125e96fSRafael J. Wysocki * handled in a non-racy way. 638c125e96fSRafael J. Wysocki * 639c125e96fSRafael J. Wysocki * If a wakeup event occurs when the system is in a sleep state, it simply is 640c125e96fSRafael J. Wysocki * woken up. In turn, if an event that would wake the system up from a sleep 641c125e96fSRafael J. Wysocki * state occurs when it is undergoing a transition to that sleep state, the 642c125e96fSRafael J. Wysocki * transition should be aborted. Moreover, if such an event occurs when the 643c125e96fSRafael J. Wysocki * system is in the working state, an attempt to start a transition to the 644c125e96fSRafael J. Wysocki * given sleep state should fail during certain period after the detection of 645c125e96fSRafael J. Wysocki * the event. Using the 'state' attribute alone is not sufficient to satisfy 646c125e96fSRafael J. Wysocki * these requirements, because a wakeup event may occur exactly when 'state' 647c125e96fSRafael J. Wysocki * is being written to and may be delivered to user space right before it is 648c125e96fSRafael J. Wysocki * frozen, so the event will remain only partially processed until the system is 649c125e96fSRafael J. Wysocki * woken up by another event. In particular, it won't cause the transition to 650c125e96fSRafael J. Wysocki * a sleep state to be aborted. 651c125e96fSRafael J. Wysocki * 652c125e96fSRafael J. Wysocki * This difficulty may be overcome if user space uses 'wakeup_count' before 653c125e96fSRafael J. Wysocki * writing to 'state'. It first should read from 'wakeup_count' and store 654c125e96fSRafael J. Wysocki * the read value. Then, after carrying out its own preparations for the system 655c125e96fSRafael J. Wysocki * transition to a sleep state, it should write the stored value to 65625985edcSLucas De Marchi * 'wakeup_count'. If that fails, at least one wakeup event has occurred since 657c125e96fSRafael J. Wysocki * 'wakeup_count' was read and 'state' should not be written to. Otherwise, it 658c125e96fSRafael J. Wysocki * is allowed to write to 'state', but the transition will be aborted if there 659c125e96fSRafael J. Wysocki * are any wakeup events detected after 'wakeup_count' was written to. 660c125e96fSRafael J. Wysocki */ 661c125e96fSRafael J. Wysocki 662c125e96fSRafael J. Wysocki static ssize_t wakeup_count_show(struct kobject *kobj, 663c125e96fSRafael J. Wysocki struct kobj_attribute *attr, 664c125e96fSRafael J. Wysocki char *buf) 665c125e96fSRafael J. Wysocki { 666074037ecSRafael J. Wysocki unsigned int val; 667c125e96fSRafael J. Wysocki 6687483b4a4SRafael J. Wysocki return pm_get_wakeup_count(&val, true) ? 6697483b4a4SRafael J. Wysocki sprintf(buf, "%u\n", val) : -EINTR; 670c125e96fSRafael J. Wysocki } 671c125e96fSRafael J. Wysocki 672c125e96fSRafael J. Wysocki static ssize_t wakeup_count_store(struct kobject *kobj, 673c125e96fSRafael J. Wysocki struct kobj_attribute *attr, 674c125e96fSRafael J. Wysocki const char *buf, size_t n) 675c125e96fSRafael J. Wysocki { 676074037ecSRafael J. Wysocki unsigned int val; 6777483b4a4SRafael J. Wysocki int error; 678c125e96fSRafael J. Wysocki 6797483b4a4SRafael J. Wysocki error = pm_autosleep_lock(); 6807483b4a4SRafael J. Wysocki if (error) 6817483b4a4SRafael J. Wysocki return error; 6827483b4a4SRafael J. Wysocki 6837483b4a4SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 6847483b4a4SRafael J. Wysocki error = -EBUSY; 6857483b4a4SRafael J. Wysocki goto out; 6867483b4a4SRafael J. Wysocki } 6877483b4a4SRafael J. Wysocki 6887483b4a4SRafael J. Wysocki error = -EINVAL; 689074037ecSRafael J. Wysocki if (sscanf(buf, "%u", &val) == 1) { 690c125e96fSRafael J. Wysocki if (pm_save_wakeup_count(val)) 6917483b4a4SRafael J. Wysocki error = n; 692bb177fedSJulius Werner else 693bb177fedSJulius Werner pm_print_active_wakeup_sources(); 694c125e96fSRafael J. Wysocki } 6957483b4a4SRafael J. Wysocki 6967483b4a4SRafael J. Wysocki out: 6977483b4a4SRafael J. Wysocki pm_autosleep_unlock(); 6987483b4a4SRafael J. Wysocki return error; 699c125e96fSRafael J. Wysocki } 700c125e96fSRafael J. Wysocki 701c125e96fSRafael J. Wysocki power_attr(wakeup_count); 7027483b4a4SRafael J. Wysocki 7037483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP 7047483b4a4SRafael J. Wysocki static ssize_t autosleep_show(struct kobject *kobj, 7057483b4a4SRafael J. Wysocki struct kobj_attribute *attr, 7067483b4a4SRafael J. Wysocki char *buf) 7077483b4a4SRafael J. Wysocki { 7087483b4a4SRafael J. Wysocki suspend_state_t state = pm_autosleep_state(); 7097483b4a4SRafael J. Wysocki 7107483b4a4SRafael J. Wysocki if (state == PM_SUSPEND_ON) 7117483b4a4SRafael J. Wysocki return sprintf(buf, "off\n"); 7127483b4a4SRafael J. Wysocki 7137483b4a4SRafael J. Wysocki #ifdef CONFIG_SUSPEND 7147483b4a4SRafael J. Wysocki if (state < PM_SUSPEND_MAX) 715d431cbc5SRafael J. Wysocki return sprintf(buf, "%s\n", pm_states[state] ? 716d431cbc5SRafael J. Wysocki pm_states[state] : "error"); 7177483b4a4SRafael J. Wysocki #endif 7187483b4a4SRafael J. Wysocki #ifdef CONFIG_HIBERNATION 7197483b4a4SRafael J. Wysocki return sprintf(buf, "disk\n"); 7207483b4a4SRafael J. Wysocki #else 7217483b4a4SRafael J. Wysocki return sprintf(buf, "error"); 7227483b4a4SRafael J. Wysocki #endif 7237483b4a4SRafael J. Wysocki } 7247483b4a4SRafael J. Wysocki 7257483b4a4SRafael J. Wysocki static ssize_t autosleep_store(struct kobject *kobj, 7267483b4a4SRafael J. Wysocki struct kobj_attribute *attr, 7277483b4a4SRafael J. Wysocki const char *buf, size_t n) 7287483b4a4SRafael J. Wysocki { 7297483b4a4SRafael J. Wysocki suspend_state_t state = decode_state(buf, n); 7307483b4a4SRafael J. Wysocki int error; 7317483b4a4SRafael J. Wysocki 7327483b4a4SRafael J. Wysocki if (state == PM_SUSPEND_ON 733040e5bf6SArve Hjønnevåg && strcmp(buf, "off") && strcmp(buf, "off\n")) 7347483b4a4SRafael J. Wysocki return -EINVAL; 7357483b4a4SRafael J. Wysocki 736406e7938SRafael J. Wysocki if (state == PM_SUSPEND_MEM) 737406e7938SRafael J. Wysocki state = mem_sleep_current; 738406e7938SRafael J. Wysocki 7397483b4a4SRafael J. Wysocki error = pm_autosleep_set_state(state); 7407483b4a4SRafael J. Wysocki return error ? error : n; 7417483b4a4SRafael J. Wysocki } 7427483b4a4SRafael J. Wysocki 7437483b4a4SRafael J. Wysocki power_attr(autosleep); 7447483b4a4SRafael J. Wysocki #endif /* CONFIG_PM_AUTOSLEEP */ 745b86ff982SRafael J. Wysocki 746b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS 747b86ff982SRafael J. Wysocki static ssize_t wake_lock_show(struct kobject *kobj, 748b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 749b86ff982SRafael J. Wysocki char *buf) 750b86ff982SRafael J. Wysocki { 751b86ff982SRafael J. Wysocki return pm_show_wakelocks(buf, true); 752b86ff982SRafael J. Wysocki } 753b86ff982SRafael J. Wysocki 754b86ff982SRafael J. Wysocki static ssize_t wake_lock_store(struct kobject *kobj, 755b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 756b86ff982SRafael J. Wysocki const char *buf, size_t n) 757b86ff982SRafael J. Wysocki { 758b86ff982SRafael J. Wysocki int error = pm_wake_lock(buf); 759b86ff982SRafael J. Wysocki return error ? error : n; 760b86ff982SRafael J. Wysocki } 761b86ff982SRafael J. Wysocki 762b86ff982SRafael J. Wysocki power_attr(wake_lock); 763b86ff982SRafael J. Wysocki 764b86ff982SRafael J. Wysocki static ssize_t wake_unlock_show(struct kobject *kobj, 765b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 766b86ff982SRafael J. Wysocki char *buf) 767b86ff982SRafael J. Wysocki { 768b86ff982SRafael J. Wysocki return pm_show_wakelocks(buf, false); 769b86ff982SRafael J. Wysocki } 770b86ff982SRafael J. Wysocki 771b86ff982SRafael J. Wysocki static ssize_t wake_unlock_store(struct kobject *kobj, 772b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 773b86ff982SRafael J. Wysocki const char *buf, size_t n) 774b86ff982SRafael J. Wysocki { 775b86ff982SRafael J. Wysocki int error = pm_wake_unlock(buf); 776b86ff982SRafael J. Wysocki return error ? error : n; 777b86ff982SRafael J. Wysocki } 778b86ff982SRafael J. Wysocki 779b86ff982SRafael J. Wysocki power_attr(wake_unlock); 780b86ff982SRafael J. Wysocki 781b86ff982SRafael J. Wysocki #endif /* CONFIG_PM_WAKELOCKS */ 782c125e96fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 783c125e96fSRafael J. Wysocki 784c5c6ba4eSRafael J. Wysocki #ifdef CONFIG_PM_TRACE 785c5c6ba4eSRafael J. Wysocki int pm_trace_enabled; 786c5c6ba4eSRafael J. Wysocki 787386f275fSKay Sievers static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr, 788386f275fSKay Sievers char *buf) 789c5c6ba4eSRafael J. Wysocki { 790c5c6ba4eSRafael J. Wysocki return sprintf(buf, "%d\n", pm_trace_enabled); 791c5c6ba4eSRafael J. Wysocki } 792c5c6ba4eSRafael J. Wysocki 793c5c6ba4eSRafael J. Wysocki static ssize_t 794386f275fSKay Sievers pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr, 795386f275fSKay Sievers const char *buf, size_t n) 796c5c6ba4eSRafael J. Wysocki { 797c5c6ba4eSRafael J. Wysocki int val; 798c5c6ba4eSRafael J. Wysocki 799c5c6ba4eSRafael J. Wysocki if (sscanf(buf, "%d", &val) == 1) { 800c5c6ba4eSRafael J. Wysocki pm_trace_enabled = !!val; 8019dceefe4SShuah Khan if (pm_trace_enabled) { 8029dceefe4SShuah Khan pr_warn("PM: Enabling pm_trace changes system date and time during resume.\n" 8039dceefe4SShuah Khan "PM: Correct system time has to be restored manually after resume.\n"); 8049dceefe4SShuah Khan } 805c5c6ba4eSRafael J. Wysocki return n; 806c5c6ba4eSRafael J. Wysocki } 807c5c6ba4eSRafael J. Wysocki return -EINVAL; 808c5c6ba4eSRafael J. Wysocki } 809c5c6ba4eSRafael J. Wysocki 810c5c6ba4eSRafael J. Wysocki power_attr(pm_trace); 811d33ac60bSJames Hogan 812d33ac60bSJames Hogan static ssize_t pm_trace_dev_match_show(struct kobject *kobj, 813d33ac60bSJames Hogan struct kobj_attribute *attr, 814d33ac60bSJames Hogan char *buf) 815d33ac60bSJames Hogan { 816d33ac60bSJames Hogan return show_trace_dev_match(buf, PAGE_SIZE); 817d33ac60bSJames Hogan } 818d33ac60bSJames Hogan 819a1e9ca69SRafael J. Wysocki power_attr_ro(pm_trace_dev_match); 820d33ac60bSJames Hogan 8210e7d56e3SRafael J. Wysocki #endif /* CONFIG_PM_TRACE */ 822c5c6ba4eSRafael J. Wysocki 823957d1282SLi Fei #ifdef CONFIG_FREEZER 824957d1282SLi Fei static ssize_t pm_freeze_timeout_show(struct kobject *kobj, 825957d1282SLi Fei struct kobj_attribute *attr, char *buf) 826957d1282SLi Fei { 827957d1282SLi Fei return sprintf(buf, "%u\n", freeze_timeout_msecs); 828957d1282SLi Fei } 829957d1282SLi Fei 830957d1282SLi Fei static ssize_t pm_freeze_timeout_store(struct kobject *kobj, 831957d1282SLi Fei struct kobj_attribute *attr, 832957d1282SLi Fei const char *buf, size_t n) 833957d1282SLi Fei { 834957d1282SLi Fei unsigned long val; 835957d1282SLi Fei 836957d1282SLi Fei if (kstrtoul(buf, 10, &val)) 837957d1282SLi Fei return -EINVAL; 838957d1282SLi Fei 839957d1282SLi Fei freeze_timeout_msecs = val; 840957d1282SLi Fei return n; 841957d1282SLi Fei } 842957d1282SLi Fei 843957d1282SLi Fei power_attr(pm_freeze_timeout); 844957d1282SLi Fei 845957d1282SLi Fei #endif /* CONFIG_FREEZER*/ 846957d1282SLi Fei 847c5c6ba4eSRafael J. Wysocki static struct attribute * g[] = { 848c5c6ba4eSRafael J. Wysocki &state_attr.attr, 8490e7d56e3SRafael J. Wysocki #ifdef CONFIG_PM_TRACE 850c5c6ba4eSRafael J. Wysocki &pm_trace_attr.attr, 851d33ac60bSJames Hogan &pm_trace_dev_match_attr.attr, 8520e7d56e3SRafael J. Wysocki #endif 8530e06b4a8SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 8540e06b4a8SRafael J. Wysocki &pm_async_attr.attr, 855c125e96fSRafael J. Wysocki &wakeup_count_attr.attr, 856406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND 857406e7938SRafael J. Wysocki &mem_sleep_attr.attr, 858406e7938SRafael J. Wysocki #endif 8597483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP 8607483b4a4SRafael J. Wysocki &autosleep_attr.attr, 8617483b4a4SRafael J. Wysocki #endif 862b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS 863b86ff982SRafael J. Wysocki &wake_lock_attr.attr, 864b86ff982SRafael J. Wysocki &wake_unlock_attr.attr, 865b86ff982SRafael J. Wysocki #endif 866b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 867e516a1dbSRafael J. Wysocki &pm_test_attr.attr, 8684b7760baSSameer Nanda &pm_print_times_attr.attr, 869a6f5f0ddSAlexandra Yates &pm_wakeup_irq_attr.attr, 8708d8b2441SRafael J. Wysocki &pm_debug_messages_attr.attr, 8710e7d56e3SRafael J. Wysocki #endif 8720e06b4a8SRafael J. Wysocki #endif 873957d1282SLi Fei #ifdef CONFIG_FREEZER 874957d1282SLi Fei &pm_freeze_timeout_attr.attr, 875957d1282SLi Fei #endif 876c5c6ba4eSRafael J. Wysocki NULL, 877c5c6ba4eSRafael J. Wysocki }; 8781da177e4SLinus Torvalds 8791d0c6e59SArvind Yadav static const struct attribute_group attr_group = { 8801da177e4SLinus Torvalds .attrs = g, 8811da177e4SLinus Torvalds }; 8821da177e4SLinus Torvalds 8832c8db5beSKalesh Singh static const struct attribute_group *attr_groups[] = { 8842c8db5beSKalesh Singh &attr_group, 8852c8db5beSKalesh Singh #ifdef CONFIG_PM_SLEEP 8862c8db5beSKalesh Singh &suspend_attr_group, 8872c8db5beSKalesh Singh #endif 8882c8db5beSKalesh Singh NULL, 8892c8db5beSKalesh Singh }; 8902c8db5beSKalesh Singh 8915e928f77SRafael J. Wysocki struct workqueue_struct *pm_wq; 8927b199ca2SAlan Stern EXPORT_SYMBOL_GPL(pm_wq); 8935e928f77SRafael J. Wysocki 8945e928f77SRafael J. Wysocki static int __init pm_start_workqueue(void) 8955e928f77SRafael J. Wysocki { 89658a69cb4STejun Heo pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0); 8975e928f77SRafael J. Wysocki 8985e928f77SRafael J. Wysocki return pm_wq ? 0 : -ENOMEM; 8995e928f77SRafael J. Wysocki } 9005e928f77SRafael J. Wysocki 9011da177e4SLinus Torvalds static int __init pm_init(void) 9021da177e4SLinus Torvalds { 9035e928f77SRafael J. Wysocki int error = pm_start_workqueue(); 9045e928f77SRafael J. Wysocki if (error) 9055e928f77SRafael J. Wysocki return error; 906ac5c24ecSRafael J. Wysocki hibernate_image_size_init(); 907ddeb6487SRafael J. Wysocki hibernate_reserved_size_init(); 908fa7fd6faSSudeep Holla pm_states_init(); 909d76e15fbSGreg Kroah-Hartman power_kobj = kobject_create_and_add("power", NULL); 910d76e15fbSGreg Kroah-Hartman if (!power_kobj) 911039a5dcdSGreg Kroah-Hartman return -ENOMEM; 9122c8db5beSKalesh Singh error = sysfs_create_groups(power_kobj, attr_groups); 9137483b4a4SRafael J. Wysocki if (error) 9147483b4a4SRafael J. Wysocki return error; 915b2df1d4fSRafael J. Wysocki pm_print_times_init(); 9167483b4a4SRafael J. Wysocki return pm_autosleep_init(); 9171da177e4SLinus Torvalds } 9181da177e4SLinus Torvalds 9191da177e4SLinus Torvalds core_initcall(pm_init); 920