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> 18f49249d5SBen 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 24*5950e5d5SPeter Zijlstra unsigned int lock_system_sleep(void) 254bf236a3SBart Van Assche { 26*5950e5d5SPeter Zijlstra unsigned int flags = current->flags; 274bf236a3SBart Van Assche current->flags |= PF_FREEZER_SKIP; 2855f2503cSPingfan Liu mutex_lock(&system_transition_mutex); 29*5950e5d5SPeter Zijlstra return flags; 304bf236a3SBart Van Assche } 314bf236a3SBart Van Assche EXPORT_SYMBOL_GPL(lock_system_sleep); 324bf236a3SBart Van Assche 33*5950e5d5SPeter Zijlstra void unlock_system_sleep(unsigned int flags) 344bf236a3SBart Van Assche { 354bf236a3SBart Van Assche /* 364bf236a3SBart Van Assche * Don't use freezer_count() because we don't want the call to 374bf236a3SBart Van Assche * try_to_freeze() here. 384bf236a3SBart Van Assche * 394bf236a3SBart Van Assche * Reason: 404bf236a3SBart Van Assche * Fundamentally, we just don't need it, because freezing condition 4155f2503cSPingfan Liu * doesn't come into effect until we release the 4255f2503cSPingfan Liu * system_transition_mutex lock, since the freezer always works with 4355f2503cSPingfan Liu * system_transition_mutex held. 444bf236a3SBart Van Assche * 454bf236a3SBart Van Assche * More importantly, in the case of hibernation, 464bf236a3SBart Van Assche * unlock_system_sleep() gets called in snapshot_read() and 474bf236a3SBart Van Assche * snapshot_write() when the freezing condition is still in effect. 484bf236a3SBart Van Assche * Which means, if we use try_to_freeze() here, it would make them 494bf236a3SBart Van Assche * enter the refrigerator, thus causing hibernation to lockup. 504bf236a3SBart Van Assche */ 51*5950e5d5SPeter Zijlstra if (!(flags & PF_FREEZER_SKIP)) 524bf236a3SBart Van Assche current->flags &= ~PF_FREEZER_SKIP; 5355f2503cSPingfan Liu mutex_unlock(&system_transition_mutex); 544bf236a3SBart Van Assche } 554bf236a3SBart Van Assche EXPORT_SYMBOL_GPL(unlock_system_sleep); 564bf236a3SBart Van Assche 57b5dee313SHarry Pan void ksys_sync_helper(void) 58b5dee313SHarry Pan { 59c64546b1SHarry Pan ktime_t start; 60c64546b1SHarry Pan long elapsed_msecs; 61c64546b1SHarry Pan 62c64546b1SHarry Pan start = ktime_get(); 63b5dee313SHarry Pan ksys_sync(); 64c64546b1SHarry Pan elapsed_msecs = ktime_to_ms(ktime_sub(ktime_get(), start)); 65c64546b1SHarry Pan pr_info("Filesystems sync: %ld.%03ld seconds\n", 66c64546b1SHarry Pan elapsed_msecs / MSEC_PER_SEC, elapsed_msecs % MSEC_PER_SEC); 67b5dee313SHarry Pan } 68b5dee313SHarry Pan EXPORT_SYMBOL_GPL(ksys_sync_helper); 69b5dee313SHarry Pan 7082525756SAlan Stern /* Routines for PM-transition notifications */ 7182525756SAlan Stern 7282525756SAlan Stern static BLOCKING_NOTIFIER_HEAD(pm_chain_head); 7382525756SAlan Stern 7482525756SAlan Stern int register_pm_notifier(struct notifier_block *nb) 7582525756SAlan Stern { 7682525756SAlan Stern return blocking_notifier_chain_register(&pm_chain_head, nb); 7782525756SAlan Stern } 7882525756SAlan Stern EXPORT_SYMBOL_GPL(register_pm_notifier); 7982525756SAlan Stern 8082525756SAlan Stern int unregister_pm_notifier(struct notifier_block *nb) 8182525756SAlan Stern { 8282525756SAlan Stern return blocking_notifier_chain_unregister(&pm_chain_head, nb); 8382525756SAlan Stern } 8482525756SAlan Stern EXPORT_SYMBOL_GPL(unregister_pm_notifier); 8582525756SAlan Stern 8670d93298SPeter Zijlstra int pm_notifier_call_chain_robust(unsigned long val_up, unsigned long val_down) 8782525756SAlan Stern { 88ea00f4f4SLianwei Wang int ret; 89ea00f4f4SLianwei Wang 9070d93298SPeter Zijlstra ret = blocking_notifier_call_chain_robust(&pm_chain_head, val_up, val_down, NULL); 91f0c077a8SAkinobu Mita 92f0c077a8SAkinobu Mita return notifier_to_errno(ret); 9382525756SAlan Stern } 9470d93298SPeter Zijlstra 95ea00f4f4SLianwei Wang int pm_notifier_call_chain(unsigned long val) 96ea00f4f4SLianwei Wang { 9770d93298SPeter Zijlstra return blocking_notifier_call_chain(&pm_chain_head, val, NULL); 98ea00f4f4SLianwei Wang } 9982525756SAlan Stern 1000e06b4a8SRafael J. Wysocki /* If set, devices may be suspended and resumed asynchronously. */ 1010e06b4a8SRafael J. Wysocki int pm_async_enabled = 1; 1020e06b4a8SRafael J. Wysocki 1030e06b4a8SRafael J. Wysocki static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr, 1040e06b4a8SRafael J. Wysocki char *buf) 1050e06b4a8SRafael J. Wysocki { 1060e06b4a8SRafael J. Wysocki return sprintf(buf, "%d\n", pm_async_enabled); 1070e06b4a8SRafael J. Wysocki } 1080e06b4a8SRafael J. Wysocki 1090e06b4a8SRafael J. Wysocki static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr, 1100e06b4a8SRafael J. Wysocki const char *buf, size_t n) 1110e06b4a8SRafael J. Wysocki { 1120e06b4a8SRafael J. Wysocki unsigned long val; 1130e06b4a8SRafael J. Wysocki 114883ee4f7SDaniel Walter if (kstrtoul(buf, 10, &val)) 1150e06b4a8SRafael J. Wysocki return -EINVAL; 1160e06b4a8SRafael J. Wysocki 1170e06b4a8SRafael J. Wysocki if (val > 1) 1180e06b4a8SRafael J. Wysocki return -EINVAL; 1190e06b4a8SRafael J. Wysocki 1200e06b4a8SRafael J. Wysocki pm_async_enabled = val; 1210e06b4a8SRafael J. Wysocki return n; 1220e06b4a8SRafael J. Wysocki } 1230e06b4a8SRafael J. Wysocki 1240e06b4a8SRafael J. Wysocki power_attr(pm_async); 1250e06b4a8SRafael J. Wysocki 126406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND 127406e7938SRafael J. Wysocki static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr, 128406e7938SRafael J. Wysocki char *buf) 129406e7938SRafael J. Wysocki { 130406e7938SRafael J. Wysocki char *s = buf; 131406e7938SRafael J. Wysocki suspend_state_t i; 132406e7938SRafael J. Wysocki 1339ea4dcf4SDan Williams for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) { 1349ea4dcf4SDan Williams if (i >= PM_SUSPEND_MEM && cxl_mem_active()) 1359ea4dcf4SDan Williams continue; 136406e7938SRafael J. Wysocki if (mem_sleep_states[i]) { 137406e7938SRafael J. Wysocki const char *label = mem_sleep_states[i]; 138406e7938SRafael J. Wysocki 139406e7938SRafael J. Wysocki if (mem_sleep_current == i) 140406e7938SRafael J. Wysocki s += sprintf(s, "[%s] ", label); 141406e7938SRafael J. Wysocki else 142406e7938SRafael J. Wysocki s += sprintf(s, "%s ", label); 143406e7938SRafael J. Wysocki } 1449ea4dcf4SDan Williams } 145406e7938SRafael J. Wysocki 146406e7938SRafael J. Wysocki /* Convert the last space to a newline if needed. */ 147406e7938SRafael J. Wysocki if (s != buf) 148406e7938SRafael J. Wysocki *(s-1) = '\n'; 149406e7938SRafael J. Wysocki 150406e7938SRafael J. Wysocki return (s - buf); 151406e7938SRafael J. Wysocki } 152406e7938SRafael J. Wysocki 153406e7938SRafael J. Wysocki static suspend_state_t decode_suspend_state(const char *buf, size_t n) 154406e7938SRafael J. Wysocki { 155406e7938SRafael J. Wysocki suspend_state_t state; 156406e7938SRafael J. Wysocki char *p; 157406e7938SRafael J. Wysocki int len; 158406e7938SRafael J. Wysocki 159406e7938SRafael J. Wysocki p = memchr(buf, '\n', n); 160406e7938SRafael J. Wysocki len = p ? p - buf : n; 161406e7938SRafael J. Wysocki 162406e7938SRafael J. Wysocki for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) { 163406e7938SRafael J. Wysocki const char *label = mem_sleep_states[state]; 164406e7938SRafael J. Wysocki 165406e7938SRafael J. Wysocki if (label && len == strlen(label) && !strncmp(buf, label, len)) 166406e7938SRafael J. Wysocki return state; 167406e7938SRafael J. Wysocki } 168406e7938SRafael J. Wysocki 169406e7938SRafael J. Wysocki return PM_SUSPEND_ON; 170406e7938SRafael J. Wysocki } 171406e7938SRafael J. Wysocki 172406e7938SRafael J. Wysocki static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr, 173406e7938SRafael J. Wysocki const char *buf, size_t n) 174406e7938SRafael J. Wysocki { 175406e7938SRafael J. Wysocki suspend_state_t state; 176406e7938SRafael J. Wysocki int error; 177406e7938SRafael J. Wysocki 178406e7938SRafael J. Wysocki error = pm_autosleep_lock(); 179406e7938SRafael J. Wysocki if (error) 180406e7938SRafael J. Wysocki return error; 181406e7938SRafael J. Wysocki 182406e7938SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 183406e7938SRafael J. Wysocki error = -EBUSY; 184406e7938SRafael J. Wysocki goto out; 185406e7938SRafael J. Wysocki } 186406e7938SRafael J. Wysocki 187406e7938SRafael J. Wysocki state = decode_suspend_state(buf, n); 188406e7938SRafael J. Wysocki if (state < PM_SUSPEND_MAX && state > PM_SUSPEND_ON) 189406e7938SRafael J. Wysocki mem_sleep_current = state; 190406e7938SRafael J. Wysocki else 191406e7938SRafael J. Wysocki error = -EINVAL; 192406e7938SRafael J. Wysocki 193406e7938SRafael J. Wysocki out: 194406e7938SRafael J. Wysocki pm_autosleep_unlock(); 195406e7938SRafael J. Wysocki return error ? error : n; 196406e7938SRafael J. Wysocki } 197406e7938SRafael J. Wysocki 198406e7938SRafael J. Wysocki power_attr(mem_sleep); 199c052bf82SJonas Meurer 200c052bf82SJonas Meurer /* 201c052bf82SJonas Meurer * sync_on_suspend: invoke ksys_sync_helper() before suspend. 202c052bf82SJonas Meurer * 203c052bf82SJonas Meurer * show() returns whether ksys_sync_helper() is invoked before suspend. 204c052bf82SJonas Meurer * store() accepts 0 or 1. 0 disables ksys_sync_helper() and 1 enables it. 205c052bf82SJonas Meurer */ 206c052bf82SJonas Meurer bool sync_on_suspend_enabled = !IS_ENABLED(CONFIG_SUSPEND_SKIP_SYNC); 207c052bf82SJonas Meurer 208c052bf82SJonas Meurer static ssize_t sync_on_suspend_show(struct kobject *kobj, 209c052bf82SJonas Meurer struct kobj_attribute *attr, char *buf) 210c052bf82SJonas Meurer { 211c052bf82SJonas Meurer return sprintf(buf, "%d\n", sync_on_suspend_enabled); 212c052bf82SJonas Meurer } 213c052bf82SJonas Meurer 214c052bf82SJonas Meurer static ssize_t sync_on_suspend_store(struct kobject *kobj, 215c052bf82SJonas Meurer struct kobj_attribute *attr, 216c052bf82SJonas Meurer const char *buf, size_t n) 217c052bf82SJonas Meurer { 218c052bf82SJonas Meurer unsigned long val; 219c052bf82SJonas Meurer 220c052bf82SJonas Meurer if (kstrtoul(buf, 10, &val)) 221c052bf82SJonas Meurer return -EINVAL; 222c052bf82SJonas Meurer 223c052bf82SJonas Meurer if (val > 1) 224c052bf82SJonas Meurer return -EINVAL; 225c052bf82SJonas Meurer 226c052bf82SJonas Meurer sync_on_suspend_enabled = !!val; 227c052bf82SJonas Meurer return n; 228c052bf82SJonas Meurer } 229c052bf82SJonas Meurer 230c052bf82SJonas Meurer power_attr(sync_on_suspend); 231406e7938SRafael J. Wysocki #endif /* CONFIG_SUSPEND */ 232406e7938SRafael J. Wysocki 233e516a1dbSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 2340e7d56e3SRafael J. Wysocki int pm_test_level = TEST_NONE; 2350e7d56e3SRafael J. Wysocki 2360e7d56e3SRafael J. Wysocki static const char * const pm_tests[__TEST_AFTER_LAST] = { 2370e7d56e3SRafael J. Wysocki [TEST_NONE] = "none", 2380e7d56e3SRafael J. Wysocki [TEST_CORE] = "core", 2390e7d56e3SRafael J. Wysocki [TEST_CPUS] = "processors", 2400e7d56e3SRafael J. Wysocki [TEST_PLATFORM] = "platform", 2410e7d56e3SRafael J. Wysocki [TEST_DEVICES] = "devices", 2420e7d56e3SRafael J. Wysocki [TEST_FREEZER] = "freezer", 2430e7d56e3SRafael J. Wysocki }; 2440e7d56e3SRafael J. Wysocki 245039a75c6SRafael J. Wysocki static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr, 246039a75c6SRafael J. Wysocki char *buf) 2470e7d56e3SRafael J. Wysocki { 2480e7d56e3SRafael J. Wysocki char *s = buf; 2490e7d56e3SRafael J. Wysocki int level; 2500e7d56e3SRafael J. Wysocki 2510e7d56e3SRafael J. Wysocki for (level = TEST_FIRST; level <= TEST_MAX; level++) 2520e7d56e3SRafael J. Wysocki if (pm_tests[level]) { 2530e7d56e3SRafael J. Wysocki if (level == pm_test_level) 2540e7d56e3SRafael J. Wysocki s += sprintf(s, "[%s] ", pm_tests[level]); 2550e7d56e3SRafael J. Wysocki else 2560e7d56e3SRafael J. Wysocki s += sprintf(s, "%s ", pm_tests[level]); 2570e7d56e3SRafael J. Wysocki } 2580e7d56e3SRafael J. Wysocki 2590e7d56e3SRafael J. Wysocki if (s != buf) 2600e7d56e3SRafael J. Wysocki /* convert the last space to a newline */ 2610e7d56e3SRafael J. Wysocki *(s-1) = '\n'; 2620e7d56e3SRafael J. Wysocki 2630e7d56e3SRafael J. Wysocki return (s - buf); 2640e7d56e3SRafael J. Wysocki } 2650e7d56e3SRafael J. Wysocki 266039a75c6SRafael J. Wysocki static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, 267039a75c6SRafael J. Wysocki const char *buf, size_t n) 2680e7d56e3SRafael J. Wysocki { 269*5950e5d5SPeter Zijlstra unsigned int sleep_flags; 2700e7d56e3SRafael J. Wysocki const char * const *s; 271*5950e5d5SPeter Zijlstra int error = -EINVAL; 2720e7d56e3SRafael J. Wysocki int level; 2730e7d56e3SRafael J. Wysocki char *p; 2740e7d56e3SRafael J. Wysocki int len; 2750e7d56e3SRafael J. Wysocki 2760e7d56e3SRafael J. Wysocki p = memchr(buf, '\n', n); 2770e7d56e3SRafael J. Wysocki len = p ? p - buf : n; 2780e7d56e3SRafael J. Wysocki 279*5950e5d5SPeter Zijlstra sleep_flags = lock_system_sleep(); 2800e7d56e3SRafael J. Wysocki 2810e7d56e3SRafael J. Wysocki level = TEST_FIRST; 2820e7d56e3SRafael J. Wysocki for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++) 2830e7d56e3SRafael J. Wysocki if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) { 2840e7d56e3SRafael J. Wysocki pm_test_level = level; 2850e7d56e3SRafael J. Wysocki error = 0; 2860e7d56e3SRafael J. Wysocki break; 2870e7d56e3SRafael J. Wysocki } 2880e7d56e3SRafael J. Wysocki 289*5950e5d5SPeter Zijlstra unlock_system_sleep(sleep_flags); 2900e7d56e3SRafael J. Wysocki 2910e7d56e3SRafael J. Wysocki return error ? error : n; 2920e7d56e3SRafael J. Wysocki } 2930e7d56e3SRafael J. Wysocki 2940e7d56e3SRafael J. Wysocki power_attr(pm_test); 295e516a1dbSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */ 2960e7d56e3SRafael J. Wysocki 2972a77c46dSShuoX Liu static char *suspend_step_name(enum suspend_stat_step step) 2982a77c46dSShuoX Liu { 2992a77c46dSShuoX Liu switch (step) { 3002a77c46dSShuoX Liu case SUSPEND_FREEZE: 3012a77c46dSShuoX Liu return "freeze"; 3022a77c46dSShuoX Liu case SUSPEND_PREPARE: 3032a77c46dSShuoX Liu return "prepare"; 3042a77c46dSShuoX Liu case SUSPEND_SUSPEND: 3052a77c46dSShuoX Liu return "suspend"; 3062a77c46dSShuoX Liu case SUSPEND_SUSPEND_NOIRQ: 3072a77c46dSShuoX Liu return "suspend_noirq"; 3082a77c46dSShuoX Liu case SUSPEND_RESUME_NOIRQ: 3092a77c46dSShuoX Liu return "resume_noirq"; 3102a77c46dSShuoX Liu case SUSPEND_RESUME: 3112a77c46dSShuoX Liu return "resume"; 3122a77c46dSShuoX Liu default: 3132a77c46dSShuoX Liu return ""; 3142a77c46dSShuoX Liu } 3152a77c46dSShuoX Liu } 3162a77c46dSShuoX Liu 3172c8db5beSKalesh Singh #define suspend_attr(_name) \ 3182c8db5beSKalesh Singh static ssize_t _name##_show(struct kobject *kobj, \ 3192c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) \ 3202c8db5beSKalesh Singh { \ 3212c8db5beSKalesh Singh return sprintf(buf, "%d\n", suspend_stats._name); \ 3222c8db5beSKalesh Singh } \ 3232c8db5beSKalesh Singh static struct kobj_attribute _name = __ATTR_RO(_name) 3242c8db5beSKalesh Singh 3252c8db5beSKalesh Singh suspend_attr(success); 3262c8db5beSKalesh Singh suspend_attr(fail); 3272c8db5beSKalesh Singh suspend_attr(failed_freeze); 3282c8db5beSKalesh Singh suspend_attr(failed_prepare); 3292c8db5beSKalesh Singh suspend_attr(failed_suspend); 3302c8db5beSKalesh Singh suspend_attr(failed_suspend_late); 3312c8db5beSKalesh Singh suspend_attr(failed_suspend_noirq); 3322c8db5beSKalesh Singh suspend_attr(failed_resume); 3332c8db5beSKalesh Singh suspend_attr(failed_resume_early); 3342c8db5beSKalesh Singh suspend_attr(failed_resume_noirq); 3352c8db5beSKalesh Singh 3362c8db5beSKalesh Singh static ssize_t last_failed_dev_show(struct kobject *kobj, 3372c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 3382c8db5beSKalesh Singh { 3392c8db5beSKalesh Singh int index; 3402c8db5beSKalesh Singh char *last_failed_dev = NULL; 3412c8db5beSKalesh Singh 3422c8db5beSKalesh Singh index = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; 3432c8db5beSKalesh Singh index %= REC_FAILED_NUM; 3442c8db5beSKalesh Singh last_failed_dev = suspend_stats.failed_devs[index]; 3452c8db5beSKalesh Singh 3462c8db5beSKalesh Singh return sprintf(buf, "%s\n", last_failed_dev); 3472c8db5beSKalesh Singh } 3482c8db5beSKalesh Singh static struct kobj_attribute last_failed_dev = __ATTR_RO(last_failed_dev); 3492c8db5beSKalesh Singh 3502c8db5beSKalesh Singh static ssize_t last_failed_errno_show(struct kobject *kobj, 3512c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 3522c8db5beSKalesh Singh { 3532c8db5beSKalesh Singh int index; 3542c8db5beSKalesh Singh int last_failed_errno; 3552c8db5beSKalesh Singh 3562c8db5beSKalesh Singh index = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1; 3572c8db5beSKalesh Singh index %= REC_FAILED_NUM; 3582c8db5beSKalesh Singh last_failed_errno = suspend_stats.errno[index]; 3592c8db5beSKalesh Singh 3602c8db5beSKalesh Singh return sprintf(buf, "%d\n", last_failed_errno); 3612c8db5beSKalesh Singh } 3622c8db5beSKalesh Singh static struct kobj_attribute last_failed_errno = __ATTR_RO(last_failed_errno); 3632c8db5beSKalesh Singh 3642c8db5beSKalesh Singh static ssize_t last_failed_step_show(struct kobject *kobj, 3652c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 3662c8db5beSKalesh Singh { 3672c8db5beSKalesh Singh int index; 3682c8db5beSKalesh Singh enum suspend_stat_step step; 3692c8db5beSKalesh Singh char *last_failed_step = NULL; 3702c8db5beSKalesh Singh 3712c8db5beSKalesh Singh index = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; 3722c8db5beSKalesh Singh index %= REC_FAILED_NUM; 3732c8db5beSKalesh Singh step = suspend_stats.failed_steps[index]; 3742c8db5beSKalesh Singh last_failed_step = suspend_step_name(step); 3752c8db5beSKalesh Singh 3762c8db5beSKalesh Singh return sprintf(buf, "%s\n", last_failed_step); 3772c8db5beSKalesh Singh } 3782c8db5beSKalesh Singh static struct kobj_attribute last_failed_step = __ATTR_RO(last_failed_step); 3792c8db5beSKalesh Singh 3802c8db5beSKalesh Singh static struct attribute *suspend_attrs[] = { 3812c8db5beSKalesh Singh &success.attr, 3822c8db5beSKalesh Singh &fail.attr, 3832c8db5beSKalesh Singh &failed_freeze.attr, 3842c8db5beSKalesh Singh &failed_prepare.attr, 3852c8db5beSKalesh Singh &failed_suspend.attr, 3862c8db5beSKalesh Singh &failed_suspend_late.attr, 3872c8db5beSKalesh Singh &failed_suspend_noirq.attr, 3882c8db5beSKalesh Singh &failed_resume.attr, 3892c8db5beSKalesh Singh &failed_resume_early.attr, 3902c8db5beSKalesh Singh &failed_resume_noirq.attr, 3912c8db5beSKalesh Singh &last_failed_dev.attr, 3922c8db5beSKalesh Singh &last_failed_errno.attr, 3932c8db5beSKalesh Singh &last_failed_step.attr, 3942c8db5beSKalesh Singh NULL, 3952c8db5beSKalesh Singh }; 3962c8db5beSKalesh Singh 39715560574SRikard Falkeborn static const struct attribute_group suspend_attr_group = { 3982c8db5beSKalesh Singh .name = "suspend_stats", 3992c8db5beSKalesh Singh .attrs = suspend_attrs, 4002c8db5beSKalesh Singh }; 4012c8db5beSKalesh Singh 4022c8db5beSKalesh Singh #ifdef CONFIG_DEBUG_FS 4032a77c46dSShuoX Liu static int suspend_stats_show(struct seq_file *s, void *unused) 4042a77c46dSShuoX Liu { 4052a77c46dSShuoX Liu int i, index, last_dev, last_errno, last_step; 4062a77c46dSShuoX Liu 4072a77c46dSShuoX Liu last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; 4082a77c46dSShuoX Liu last_dev %= REC_FAILED_NUM; 4092a77c46dSShuoX Liu last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1; 4102a77c46dSShuoX Liu last_errno %= REC_FAILED_NUM; 4112a77c46dSShuoX Liu last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; 4122a77c46dSShuoX Liu last_step %= REC_FAILED_NUM; 413cf579dfbSRafael J. Wysocki seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n" 414cf579dfbSRafael J. Wysocki "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n", 4152a77c46dSShuoX Liu "success", suspend_stats.success, 4162a77c46dSShuoX Liu "fail", suspend_stats.fail, 4172a77c46dSShuoX Liu "failed_freeze", suspend_stats.failed_freeze, 4182a77c46dSShuoX Liu "failed_prepare", suspend_stats.failed_prepare, 4192a77c46dSShuoX Liu "failed_suspend", suspend_stats.failed_suspend, 420cf579dfbSRafael J. Wysocki "failed_suspend_late", 421cf579dfbSRafael J. Wysocki suspend_stats.failed_suspend_late, 4222a77c46dSShuoX Liu "failed_suspend_noirq", 4232a77c46dSShuoX Liu suspend_stats.failed_suspend_noirq, 4242a77c46dSShuoX Liu "failed_resume", suspend_stats.failed_resume, 425cf579dfbSRafael J. Wysocki "failed_resume_early", 426cf579dfbSRafael J. Wysocki suspend_stats.failed_resume_early, 4272a77c46dSShuoX Liu "failed_resume_noirq", 4282a77c46dSShuoX Liu suspend_stats.failed_resume_noirq); 4292a77c46dSShuoX Liu seq_printf(s, "failures:\n last_failed_dev:\t%-s\n", 4302a77c46dSShuoX Liu suspend_stats.failed_devs[last_dev]); 4312a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4322a77c46dSShuoX Liu index = last_dev + REC_FAILED_NUM - i; 4332a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4342a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-s\n", 4352a77c46dSShuoX Liu suspend_stats.failed_devs[index]); 4362a77c46dSShuoX Liu } 4372a77c46dSShuoX Liu seq_printf(s, " last_failed_errno:\t%-d\n", 4382a77c46dSShuoX Liu suspend_stats.errno[last_errno]); 4392a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4402a77c46dSShuoX Liu index = last_errno + REC_FAILED_NUM - i; 4412a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4422a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-d\n", 4432a77c46dSShuoX Liu suspend_stats.errno[index]); 4442a77c46dSShuoX Liu } 4452a77c46dSShuoX Liu seq_printf(s, " last_failed_step:\t%-s\n", 4462a77c46dSShuoX Liu suspend_step_name( 4472a77c46dSShuoX Liu suspend_stats.failed_steps[last_step])); 4482a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4492a77c46dSShuoX Liu index = last_step + REC_FAILED_NUM - i; 4502a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4512a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-s\n", 4522a77c46dSShuoX Liu suspend_step_name( 4532a77c46dSShuoX Liu suspend_stats.failed_steps[index])); 4542a77c46dSShuoX Liu } 4552a77c46dSShuoX Liu 4562a77c46dSShuoX Liu return 0; 4572a77c46dSShuoX Liu } 458943a10f8SYangtao Li DEFINE_SHOW_ATTRIBUTE(suspend_stats); 4592a77c46dSShuoX Liu 4602a77c46dSShuoX Liu static int __init pm_debugfs_init(void) 4612a77c46dSShuoX Liu { 4622a77c46dSShuoX Liu debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO, 463943a10f8SYangtao Li NULL, NULL, &suspend_stats_fops); 4642a77c46dSShuoX Liu return 0; 4652a77c46dSShuoX Liu } 4662a77c46dSShuoX Liu 4672a77c46dSShuoX Liu late_initcall(pm_debugfs_init); 4682a77c46dSShuoX Liu #endif /* CONFIG_DEBUG_FS */ 4692a77c46dSShuoX Liu 470ca123102SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 471ca123102SRafael J. Wysocki 472b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 473b2df1d4fSRafael J. Wysocki /* 474b2df1d4fSRafael J. Wysocki * pm_print_times: print time taken by devices to suspend and resume. 475b2df1d4fSRafael J. Wysocki * 476b2df1d4fSRafael J. Wysocki * show() returns whether printing of suspend and resume times is enabled. 477b2df1d4fSRafael J. Wysocki * store() accepts 0 or 1. 0 disables printing and 1 enables it. 478b2df1d4fSRafael J. Wysocki */ 479b2df1d4fSRafael J. Wysocki bool pm_print_times_enabled; 480b2df1d4fSRafael J. Wysocki 481b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_show(struct kobject *kobj, 482b2df1d4fSRafael J. Wysocki struct kobj_attribute *attr, char *buf) 483b2df1d4fSRafael J. Wysocki { 484b2df1d4fSRafael J. Wysocki return sprintf(buf, "%d\n", pm_print_times_enabled); 485b2df1d4fSRafael J. Wysocki } 486b2df1d4fSRafael J. Wysocki 487b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_store(struct kobject *kobj, 488b2df1d4fSRafael J. Wysocki struct kobj_attribute *attr, 489b2df1d4fSRafael J. Wysocki const char *buf, size_t n) 490b2df1d4fSRafael J. Wysocki { 491b2df1d4fSRafael J. Wysocki unsigned long val; 492b2df1d4fSRafael J. Wysocki 493b2df1d4fSRafael J. Wysocki if (kstrtoul(buf, 10, &val)) 494b2df1d4fSRafael J. Wysocki return -EINVAL; 495b2df1d4fSRafael J. Wysocki 496b2df1d4fSRafael J. Wysocki if (val > 1) 497b2df1d4fSRafael J. Wysocki return -EINVAL; 498b2df1d4fSRafael J. Wysocki 499b2df1d4fSRafael J. Wysocki pm_print_times_enabled = !!val; 500b2df1d4fSRafael J. Wysocki return n; 501b2df1d4fSRafael J. Wysocki } 502b2df1d4fSRafael J. Wysocki 503b2df1d4fSRafael J. Wysocki power_attr(pm_print_times); 504b2df1d4fSRafael J. Wysocki 505b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) 506b2df1d4fSRafael J. Wysocki { 507b2df1d4fSRafael J. Wysocki pm_print_times_enabled = !!initcall_debug; 508b2df1d4fSRafael J. Wysocki } 509a6f5f0ddSAlexandra Yates 510a6f5f0ddSAlexandra Yates static ssize_t pm_wakeup_irq_show(struct kobject *kobj, 511a6f5f0ddSAlexandra Yates struct kobj_attribute *attr, 512a6f5f0ddSAlexandra Yates char *buf) 513a6f5f0ddSAlexandra Yates { 514cb1f65c1SRafael J. Wysocki if (!pm_wakeup_irq()) 515cb1f65c1SRafael J. Wysocki return -ENODATA; 516cb1f65c1SRafael J. Wysocki 517cb1f65c1SRafael J. Wysocki return sprintf(buf, "%u\n", pm_wakeup_irq()); 518a6f5f0ddSAlexandra Yates } 519a6f5f0ddSAlexandra Yates 520a1e9ca69SRafael J. Wysocki power_attr_ro(pm_wakeup_irq); 521a6f5f0ddSAlexandra Yates 522726fb6b4SSrinivas Pandruvada bool pm_debug_messages_on __read_mostly; 5238d8b2441SRafael J. Wysocki 5248d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_show(struct kobject *kobj, 5258d8b2441SRafael J. Wysocki struct kobj_attribute *attr, char *buf) 5268d8b2441SRafael J. Wysocki { 5278d8b2441SRafael J. Wysocki return sprintf(buf, "%d\n", pm_debug_messages_on); 5288d8b2441SRafael J. Wysocki } 5298d8b2441SRafael J. Wysocki 5308d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_store(struct kobject *kobj, 5318d8b2441SRafael J. Wysocki struct kobj_attribute *attr, 5328d8b2441SRafael J. Wysocki const char *buf, size_t n) 5338d8b2441SRafael J. Wysocki { 5348d8b2441SRafael J. Wysocki unsigned long val; 5358d8b2441SRafael J. Wysocki 5368d8b2441SRafael J. Wysocki if (kstrtoul(buf, 10, &val)) 5378d8b2441SRafael J. Wysocki return -EINVAL; 5388d8b2441SRafael J. Wysocki 5398d8b2441SRafael J. Wysocki if (val > 1) 5408d8b2441SRafael J. Wysocki return -EINVAL; 5418d8b2441SRafael J. Wysocki 5428d8b2441SRafael J. Wysocki pm_debug_messages_on = !!val; 5438d8b2441SRafael J. Wysocki return n; 5448d8b2441SRafael J. Wysocki } 5458d8b2441SRafael J. Wysocki 5468d8b2441SRafael J. Wysocki power_attr(pm_debug_messages); 5478d8b2441SRafael J. Wysocki 548db96a759SChen Yu static int __init pm_debug_messages_setup(char *str) 549db96a759SChen Yu { 550db96a759SChen Yu pm_debug_messages_on = true; 551db96a759SChen Yu return 1; 552db96a759SChen Yu } 553db96a759SChen Yu __setup("pm_debug_messages", pm_debug_messages_setup); 554db96a759SChen Yu 555819b1bb3SRafael J. Wysocki #else /* !CONFIG_PM_SLEEP_DEBUG */ 556b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) {} 557b2df1d4fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */ 558b2df1d4fSRafael J. Wysocki 559d76e15fbSGreg Kroah-Hartman struct kobject *power_kobj; 5601da177e4SLinus Torvalds 561dbcfa715SRandy Dunlap /* 5620399d4dbSRafael J. Wysocki * state - control system sleep states. 5631da177e4SLinus Torvalds * 5640399d4dbSRafael J. Wysocki * show() returns available sleep state labels, which may be "mem", "standby", 56544348e8aSMauro Carvalho Chehab * "freeze" and "disk" (hibernation). 56644348e8aSMauro Carvalho Chehab * See Documentation/admin-guide/pm/sleep-states.rst for a description of 56744348e8aSMauro Carvalho Chehab * what they mean. 5681da177e4SLinus Torvalds * 5690399d4dbSRafael J. Wysocki * store() accepts one of those strings, translates it into the proper 5700399d4dbSRafael J. Wysocki * enumerated value, and initiates a suspend transition. 5711da177e4SLinus Torvalds */ 572386f275fSKay Sievers static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, 573386f275fSKay Sievers char *buf) 5741da177e4SLinus Torvalds { 5751da177e4SLinus Torvalds char *s = buf; 576296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 57727ddcc65SRafael J. Wysocki suspend_state_t i; 5781da177e4SLinus Torvalds 57927ddcc65SRafael J. Wysocki for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) 580d431cbc5SRafael J. Wysocki if (pm_states[i]) 581d431cbc5SRafael J. Wysocki s += sprintf(s,"%s ", pm_states[i]); 58227ddcc65SRafael J. Wysocki 583296699deSRafael J. Wysocki #endif 584a6e15a39SKees Cook if (hibernation_available()) 585a6e15a39SKees Cook s += sprintf(s, "disk "); 586a3d25c27SRafael J. Wysocki if (s != buf) 587a3d25c27SRafael J. Wysocki /* convert the last space to a newline */ 588a3d25c27SRafael J. Wysocki *(s-1) = '\n'; 5891da177e4SLinus Torvalds return (s - buf); 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds 5927483b4a4SRafael J. Wysocki static suspend_state_t decode_state(const char *buf, size_t n) 5931da177e4SLinus Torvalds { 594296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 595d431cbc5SRafael J. Wysocki suspend_state_t state; 596296699deSRafael J. Wysocki #endif 5971da177e4SLinus Torvalds char *p; 5981da177e4SLinus Torvalds int len; 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds p = memchr(buf, '\n', n); 6011da177e4SLinus Torvalds len = p ? p - buf : n; 6021da177e4SLinus Torvalds 6037483b4a4SRafael J. Wysocki /* Check hibernation first. */ 604d30bdfc0SChuhong Yuan if (len == 4 && str_has_prefix(buf, "disk")) 6057483b4a4SRafael J. Wysocki return PM_SUSPEND_MAX; 606a3d25c27SRafael J. Wysocki 607296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 608d431cbc5SRafael J. Wysocki for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) { 609d431cbc5SRafael J. Wysocki const char *label = pm_states[state]; 610d431cbc5SRafael J. Wysocki 611d431cbc5SRafael J. Wysocki if (label && len == strlen(label) && !strncmp(buf, label, len)) 612d431cbc5SRafael J. Wysocki return state; 613d431cbc5SRafael J. Wysocki } 614296699deSRafael J. Wysocki #endif 615296699deSRafael J. Wysocki 6167483b4a4SRafael J. Wysocki return PM_SUSPEND_ON; 6177483b4a4SRafael J. Wysocki } 6187483b4a4SRafael J. Wysocki 6197483b4a4SRafael J. Wysocki static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, 6207483b4a4SRafael J. Wysocki const char *buf, size_t n) 6217483b4a4SRafael J. Wysocki { 6227483b4a4SRafael J. Wysocki suspend_state_t state; 6237483b4a4SRafael J. Wysocki int error; 6247483b4a4SRafael J. Wysocki 6257483b4a4SRafael J. Wysocki error = pm_autosleep_lock(); 6267483b4a4SRafael J. Wysocki if (error) 6277483b4a4SRafael J. Wysocki return error; 6287483b4a4SRafael J. Wysocki 6297483b4a4SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 6307483b4a4SRafael J. Wysocki error = -EBUSY; 6317483b4a4SRafael J. Wysocki goto out; 6327483b4a4SRafael J. Wysocki } 6337483b4a4SRafael J. Wysocki 6347483b4a4SRafael J. Wysocki state = decode_state(buf, n); 635406e7938SRafael J. Wysocki if (state < PM_SUSPEND_MAX) { 636406e7938SRafael J. Wysocki if (state == PM_SUSPEND_MEM) 637406e7938SRafael J. Wysocki state = mem_sleep_current; 638406e7938SRafael J. Wysocki 6397483b4a4SRafael J. Wysocki error = pm_suspend(state); 640406e7938SRafael J. Wysocki } else if (state == PM_SUSPEND_MAX) { 6417483b4a4SRafael J. Wysocki error = hibernate(); 642406e7938SRafael J. Wysocki } else { 6437483b4a4SRafael J. Wysocki error = -EINVAL; 644406e7938SRafael J. Wysocki } 6457483b4a4SRafael J. Wysocki 6467483b4a4SRafael J. Wysocki out: 6477483b4a4SRafael J. Wysocki pm_autosleep_unlock(); 6481da177e4SLinus Torvalds return error ? error : n; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds power_attr(state); 6521da177e4SLinus Torvalds 653c125e96fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 654c125e96fSRafael J. Wysocki /* 655c125e96fSRafael J. Wysocki * The 'wakeup_count' attribute, along with the functions defined in 656c125e96fSRafael J. Wysocki * drivers/base/power/wakeup.c, provides a means by which wakeup events can be 657c125e96fSRafael J. Wysocki * handled in a non-racy way. 658c125e96fSRafael J. Wysocki * 659c125e96fSRafael J. Wysocki * If a wakeup event occurs when the system is in a sleep state, it simply is 660c125e96fSRafael J. Wysocki * woken up. In turn, if an event that would wake the system up from a sleep 661c125e96fSRafael J. Wysocki * state occurs when it is undergoing a transition to that sleep state, the 662c125e96fSRafael J. Wysocki * transition should be aborted. Moreover, if such an event occurs when the 663c125e96fSRafael J. Wysocki * system is in the working state, an attempt to start a transition to the 664c125e96fSRafael J. Wysocki * given sleep state should fail during certain period after the detection of 665c125e96fSRafael J. Wysocki * the event. Using the 'state' attribute alone is not sufficient to satisfy 666c125e96fSRafael J. Wysocki * these requirements, because a wakeup event may occur exactly when 'state' 667c125e96fSRafael J. Wysocki * is being written to and may be delivered to user space right before it is 668c125e96fSRafael J. Wysocki * frozen, so the event will remain only partially processed until the system is 669c125e96fSRafael J. Wysocki * woken up by another event. In particular, it won't cause the transition to 670c125e96fSRafael J. Wysocki * a sleep state to be aborted. 671c125e96fSRafael J. Wysocki * 672c125e96fSRafael J. Wysocki * This difficulty may be overcome if user space uses 'wakeup_count' before 673c125e96fSRafael J. Wysocki * writing to 'state'. It first should read from 'wakeup_count' and store 674c125e96fSRafael J. Wysocki * the read value. Then, after carrying out its own preparations for the system 675c125e96fSRafael J. Wysocki * transition to a sleep state, it should write the stored value to 67625985edcSLucas De Marchi * 'wakeup_count'. If that fails, at least one wakeup event has occurred since 677c125e96fSRafael J. Wysocki * 'wakeup_count' was read and 'state' should not be written to. Otherwise, it 678c125e96fSRafael J. Wysocki * is allowed to write to 'state', but the transition will be aborted if there 679c125e96fSRafael J. Wysocki * are any wakeup events detected after 'wakeup_count' was written to. 680c125e96fSRafael J. Wysocki */ 681c125e96fSRafael J. Wysocki 682c125e96fSRafael J. Wysocki static ssize_t wakeup_count_show(struct kobject *kobj, 683c125e96fSRafael J. Wysocki struct kobj_attribute *attr, 684c125e96fSRafael J. Wysocki char *buf) 685c125e96fSRafael J. Wysocki { 686074037ecSRafael J. Wysocki unsigned int val; 687c125e96fSRafael J. Wysocki 6887483b4a4SRafael J. Wysocki return pm_get_wakeup_count(&val, true) ? 6897483b4a4SRafael J. Wysocki sprintf(buf, "%u\n", val) : -EINTR; 690c125e96fSRafael J. Wysocki } 691c125e96fSRafael J. Wysocki 692c125e96fSRafael J. Wysocki static ssize_t wakeup_count_store(struct kobject *kobj, 693c125e96fSRafael J. Wysocki struct kobj_attribute *attr, 694c125e96fSRafael J. Wysocki const char *buf, size_t n) 695c125e96fSRafael J. Wysocki { 696074037ecSRafael J. Wysocki unsigned int val; 6977483b4a4SRafael J. Wysocki int error; 698c125e96fSRafael J. Wysocki 6997483b4a4SRafael J. Wysocki error = pm_autosleep_lock(); 7007483b4a4SRafael J. Wysocki if (error) 7017483b4a4SRafael J. Wysocki return error; 7027483b4a4SRafael J. Wysocki 7037483b4a4SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 7047483b4a4SRafael J. Wysocki error = -EBUSY; 7057483b4a4SRafael J. Wysocki goto out; 7067483b4a4SRafael J. Wysocki } 7077483b4a4SRafael J. Wysocki 7087483b4a4SRafael J. Wysocki error = -EINVAL; 709074037ecSRafael J. Wysocki if (sscanf(buf, "%u", &val) == 1) { 710c125e96fSRafael J. Wysocki if (pm_save_wakeup_count(val)) 7117483b4a4SRafael J. Wysocki error = n; 712bb177fedSJulius Werner else 713bb177fedSJulius Werner pm_print_active_wakeup_sources(); 714c125e96fSRafael J. Wysocki } 7157483b4a4SRafael J. Wysocki 7167483b4a4SRafael J. Wysocki out: 7177483b4a4SRafael J. Wysocki pm_autosleep_unlock(); 7187483b4a4SRafael J. Wysocki return error; 719c125e96fSRafael J. Wysocki } 720c125e96fSRafael J. Wysocki 721c125e96fSRafael J. Wysocki power_attr(wakeup_count); 7227483b4a4SRafael J. Wysocki 7237483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP 7247483b4a4SRafael J. Wysocki static ssize_t autosleep_show(struct kobject *kobj, 7257483b4a4SRafael J. Wysocki struct kobj_attribute *attr, 7267483b4a4SRafael J. Wysocki char *buf) 7277483b4a4SRafael J. Wysocki { 7287483b4a4SRafael J. Wysocki suspend_state_t state = pm_autosleep_state(); 7297483b4a4SRafael J. Wysocki 7307483b4a4SRafael J. Wysocki if (state == PM_SUSPEND_ON) 7317483b4a4SRafael J. Wysocki return sprintf(buf, "off\n"); 7327483b4a4SRafael J. Wysocki 7337483b4a4SRafael J. Wysocki #ifdef CONFIG_SUSPEND 7347483b4a4SRafael J. Wysocki if (state < PM_SUSPEND_MAX) 735d431cbc5SRafael J. Wysocki return sprintf(buf, "%s\n", pm_states[state] ? 736d431cbc5SRafael J. Wysocki pm_states[state] : "error"); 7377483b4a4SRafael J. Wysocki #endif 7387483b4a4SRafael J. Wysocki #ifdef CONFIG_HIBERNATION 7397483b4a4SRafael J. Wysocki return sprintf(buf, "disk\n"); 7407483b4a4SRafael J. Wysocki #else 7417483b4a4SRafael J. Wysocki return sprintf(buf, "error"); 7427483b4a4SRafael J. Wysocki #endif 7437483b4a4SRafael J. Wysocki } 7447483b4a4SRafael J. Wysocki 7457483b4a4SRafael J. Wysocki static ssize_t autosleep_store(struct kobject *kobj, 7467483b4a4SRafael J. Wysocki struct kobj_attribute *attr, 7477483b4a4SRafael J. Wysocki const char *buf, size_t n) 7487483b4a4SRafael J. Wysocki { 7497483b4a4SRafael J. Wysocki suspend_state_t state = decode_state(buf, n); 7507483b4a4SRafael J. Wysocki int error; 7517483b4a4SRafael J. Wysocki 7527483b4a4SRafael J. Wysocki if (state == PM_SUSPEND_ON 753040e5bf6SArve Hjønnevåg && strcmp(buf, "off") && strcmp(buf, "off\n")) 7547483b4a4SRafael J. Wysocki return -EINVAL; 7557483b4a4SRafael J. Wysocki 756406e7938SRafael J. Wysocki if (state == PM_SUSPEND_MEM) 757406e7938SRafael J. Wysocki state = mem_sleep_current; 758406e7938SRafael J. Wysocki 7597483b4a4SRafael J. Wysocki error = pm_autosleep_set_state(state); 7607483b4a4SRafael J. Wysocki return error ? error : n; 7617483b4a4SRafael J. Wysocki } 7627483b4a4SRafael J. Wysocki 7637483b4a4SRafael J. Wysocki power_attr(autosleep); 7647483b4a4SRafael J. Wysocki #endif /* CONFIG_PM_AUTOSLEEP */ 765b86ff982SRafael J. Wysocki 766b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS 767b86ff982SRafael J. Wysocki static ssize_t wake_lock_show(struct kobject *kobj, 768b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 769b86ff982SRafael J. Wysocki char *buf) 770b86ff982SRafael J. Wysocki { 771b86ff982SRafael J. Wysocki return pm_show_wakelocks(buf, true); 772b86ff982SRafael J. Wysocki } 773b86ff982SRafael J. Wysocki 774b86ff982SRafael J. Wysocki static ssize_t wake_lock_store(struct kobject *kobj, 775b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 776b86ff982SRafael J. Wysocki const char *buf, size_t n) 777b86ff982SRafael J. Wysocki { 778b86ff982SRafael J. Wysocki int error = pm_wake_lock(buf); 779b86ff982SRafael J. Wysocki return error ? error : n; 780b86ff982SRafael J. Wysocki } 781b86ff982SRafael J. Wysocki 782b86ff982SRafael J. Wysocki power_attr(wake_lock); 783b86ff982SRafael J. Wysocki 784b86ff982SRafael J. Wysocki static ssize_t wake_unlock_show(struct kobject *kobj, 785b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 786b86ff982SRafael J. Wysocki char *buf) 787b86ff982SRafael J. Wysocki { 788b86ff982SRafael J. Wysocki return pm_show_wakelocks(buf, false); 789b86ff982SRafael J. Wysocki } 790b86ff982SRafael J. Wysocki 791b86ff982SRafael J. Wysocki static ssize_t wake_unlock_store(struct kobject *kobj, 792b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 793b86ff982SRafael J. Wysocki const char *buf, size_t n) 794b86ff982SRafael J. Wysocki { 795b86ff982SRafael J. Wysocki int error = pm_wake_unlock(buf); 796b86ff982SRafael J. Wysocki return error ? error : n; 797b86ff982SRafael J. Wysocki } 798b86ff982SRafael J. Wysocki 799b86ff982SRafael J. Wysocki power_attr(wake_unlock); 800b86ff982SRafael J. Wysocki 801b86ff982SRafael J. Wysocki #endif /* CONFIG_PM_WAKELOCKS */ 802c125e96fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 803c125e96fSRafael J. Wysocki 804c5c6ba4eSRafael J. Wysocki #ifdef CONFIG_PM_TRACE 805c5c6ba4eSRafael J. Wysocki int pm_trace_enabled; 806c5c6ba4eSRafael J. Wysocki 807386f275fSKay Sievers static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr, 808386f275fSKay Sievers char *buf) 809c5c6ba4eSRafael J. Wysocki { 810c5c6ba4eSRafael J. Wysocki return sprintf(buf, "%d\n", pm_trace_enabled); 811c5c6ba4eSRafael J. Wysocki } 812c5c6ba4eSRafael J. Wysocki 813c5c6ba4eSRafael J. Wysocki static ssize_t 814386f275fSKay Sievers pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr, 815386f275fSKay Sievers const char *buf, size_t n) 816c5c6ba4eSRafael J. Wysocki { 817c5c6ba4eSRafael J. Wysocki int val; 818c5c6ba4eSRafael J. Wysocki 819c5c6ba4eSRafael J. Wysocki if (sscanf(buf, "%d", &val) == 1) { 820c5c6ba4eSRafael J. Wysocki pm_trace_enabled = !!val; 8219dceefe4SShuah Khan if (pm_trace_enabled) { 8229dceefe4SShuah Khan pr_warn("PM: Enabling pm_trace changes system date and time during resume.\n" 8239dceefe4SShuah Khan "PM: Correct system time has to be restored manually after resume.\n"); 8249dceefe4SShuah Khan } 825c5c6ba4eSRafael J. Wysocki return n; 826c5c6ba4eSRafael J. Wysocki } 827c5c6ba4eSRafael J. Wysocki return -EINVAL; 828c5c6ba4eSRafael J. Wysocki } 829c5c6ba4eSRafael J. Wysocki 830c5c6ba4eSRafael J. Wysocki power_attr(pm_trace); 831d33ac60bSJames Hogan 832d33ac60bSJames Hogan static ssize_t pm_trace_dev_match_show(struct kobject *kobj, 833d33ac60bSJames Hogan struct kobj_attribute *attr, 834d33ac60bSJames Hogan char *buf) 835d33ac60bSJames Hogan { 836d33ac60bSJames Hogan return show_trace_dev_match(buf, PAGE_SIZE); 837d33ac60bSJames Hogan } 838d33ac60bSJames Hogan 839a1e9ca69SRafael J. Wysocki power_attr_ro(pm_trace_dev_match); 840d33ac60bSJames Hogan 8410e7d56e3SRafael J. Wysocki #endif /* CONFIG_PM_TRACE */ 842c5c6ba4eSRafael J. Wysocki 843957d1282SLi Fei #ifdef CONFIG_FREEZER 844957d1282SLi Fei static ssize_t pm_freeze_timeout_show(struct kobject *kobj, 845957d1282SLi Fei struct kobj_attribute *attr, char *buf) 846957d1282SLi Fei { 847957d1282SLi Fei return sprintf(buf, "%u\n", freeze_timeout_msecs); 848957d1282SLi Fei } 849957d1282SLi Fei 850957d1282SLi Fei static ssize_t pm_freeze_timeout_store(struct kobject *kobj, 851957d1282SLi Fei struct kobj_attribute *attr, 852957d1282SLi Fei const char *buf, size_t n) 853957d1282SLi Fei { 854957d1282SLi Fei unsigned long val; 855957d1282SLi Fei 856957d1282SLi Fei if (kstrtoul(buf, 10, &val)) 857957d1282SLi Fei return -EINVAL; 858957d1282SLi Fei 859957d1282SLi Fei freeze_timeout_msecs = val; 860957d1282SLi Fei return n; 861957d1282SLi Fei } 862957d1282SLi Fei 863957d1282SLi Fei power_attr(pm_freeze_timeout); 864957d1282SLi Fei 865957d1282SLi Fei #endif /* CONFIG_FREEZER*/ 866957d1282SLi Fei 867c5c6ba4eSRafael J. Wysocki static struct attribute * g[] = { 868c5c6ba4eSRafael J. Wysocki &state_attr.attr, 8690e7d56e3SRafael J. Wysocki #ifdef CONFIG_PM_TRACE 870c5c6ba4eSRafael J. Wysocki &pm_trace_attr.attr, 871d33ac60bSJames Hogan &pm_trace_dev_match_attr.attr, 8720e7d56e3SRafael J. Wysocki #endif 8730e06b4a8SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 8740e06b4a8SRafael J. Wysocki &pm_async_attr.attr, 875c125e96fSRafael J. Wysocki &wakeup_count_attr.attr, 876406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND 877406e7938SRafael J. Wysocki &mem_sleep_attr.attr, 878c052bf82SJonas Meurer &sync_on_suspend_attr.attr, 879406e7938SRafael J. Wysocki #endif 8807483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP 8817483b4a4SRafael J. Wysocki &autosleep_attr.attr, 8827483b4a4SRafael J. Wysocki #endif 883b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS 884b86ff982SRafael J. Wysocki &wake_lock_attr.attr, 885b86ff982SRafael J. Wysocki &wake_unlock_attr.attr, 886b86ff982SRafael J. Wysocki #endif 887b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 888e516a1dbSRafael J. Wysocki &pm_test_attr.attr, 8894b7760baSSameer Nanda &pm_print_times_attr.attr, 890a6f5f0ddSAlexandra Yates &pm_wakeup_irq_attr.attr, 8918d8b2441SRafael J. Wysocki &pm_debug_messages_attr.attr, 8920e7d56e3SRafael J. Wysocki #endif 8930e06b4a8SRafael J. Wysocki #endif 894957d1282SLi Fei #ifdef CONFIG_FREEZER 895957d1282SLi Fei &pm_freeze_timeout_attr.attr, 896957d1282SLi Fei #endif 897c5c6ba4eSRafael J. Wysocki NULL, 898c5c6ba4eSRafael J. Wysocki }; 8991da177e4SLinus Torvalds 9001d0c6e59SArvind Yadav static const struct attribute_group attr_group = { 9011da177e4SLinus Torvalds .attrs = g, 9021da177e4SLinus Torvalds }; 9031da177e4SLinus Torvalds 9042c8db5beSKalesh Singh static const struct attribute_group *attr_groups[] = { 9052c8db5beSKalesh Singh &attr_group, 9062c8db5beSKalesh Singh #ifdef CONFIG_PM_SLEEP 9072c8db5beSKalesh Singh &suspend_attr_group, 9082c8db5beSKalesh Singh #endif 9092c8db5beSKalesh Singh NULL, 9102c8db5beSKalesh Singh }; 9112c8db5beSKalesh Singh 9125e928f77SRafael J. Wysocki struct workqueue_struct *pm_wq; 9137b199ca2SAlan Stern EXPORT_SYMBOL_GPL(pm_wq); 9145e928f77SRafael J. Wysocki 9155e928f77SRafael J. Wysocki static int __init pm_start_workqueue(void) 9165e928f77SRafael J. Wysocki { 91758a69cb4STejun Heo pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0); 9185e928f77SRafael J. Wysocki 9195e928f77SRafael J. Wysocki return pm_wq ? 0 : -ENOMEM; 9205e928f77SRafael J. Wysocki } 9215e928f77SRafael J. Wysocki 9221da177e4SLinus Torvalds static int __init pm_init(void) 9231da177e4SLinus Torvalds { 9245e928f77SRafael J. Wysocki int error = pm_start_workqueue(); 9255e928f77SRafael J. Wysocki if (error) 9265e928f77SRafael J. Wysocki return error; 927ac5c24ecSRafael J. Wysocki hibernate_image_size_init(); 928ddeb6487SRafael J. Wysocki hibernate_reserved_size_init(); 929fa7fd6faSSudeep Holla pm_states_init(); 930d76e15fbSGreg Kroah-Hartman power_kobj = kobject_create_and_add("power", NULL); 931d76e15fbSGreg Kroah-Hartman if (!power_kobj) 932039a5dcdSGreg Kroah-Hartman return -ENOMEM; 9332c8db5beSKalesh Singh error = sysfs_create_groups(power_kobj, attr_groups); 9347483b4a4SRafael J. Wysocki if (error) 9357483b4a4SRafael J. Wysocki return error; 936b2df1d4fSRafael J. Wysocki pm_print_times_init(); 9377483b4a4SRafael J. Wysocki return pm_autosleep_init(); 9381da177e4SLinus Torvalds } 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds core_initcall(pm_init); 941