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 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 8370d93298SPeter Zijlstra int pm_notifier_call_chain_robust(unsigned long val_up, unsigned long val_down) 8482525756SAlan Stern { 85ea00f4f4SLianwei Wang int ret; 86ea00f4f4SLianwei Wang 8770d93298SPeter Zijlstra ret = blocking_notifier_call_chain_robust(&pm_chain_head, val_up, val_down, NULL); 88f0c077a8SAkinobu Mita 89f0c077a8SAkinobu Mita return notifier_to_errno(ret); 9082525756SAlan Stern } 9170d93298SPeter Zijlstra 92ea00f4f4SLianwei Wang int pm_notifier_call_chain(unsigned long val) 93ea00f4f4SLianwei Wang { 9470d93298SPeter Zijlstra return blocking_notifier_call_chain(&pm_chain_head, val, 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 130*9ea4dcf4SDan Williams for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) { 131*9ea4dcf4SDan Williams if (i >= PM_SUSPEND_MEM && cxl_mem_active()) 132*9ea4dcf4SDan Williams continue; 133406e7938SRafael J. Wysocki if (mem_sleep_states[i]) { 134406e7938SRafael J. Wysocki const char *label = mem_sleep_states[i]; 135406e7938SRafael J. Wysocki 136406e7938SRafael J. Wysocki if (mem_sleep_current == i) 137406e7938SRafael J. Wysocki s += sprintf(s, "[%s] ", label); 138406e7938SRafael J. Wysocki else 139406e7938SRafael J. Wysocki s += sprintf(s, "%s ", label); 140406e7938SRafael J. Wysocki } 141*9ea4dcf4SDan Williams } 142406e7938SRafael J. Wysocki 143406e7938SRafael J. Wysocki /* Convert the last space to a newline if needed. */ 144406e7938SRafael J. Wysocki if (s != buf) 145406e7938SRafael J. Wysocki *(s-1) = '\n'; 146406e7938SRafael J. Wysocki 147406e7938SRafael J. Wysocki return (s - buf); 148406e7938SRafael J. Wysocki } 149406e7938SRafael J. Wysocki 150406e7938SRafael J. Wysocki static suspend_state_t decode_suspend_state(const char *buf, size_t n) 151406e7938SRafael J. Wysocki { 152406e7938SRafael J. Wysocki suspend_state_t state; 153406e7938SRafael J. Wysocki char *p; 154406e7938SRafael J. Wysocki int len; 155406e7938SRafael J. Wysocki 156406e7938SRafael J. Wysocki p = memchr(buf, '\n', n); 157406e7938SRafael J. Wysocki len = p ? p - buf : n; 158406e7938SRafael J. Wysocki 159406e7938SRafael J. Wysocki for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) { 160406e7938SRafael J. Wysocki const char *label = mem_sleep_states[state]; 161406e7938SRafael J. Wysocki 162406e7938SRafael J. Wysocki if (label && len == strlen(label) && !strncmp(buf, label, len)) 163406e7938SRafael J. Wysocki return state; 164406e7938SRafael J. Wysocki } 165406e7938SRafael J. Wysocki 166406e7938SRafael J. Wysocki return PM_SUSPEND_ON; 167406e7938SRafael J. Wysocki } 168406e7938SRafael J. Wysocki 169406e7938SRafael J. Wysocki static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr, 170406e7938SRafael J. Wysocki const char *buf, size_t n) 171406e7938SRafael J. Wysocki { 172406e7938SRafael J. Wysocki suspend_state_t state; 173406e7938SRafael J. Wysocki int error; 174406e7938SRafael J. Wysocki 175406e7938SRafael J. Wysocki error = pm_autosleep_lock(); 176406e7938SRafael J. Wysocki if (error) 177406e7938SRafael J. Wysocki return error; 178406e7938SRafael J. Wysocki 179406e7938SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 180406e7938SRafael J. Wysocki error = -EBUSY; 181406e7938SRafael J. Wysocki goto out; 182406e7938SRafael J. Wysocki } 183406e7938SRafael J. Wysocki 184406e7938SRafael J. Wysocki state = decode_suspend_state(buf, n); 185406e7938SRafael J. Wysocki if (state < PM_SUSPEND_MAX && state > PM_SUSPEND_ON) 186406e7938SRafael J. Wysocki mem_sleep_current = state; 187406e7938SRafael J. Wysocki else 188406e7938SRafael J. Wysocki error = -EINVAL; 189406e7938SRafael J. Wysocki 190406e7938SRafael J. Wysocki out: 191406e7938SRafael J. Wysocki pm_autosleep_unlock(); 192406e7938SRafael J. Wysocki return error ? error : n; 193406e7938SRafael J. Wysocki } 194406e7938SRafael J. Wysocki 195406e7938SRafael J. Wysocki power_attr(mem_sleep); 196c052bf82SJonas Meurer 197c052bf82SJonas Meurer /* 198c052bf82SJonas Meurer * sync_on_suspend: invoke ksys_sync_helper() before suspend. 199c052bf82SJonas Meurer * 200c052bf82SJonas Meurer * show() returns whether ksys_sync_helper() is invoked before suspend. 201c052bf82SJonas Meurer * store() accepts 0 or 1. 0 disables ksys_sync_helper() and 1 enables it. 202c052bf82SJonas Meurer */ 203c052bf82SJonas Meurer bool sync_on_suspend_enabled = !IS_ENABLED(CONFIG_SUSPEND_SKIP_SYNC); 204c052bf82SJonas Meurer 205c052bf82SJonas Meurer static ssize_t sync_on_suspend_show(struct kobject *kobj, 206c052bf82SJonas Meurer struct kobj_attribute *attr, char *buf) 207c052bf82SJonas Meurer { 208c052bf82SJonas Meurer return sprintf(buf, "%d\n", sync_on_suspend_enabled); 209c052bf82SJonas Meurer } 210c052bf82SJonas Meurer 211c052bf82SJonas Meurer static ssize_t sync_on_suspend_store(struct kobject *kobj, 212c052bf82SJonas Meurer struct kobj_attribute *attr, 213c052bf82SJonas Meurer const char *buf, size_t n) 214c052bf82SJonas Meurer { 215c052bf82SJonas Meurer unsigned long val; 216c052bf82SJonas Meurer 217c052bf82SJonas Meurer if (kstrtoul(buf, 10, &val)) 218c052bf82SJonas Meurer return -EINVAL; 219c052bf82SJonas Meurer 220c052bf82SJonas Meurer if (val > 1) 221c052bf82SJonas Meurer return -EINVAL; 222c052bf82SJonas Meurer 223c052bf82SJonas Meurer sync_on_suspend_enabled = !!val; 224c052bf82SJonas Meurer return n; 225c052bf82SJonas Meurer } 226c052bf82SJonas Meurer 227c052bf82SJonas Meurer power_attr(sync_on_suspend); 228406e7938SRafael J. Wysocki #endif /* CONFIG_SUSPEND */ 229406e7938SRafael J. Wysocki 230e516a1dbSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 2310e7d56e3SRafael J. Wysocki int pm_test_level = TEST_NONE; 2320e7d56e3SRafael J. Wysocki 2330e7d56e3SRafael J. Wysocki static const char * const pm_tests[__TEST_AFTER_LAST] = { 2340e7d56e3SRafael J. Wysocki [TEST_NONE] = "none", 2350e7d56e3SRafael J. Wysocki [TEST_CORE] = "core", 2360e7d56e3SRafael J. Wysocki [TEST_CPUS] = "processors", 2370e7d56e3SRafael J. Wysocki [TEST_PLATFORM] = "platform", 2380e7d56e3SRafael J. Wysocki [TEST_DEVICES] = "devices", 2390e7d56e3SRafael J. Wysocki [TEST_FREEZER] = "freezer", 2400e7d56e3SRafael J. Wysocki }; 2410e7d56e3SRafael J. Wysocki 242039a75c6SRafael J. Wysocki static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr, 243039a75c6SRafael J. Wysocki char *buf) 2440e7d56e3SRafael J. Wysocki { 2450e7d56e3SRafael J. Wysocki char *s = buf; 2460e7d56e3SRafael J. Wysocki int level; 2470e7d56e3SRafael J. Wysocki 2480e7d56e3SRafael J. Wysocki for (level = TEST_FIRST; level <= TEST_MAX; level++) 2490e7d56e3SRafael J. Wysocki if (pm_tests[level]) { 2500e7d56e3SRafael J. Wysocki if (level == pm_test_level) 2510e7d56e3SRafael J. Wysocki s += sprintf(s, "[%s] ", pm_tests[level]); 2520e7d56e3SRafael J. Wysocki else 2530e7d56e3SRafael J. Wysocki s += sprintf(s, "%s ", pm_tests[level]); 2540e7d56e3SRafael J. Wysocki } 2550e7d56e3SRafael J. Wysocki 2560e7d56e3SRafael J. Wysocki if (s != buf) 2570e7d56e3SRafael J. Wysocki /* convert the last space to a newline */ 2580e7d56e3SRafael J. Wysocki *(s-1) = '\n'; 2590e7d56e3SRafael J. Wysocki 2600e7d56e3SRafael J. Wysocki return (s - buf); 2610e7d56e3SRafael J. Wysocki } 2620e7d56e3SRafael J. Wysocki 263039a75c6SRafael J. Wysocki static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, 264039a75c6SRafael J. Wysocki const char *buf, size_t n) 2650e7d56e3SRafael J. Wysocki { 2660e7d56e3SRafael J. Wysocki const char * const *s; 2670e7d56e3SRafael J. Wysocki int level; 2680e7d56e3SRafael J. Wysocki char *p; 2690e7d56e3SRafael J. Wysocki int len; 2700e7d56e3SRafael J. Wysocki int error = -EINVAL; 2710e7d56e3SRafael J. Wysocki 2720e7d56e3SRafael J. Wysocki p = memchr(buf, '\n', n); 2730e7d56e3SRafael J. Wysocki len = p ? p - buf : n; 2740e7d56e3SRafael J. Wysocki 275bcda53faSSrivatsa S. Bhat lock_system_sleep(); 2760e7d56e3SRafael J. Wysocki 2770e7d56e3SRafael J. Wysocki level = TEST_FIRST; 2780e7d56e3SRafael J. Wysocki for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++) 2790e7d56e3SRafael J. Wysocki if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) { 2800e7d56e3SRafael J. Wysocki pm_test_level = level; 2810e7d56e3SRafael J. Wysocki error = 0; 2820e7d56e3SRafael J. Wysocki break; 2830e7d56e3SRafael J. Wysocki } 2840e7d56e3SRafael J. Wysocki 285bcda53faSSrivatsa S. Bhat unlock_system_sleep(); 2860e7d56e3SRafael J. Wysocki 2870e7d56e3SRafael J. Wysocki return error ? error : n; 2880e7d56e3SRafael J. Wysocki } 2890e7d56e3SRafael J. Wysocki 2900e7d56e3SRafael J. Wysocki power_attr(pm_test); 291e516a1dbSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */ 2920e7d56e3SRafael J. Wysocki 2932a77c46dSShuoX Liu static char *suspend_step_name(enum suspend_stat_step step) 2942a77c46dSShuoX Liu { 2952a77c46dSShuoX Liu switch (step) { 2962a77c46dSShuoX Liu case SUSPEND_FREEZE: 2972a77c46dSShuoX Liu return "freeze"; 2982a77c46dSShuoX Liu case SUSPEND_PREPARE: 2992a77c46dSShuoX Liu return "prepare"; 3002a77c46dSShuoX Liu case SUSPEND_SUSPEND: 3012a77c46dSShuoX Liu return "suspend"; 3022a77c46dSShuoX Liu case SUSPEND_SUSPEND_NOIRQ: 3032a77c46dSShuoX Liu return "suspend_noirq"; 3042a77c46dSShuoX Liu case SUSPEND_RESUME_NOIRQ: 3052a77c46dSShuoX Liu return "resume_noirq"; 3062a77c46dSShuoX Liu case SUSPEND_RESUME: 3072a77c46dSShuoX Liu return "resume"; 3082a77c46dSShuoX Liu default: 3092a77c46dSShuoX Liu return ""; 3102a77c46dSShuoX Liu } 3112a77c46dSShuoX Liu } 3122a77c46dSShuoX Liu 3132c8db5beSKalesh Singh #define suspend_attr(_name) \ 3142c8db5beSKalesh Singh static ssize_t _name##_show(struct kobject *kobj, \ 3152c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) \ 3162c8db5beSKalesh Singh { \ 3172c8db5beSKalesh Singh return sprintf(buf, "%d\n", suspend_stats._name); \ 3182c8db5beSKalesh Singh } \ 3192c8db5beSKalesh Singh static struct kobj_attribute _name = __ATTR_RO(_name) 3202c8db5beSKalesh Singh 3212c8db5beSKalesh Singh suspend_attr(success); 3222c8db5beSKalesh Singh suspend_attr(fail); 3232c8db5beSKalesh Singh suspend_attr(failed_freeze); 3242c8db5beSKalesh Singh suspend_attr(failed_prepare); 3252c8db5beSKalesh Singh suspend_attr(failed_suspend); 3262c8db5beSKalesh Singh suspend_attr(failed_suspend_late); 3272c8db5beSKalesh Singh suspend_attr(failed_suspend_noirq); 3282c8db5beSKalesh Singh suspend_attr(failed_resume); 3292c8db5beSKalesh Singh suspend_attr(failed_resume_early); 3302c8db5beSKalesh Singh suspend_attr(failed_resume_noirq); 3312c8db5beSKalesh Singh 3322c8db5beSKalesh Singh static ssize_t last_failed_dev_show(struct kobject *kobj, 3332c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 3342c8db5beSKalesh Singh { 3352c8db5beSKalesh Singh int index; 3362c8db5beSKalesh Singh char *last_failed_dev = NULL; 3372c8db5beSKalesh Singh 3382c8db5beSKalesh Singh index = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; 3392c8db5beSKalesh Singh index %= REC_FAILED_NUM; 3402c8db5beSKalesh Singh last_failed_dev = suspend_stats.failed_devs[index]; 3412c8db5beSKalesh Singh 3422c8db5beSKalesh Singh return sprintf(buf, "%s\n", last_failed_dev); 3432c8db5beSKalesh Singh } 3442c8db5beSKalesh Singh static struct kobj_attribute last_failed_dev = __ATTR_RO(last_failed_dev); 3452c8db5beSKalesh Singh 3462c8db5beSKalesh Singh static ssize_t last_failed_errno_show(struct kobject *kobj, 3472c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 3482c8db5beSKalesh Singh { 3492c8db5beSKalesh Singh int index; 3502c8db5beSKalesh Singh int last_failed_errno; 3512c8db5beSKalesh Singh 3522c8db5beSKalesh Singh index = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1; 3532c8db5beSKalesh Singh index %= REC_FAILED_NUM; 3542c8db5beSKalesh Singh last_failed_errno = suspend_stats.errno[index]; 3552c8db5beSKalesh Singh 3562c8db5beSKalesh Singh return sprintf(buf, "%d\n", last_failed_errno); 3572c8db5beSKalesh Singh } 3582c8db5beSKalesh Singh static struct kobj_attribute last_failed_errno = __ATTR_RO(last_failed_errno); 3592c8db5beSKalesh Singh 3602c8db5beSKalesh Singh static ssize_t last_failed_step_show(struct kobject *kobj, 3612c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 3622c8db5beSKalesh Singh { 3632c8db5beSKalesh Singh int index; 3642c8db5beSKalesh Singh enum suspend_stat_step step; 3652c8db5beSKalesh Singh char *last_failed_step = NULL; 3662c8db5beSKalesh Singh 3672c8db5beSKalesh Singh index = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; 3682c8db5beSKalesh Singh index %= REC_FAILED_NUM; 3692c8db5beSKalesh Singh step = suspend_stats.failed_steps[index]; 3702c8db5beSKalesh Singh last_failed_step = suspend_step_name(step); 3712c8db5beSKalesh Singh 3722c8db5beSKalesh Singh return sprintf(buf, "%s\n", last_failed_step); 3732c8db5beSKalesh Singh } 3742c8db5beSKalesh Singh static struct kobj_attribute last_failed_step = __ATTR_RO(last_failed_step); 3752c8db5beSKalesh Singh 3762c8db5beSKalesh Singh static struct attribute *suspend_attrs[] = { 3772c8db5beSKalesh Singh &success.attr, 3782c8db5beSKalesh Singh &fail.attr, 3792c8db5beSKalesh Singh &failed_freeze.attr, 3802c8db5beSKalesh Singh &failed_prepare.attr, 3812c8db5beSKalesh Singh &failed_suspend.attr, 3822c8db5beSKalesh Singh &failed_suspend_late.attr, 3832c8db5beSKalesh Singh &failed_suspend_noirq.attr, 3842c8db5beSKalesh Singh &failed_resume.attr, 3852c8db5beSKalesh Singh &failed_resume_early.attr, 3862c8db5beSKalesh Singh &failed_resume_noirq.attr, 3872c8db5beSKalesh Singh &last_failed_dev.attr, 3882c8db5beSKalesh Singh &last_failed_errno.attr, 3892c8db5beSKalesh Singh &last_failed_step.attr, 3902c8db5beSKalesh Singh NULL, 3912c8db5beSKalesh Singh }; 3922c8db5beSKalesh Singh 39315560574SRikard Falkeborn static const struct attribute_group suspend_attr_group = { 3942c8db5beSKalesh Singh .name = "suspend_stats", 3952c8db5beSKalesh Singh .attrs = suspend_attrs, 3962c8db5beSKalesh Singh }; 3972c8db5beSKalesh Singh 3982c8db5beSKalesh Singh #ifdef CONFIG_DEBUG_FS 3992a77c46dSShuoX Liu static int suspend_stats_show(struct seq_file *s, void *unused) 4002a77c46dSShuoX Liu { 4012a77c46dSShuoX Liu int i, index, last_dev, last_errno, last_step; 4022a77c46dSShuoX Liu 4032a77c46dSShuoX Liu last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; 4042a77c46dSShuoX Liu last_dev %= REC_FAILED_NUM; 4052a77c46dSShuoX Liu last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1; 4062a77c46dSShuoX Liu last_errno %= REC_FAILED_NUM; 4072a77c46dSShuoX Liu last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; 4082a77c46dSShuoX Liu last_step %= REC_FAILED_NUM; 409cf579dfbSRafael J. Wysocki seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n" 410cf579dfbSRafael J. Wysocki "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n", 4112a77c46dSShuoX Liu "success", suspend_stats.success, 4122a77c46dSShuoX Liu "fail", suspend_stats.fail, 4132a77c46dSShuoX Liu "failed_freeze", suspend_stats.failed_freeze, 4142a77c46dSShuoX Liu "failed_prepare", suspend_stats.failed_prepare, 4152a77c46dSShuoX Liu "failed_suspend", suspend_stats.failed_suspend, 416cf579dfbSRafael J. Wysocki "failed_suspend_late", 417cf579dfbSRafael J. Wysocki suspend_stats.failed_suspend_late, 4182a77c46dSShuoX Liu "failed_suspend_noirq", 4192a77c46dSShuoX Liu suspend_stats.failed_suspend_noirq, 4202a77c46dSShuoX Liu "failed_resume", suspend_stats.failed_resume, 421cf579dfbSRafael J. Wysocki "failed_resume_early", 422cf579dfbSRafael J. Wysocki suspend_stats.failed_resume_early, 4232a77c46dSShuoX Liu "failed_resume_noirq", 4242a77c46dSShuoX Liu suspend_stats.failed_resume_noirq); 4252a77c46dSShuoX Liu seq_printf(s, "failures:\n last_failed_dev:\t%-s\n", 4262a77c46dSShuoX Liu suspend_stats.failed_devs[last_dev]); 4272a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4282a77c46dSShuoX Liu index = last_dev + REC_FAILED_NUM - i; 4292a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4302a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-s\n", 4312a77c46dSShuoX Liu suspend_stats.failed_devs[index]); 4322a77c46dSShuoX Liu } 4332a77c46dSShuoX Liu seq_printf(s, " last_failed_errno:\t%-d\n", 4342a77c46dSShuoX Liu suspend_stats.errno[last_errno]); 4352a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4362a77c46dSShuoX Liu index = last_errno + REC_FAILED_NUM - i; 4372a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4382a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-d\n", 4392a77c46dSShuoX Liu suspend_stats.errno[index]); 4402a77c46dSShuoX Liu } 4412a77c46dSShuoX Liu seq_printf(s, " last_failed_step:\t%-s\n", 4422a77c46dSShuoX Liu suspend_step_name( 4432a77c46dSShuoX Liu suspend_stats.failed_steps[last_step])); 4442a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4452a77c46dSShuoX Liu index = last_step + REC_FAILED_NUM - i; 4462a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4472a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-s\n", 4482a77c46dSShuoX Liu suspend_step_name( 4492a77c46dSShuoX Liu suspend_stats.failed_steps[index])); 4502a77c46dSShuoX Liu } 4512a77c46dSShuoX Liu 4522a77c46dSShuoX Liu return 0; 4532a77c46dSShuoX Liu } 454943a10f8SYangtao Li DEFINE_SHOW_ATTRIBUTE(suspend_stats); 4552a77c46dSShuoX Liu 4562a77c46dSShuoX Liu static int __init pm_debugfs_init(void) 4572a77c46dSShuoX Liu { 4582a77c46dSShuoX Liu debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO, 459943a10f8SYangtao Li NULL, NULL, &suspend_stats_fops); 4602a77c46dSShuoX Liu return 0; 4612a77c46dSShuoX Liu } 4622a77c46dSShuoX Liu 4632a77c46dSShuoX Liu late_initcall(pm_debugfs_init); 4642a77c46dSShuoX Liu #endif /* CONFIG_DEBUG_FS */ 4652a77c46dSShuoX Liu 466ca123102SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 467ca123102SRafael J. Wysocki 468b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 469b2df1d4fSRafael J. Wysocki /* 470b2df1d4fSRafael J. Wysocki * pm_print_times: print time taken by devices to suspend and resume. 471b2df1d4fSRafael J. Wysocki * 472b2df1d4fSRafael J. Wysocki * show() returns whether printing of suspend and resume times is enabled. 473b2df1d4fSRafael J. Wysocki * store() accepts 0 or 1. 0 disables printing and 1 enables it. 474b2df1d4fSRafael J. Wysocki */ 475b2df1d4fSRafael J. Wysocki bool pm_print_times_enabled; 476b2df1d4fSRafael J. Wysocki 477b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_show(struct kobject *kobj, 478b2df1d4fSRafael J. Wysocki struct kobj_attribute *attr, char *buf) 479b2df1d4fSRafael J. Wysocki { 480b2df1d4fSRafael J. Wysocki return sprintf(buf, "%d\n", pm_print_times_enabled); 481b2df1d4fSRafael J. Wysocki } 482b2df1d4fSRafael J. Wysocki 483b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_store(struct kobject *kobj, 484b2df1d4fSRafael J. Wysocki struct kobj_attribute *attr, 485b2df1d4fSRafael J. Wysocki const char *buf, size_t n) 486b2df1d4fSRafael J. Wysocki { 487b2df1d4fSRafael J. Wysocki unsigned long val; 488b2df1d4fSRafael J. Wysocki 489b2df1d4fSRafael J. Wysocki if (kstrtoul(buf, 10, &val)) 490b2df1d4fSRafael J. Wysocki return -EINVAL; 491b2df1d4fSRafael J. Wysocki 492b2df1d4fSRafael J. Wysocki if (val > 1) 493b2df1d4fSRafael J. Wysocki return -EINVAL; 494b2df1d4fSRafael J. Wysocki 495b2df1d4fSRafael J. Wysocki pm_print_times_enabled = !!val; 496b2df1d4fSRafael J. Wysocki return n; 497b2df1d4fSRafael J. Wysocki } 498b2df1d4fSRafael J. Wysocki 499b2df1d4fSRafael J. Wysocki power_attr(pm_print_times); 500b2df1d4fSRafael J. Wysocki 501b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) 502b2df1d4fSRafael J. Wysocki { 503b2df1d4fSRafael J. Wysocki pm_print_times_enabled = !!initcall_debug; 504b2df1d4fSRafael J. Wysocki } 505a6f5f0ddSAlexandra Yates 506a6f5f0ddSAlexandra Yates static ssize_t pm_wakeup_irq_show(struct kobject *kobj, 507a6f5f0ddSAlexandra Yates struct kobj_attribute *attr, 508a6f5f0ddSAlexandra Yates char *buf) 509a6f5f0ddSAlexandra Yates { 510cb1f65c1SRafael J. Wysocki if (!pm_wakeup_irq()) 511cb1f65c1SRafael J. Wysocki return -ENODATA; 512cb1f65c1SRafael J. Wysocki 513cb1f65c1SRafael J. Wysocki return sprintf(buf, "%u\n", pm_wakeup_irq()); 514a6f5f0ddSAlexandra Yates } 515a6f5f0ddSAlexandra Yates 516a1e9ca69SRafael J. Wysocki power_attr_ro(pm_wakeup_irq); 517a6f5f0ddSAlexandra Yates 518726fb6b4SSrinivas Pandruvada bool pm_debug_messages_on __read_mostly; 5198d8b2441SRafael J. Wysocki 5208d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_show(struct kobject *kobj, 5218d8b2441SRafael J. Wysocki struct kobj_attribute *attr, char *buf) 5228d8b2441SRafael J. Wysocki { 5238d8b2441SRafael J. Wysocki return sprintf(buf, "%d\n", pm_debug_messages_on); 5248d8b2441SRafael J. Wysocki } 5258d8b2441SRafael J. Wysocki 5268d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_store(struct kobject *kobj, 5278d8b2441SRafael J. Wysocki struct kobj_attribute *attr, 5288d8b2441SRafael J. Wysocki const char *buf, size_t n) 5298d8b2441SRafael J. Wysocki { 5308d8b2441SRafael J. Wysocki unsigned long val; 5318d8b2441SRafael J. Wysocki 5328d8b2441SRafael J. Wysocki if (kstrtoul(buf, 10, &val)) 5338d8b2441SRafael J. Wysocki return -EINVAL; 5348d8b2441SRafael J. Wysocki 5358d8b2441SRafael J. Wysocki if (val > 1) 5368d8b2441SRafael J. Wysocki return -EINVAL; 5378d8b2441SRafael J. Wysocki 5388d8b2441SRafael J. Wysocki pm_debug_messages_on = !!val; 5398d8b2441SRafael J. Wysocki return n; 5408d8b2441SRafael J. Wysocki } 5418d8b2441SRafael J. Wysocki 5428d8b2441SRafael J. Wysocki power_attr(pm_debug_messages); 5438d8b2441SRafael J. Wysocki 544db96a759SChen Yu static int __init pm_debug_messages_setup(char *str) 545db96a759SChen Yu { 546db96a759SChen Yu pm_debug_messages_on = true; 547db96a759SChen Yu return 1; 548db96a759SChen Yu } 549db96a759SChen Yu __setup("pm_debug_messages", pm_debug_messages_setup); 550db96a759SChen Yu 5518d8b2441SRafael J. Wysocki /** 552cb08e035SRafael J. Wysocki * __pm_pr_dbg - Print a suspend debug message to the kernel log. 553cb08e035SRafael J. Wysocki * @defer: Whether or not to use printk_deferred() to print the message. 5548d8b2441SRafael J. Wysocki * @fmt: Message format. 5558d8b2441SRafael J. Wysocki * 5568d8b2441SRafael J. Wysocki * The message will be emitted if enabled through the pm_debug_messages 5578d8b2441SRafael J. Wysocki * sysfs attribute. 5588d8b2441SRafael J. Wysocki */ 559cb08e035SRafael J. Wysocki void __pm_pr_dbg(bool defer, const char *fmt, ...) 5608d8b2441SRafael J. Wysocki { 5618d8b2441SRafael J. Wysocki struct va_format vaf; 5628d8b2441SRafael J. Wysocki va_list args; 5638d8b2441SRafael J. Wysocki 5648d8b2441SRafael J. Wysocki if (!pm_debug_messages_on) 5658d8b2441SRafael J. Wysocki return; 5668d8b2441SRafael J. Wysocki 5678d8b2441SRafael J. Wysocki va_start(args, fmt); 5688d8b2441SRafael J. Wysocki 5698d8b2441SRafael J. Wysocki vaf.fmt = fmt; 5708d8b2441SRafael J. Wysocki vaf.va = &args; 5718d8b2441SRafael J. Wysocki 572cb08e035SRafael J. Wysocki if (defer) 573cb08e035SRafael J. Wysocki printk_deferred(KERN_DEBUG "PM: %pV", &vaf); 574cb08e035SRafael J. Wysocki else 5758d8b2441SRafael J. Wysocki printk(KERN_DEBUG "PM: %pV", &vaf); 5768d8b2441SRafael J. Wysocki 5778d8b2441SRafael J. Wysocki va_end(args); 5788d8b2441SRafael J. Wysocki } 5798d8b2441SRafael J. Wysocki 580819b1bb3SRafael J. Wysocki #else /* !CONFIG_PM_SLEEP_DEBUG */ 581b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) {} 582b2df1d4fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */ 583b2df1d4fSRafael J. Wysocki 584d76e15fbSGreg Kroah-Hartman struct kobject *power_kobj; 5851da177e4SLinus Torvalds 586dbcfa715SRandy Dunlap /* 5870399d4dbSRafael J. Wysocki * state - control system sleep states. 5881da177e4SLinus Torvalds * 5890399d4dbSRafael J. Wysocki * show() returns available sleep state labels, which may be "mem", "standby", 59044348e8aSMauro Carvalho Chehab * "freeze" and "disk" (hibernation). 59144348e8aSMauro Carvalho Chehab * See Documentation/admin-guide/pm/sleep-states.rst for a description of 59244348e8aSMauro Carvalho Chehab * what they mean. 5931da177e4SLinus Torvalds * 5940399d4dbSRafael J. Wysocki * store() accepts one of those strings, translates it into the proper 5950399d4dbSRafael J. Wysocki * enumerated value, and initiates a suspend transition. 5961da177e4SLinus Torvalds */ 597386f275fSKay Sievers static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, 598386f275fSKay Sievers char *buf) 5991da177e4SLinus Torvalds { 6001da177e4SLinus Torvalds char *s = buf; 601296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 60227ddcc65SRafael J. Wysocki suspend_state_t i; 6031da177e4SLinus Torvalds 60427ddcc65SRafael J. Wysocki for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) 605d431cbc5SRafael J. Wysocki if (pm_states[i]) 606d431cbc5SRafael J. Wysocki s += sprintf(s,"%s ", pm_states[i]); 60727ddcc65SRafael J. Wysocki 608296699deSRafael J. Wysocki #endif 609a6e15a39SKees Cook if (hibernation_available()) 610a6e15a39SKees Cook s += sprintf(s, "disk "); 611a3d25c27SRafael J. Wysocki if (s != buf) 612a3d25c27SRafael J. Wysocki /* convert the last space to a newline */ 613a3d25c27SRafael J. Wysocki *(s-1) = '\n'; 6141da177e4SLinus Torvalds return (s - buf); 6151da177e4SLinus Torvalds } 6161da177e4SLinus Torvalds 6177483b4a4SRafael J. Wysocki static suspend_state_t decode_state(const char *buf, size_t n) 6181da177e4SLinus Torvalds { 619296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 620d431cbc5SRafael J. Wysocki suspend_state_t state; 621296699deSRafael J. Wysocki #endif 6221da177e4SLinus Torvalds char *p; 6231da177e4SLinus Torvalds int len; 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds p = memchr(buf, '\n', n); 6261da177e4SLinus Torvalds len = p ? p - buf : n; 6271da177e4SLinus Torvalds 6287483b4a4SRafael J. Wysocki /* Check hibernation first. */ 629d30bdfc0SChuhong Yuan if (len == 4 && str_has_prefix(buf, "disk")) 6307483b4a4SRafael J. Wysocki return PM_SUSPEND_MAX; 631a3d25c27SRafael J. Wysocki 632296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 633d431cbc5SRafael J. Wysocki for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) { 634d431cbc5SRafael J. Wysocki const char *label = pm_states[state]; 635d431cbc5SRafael J. Wysocki 636d431cbc5SRafael J. Wysocki if (label && len == strlen(label) && !strncmp(buf, label, len)) 637d431cbc5SRafael J. Wysocki return state; 638d431cbc5SRafael J. Wysocki } 639296699deSRafael J. Wysocki #endif 640296699deSRafael J. Wysocki 6417483b4a4SRafael J. Wysocki return PM_SUSPEND_ON; 6427483b4a4SRafael J. Wysocki } 6437483b4a4SRafael J. Wysocki 6447483b4a4SRafael J. Wysocki static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, 6457483b4a4SRafael J. Wysocki const char *buf, size_t n) 6467483b4a4SRafael J. Wysocki { 6477483b4a4SRafael J. Wysocki suspend_state_t state; 6487483b4a4SRafael J. Wysocki int error; 6497483b4a4SRafael J. Wysocki 6507483b4a4SRafael J. Wysocki error = pm_autosleep_lock(); 6517483b4a4SRafael J. Wysocki if (error) 6527483b4a4SRafael J. Wysocki return error; 6537483b4a4SRafael J. Wysocki 6547483b4a4SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 6557483b4a4SRafael J. Wysocki error = -EBUSY; 6567483b4a4SRafael J. Wysocki goto out; 6577483b4a4SRafael J. Wysocki } 6587483b4a4SRafael J. Wysocki 6597483b4a4SRafael J. Wysocki state = decode_state(buf, n); 660406e7938SRafael J. Wysocki if (state < PM_SUSPEND_MAX) { 661406e7938SRafael J. Wysocki if (state == PM_SUSPEND_MEM) 662406e7938SRafael J. Wysocki state = mem_sleep_current; 663406e7938SRafael J. Wysocki 6647483b4a4SRafael J. Wysocki error = pm_suspend(state); 665406e7938SRafael J. Wysocki } else if (state == PM_SUSPEND_MAX) { 6667483b4a4SRafael J. Wysocki error = hibernate(); 667406e7938SRafael J. Wysocki } else { 6687483b4a4SRafael J. Wysocki error = -EINVAL; 669406e7938SRafael J. Wysocki } 6707483b4a4SRafael J. Wysocki 6717483b4a4SRafael J. Wysocki out: 6727483b4a4SRafael J. Wysocki pm_autosleep_unlock(); 6731da177e4SLinus Torvalds return error ? error : n; 6741da177e4SLinus Torvalds } 6751da177e4SLinus Torvalds 6761da177e4SLinus Torvalds power_attr(state); 6771da177e4SLinus Torvalds 678c125e96fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 679c125e96fSRafael J. Wysocki /* 680c125e96fSRafael J. Wysocki * The 'wakeup_count' attribute, along with the functions defined in 681c125e96fSRafael J. Wysocki * drivers/base/power/wakeup.c, provides a means by which wakeup events can be 682c125e96fSRafael J. Wysocki * handled in a non-racy way. 683c125e96fSRafael J. Wysocki * 684c125e96fSRafael J. Wysocki * If a wakeup event occurs when the system is in a sleep state, it simply is 685c125e96fSRafael J. Wysocki * woken up. In turn, if an event that would wake the system up from a sleep 686c125e96fSRafael J. Wysocki * state occurs when it is undergoing a transition to that sleep state, the 687c125e96fSRafael J. Wysocki * transition should be aborted. Moreover, if such an event occurs when the 688c125e96fSRafael J. Wysocki * system is in the working state, an attempt to start a transition to the 689c125e96fSRafael J. Wysocki * given sleep state should fail during certain period after the detection of 690c125e96fSRafael J. Wysocki * the event. Using the 'state' attribute alone is not sufficient to satisfy 691c125e96fSRafael J. Wysocki * these requirements, because a wakeup event may occur exactly when 'state' 692c125e96fSRafael J. Wysocki * is being written to and may be delivered to user space right before it is 693c125e96fSRafael J. Wysocki * frozen, so the event will remain only partially processed until the system is 694c125e96fSRafael J. Wysocki * woken up by another event. In particular, it won't cause the transition to 695c125e96fSRafael J. Wysocki * a sleep state to be aborted. 696c125e96fSRafael J. Wysocki * 697c125e96fSRafael J. Wysocki * This difficulty may be overcome if user space uses 'wakeup_count' before 698c125e96fSRafael J. Wysocki * writing to 'state'. It first should read from 'wakeup_count' and store 699c125e96fSRafael J. Wysocki * the read value. Then, after carrying out its own preparations for the system 700c125e96fSRafael J. Wysocki * transition to a sleep state, it should write the stored value to 70125985edcSLucas De Marchi * 'wakeup_count'. If that fails, at least one wakeup event has occurred since 702c125e96fSRafael J. Wysocki * 'wakeup_count' was read and 'state' should not be written to. Otherwise, it 703c125e96fSRafael J. Wysocki * is allowed to write to 'state', but the transition will be aborted if there 704c125e96fSRafael J. Wysocki * are any wakeup events detected after 'wakeup_count' was written to. 705c125e96fSRafael J. Wysocki */ 706c125e96fSRafael J. Wysocki 707c125e96fSRafael J. Wysocki static ssize_t wakeup_count_show(struct kobject *kobj, 708c125e96fSRafael J. Wysocki struct kobj_attribute *attr, 709c125e96fSRafael J. Wysocki char *buf) 710c125e96fSRafael J. Wysocki { 711074037ecSRafael J. Wysocki unsigned int val; 712c125e96fSRafael J. Wysocki 7137483b4a4SRafael J. Wysocki return pm_get_wakeup_count(&val, true) ? 7147483b4a4SRafael J. Wysocki sprintf(buf, "%u\n", val) : -EINTR; 715c125e96fSRafael J. Wysocki } 716c125e96fSRafael J. Wysocki 717c125e96fSRafael J. Wysocki static ssize_t wakeup_count_store(struct kobject *kobj, 718c125e96fSRafael J. Wysocki struct kobj_attribute *attr, 719c125e96fSRafael J. Wysocki const char *buf, size_t n) 720c125e96fSRafael J. Wysocki { 721074037ecSRafael J. Wysocki unsigned int val; 7227483b4a4SRafael J. Wysocki int error; 723c125e96fSRafael J. Wysocki 7247483b4a4SRafael J. Wysocki error = pm_autosleep_lock(); 7257483b4a4SRafael J. Wysocki if (error) 7267483b4a4SRafael J. Wysocki return error; 7277483b4a4SRafael J. Wysocki 7287483b4a4SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 7297483b4a4SRafael J. Wysocki error = -EBUSY; 7307483b4a4SRafael J. Wysocki goto out; 7317483b4a4SRafael J. Wysocki } 7327483b4a4SRafael J. Wysocki 7337483b4a4SRafael J. Wysocki error = -EINVAL; 734074037ecSRafael J. Wysocki if (sscanf(buf, "%u", &val) == 1) { 735c125e96fSRafael J. Wysocki if (pm_save_wakeup_count(val)) 7367483b4a4SRafael J. Wysocki error = n; 737bb177fedSJulius Werner else 738bb177fedSJulius Werner pm_print_active_wakeup_sources(); 739c125e96fSRafael J. Wysocki } 7407483b4a4SRafael J. Wysocki 7417483b4a4SRafael J. Wysocki out: 7427483b4a4SRafael J. Wysocki pm_autosleep_unlock(); 7437483b4a4SRafael J. Wysocki return error; 744c125e96fSRafael J. Wysocki } 745c125e96fSRafael J. Wysocki 746c125e96fSRafael J. Wysocki power_attr(wakeup_count); 7477483b4a4SRafael J. Wysocki 7487483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP 7497483b4a4SRafael J. Wysocki static ssize_t autosleep_show(struct kobject *kobj, 7507483b4a4SRafael J. Wysocki struct kobj_attribute *attr, 7517483b4a4SRafael J. Wysocki char *buf) 7527483b4a4SRafael J. Wysocki { 7537483b4a4SRafael J. Wysocki suspend_state_t state = pm_autosleep_state(); 7547483b4a4SRafael J. Wysocki 7557483b4a4SRafael J. Wysocki if (state == PM_SUSPEND_ON) 7567483b4a4SRafael J. Wysocki return sprintf(buf, "off\n"); 7577483b4a4SRafael J. Wysocki 7587483b4a4SRafael J. Wysocki #ifdef CONFIG_SUSPEND 7597483b4a4SRafael J. Wysocki if (state < PM_SUSPEND_MAX) 760d431cbc5SRafael J. Wysocki return sprintf(buf, "%s\n", pm_states[state] ? 761d431cbc5SRafael J. Wysocki pm_states[state] : "error"); 7627483b4a4SRafael J. Wysocki #endif 7637483b4a4SRafael J. Wysocki #ifdef CONFIG_HIBERNATION 7647483b4a4SRafael J. Wysocki return sprintf(buf, "disk\n"); 7657483b4a4SRafael J. Wysocki #else 7667483b4a4SRafael J. Wysocki return sprintf(buf, "error"); 7677483b4a4SRafael J. Wysocki #endif 7687483b4a4SRafael J. Wysocki } 7697483b4a4SRafael J. Wysocki 7707483b4a4SRafael J. Wysocki static ssize_t autosleep_store(struct kobject *kobj, 7717483b4a4SRafael J. Wysocki struct kobj_attribute *attr, 7727483b4a4SRafael J. Wysocki const char *buf, size_t n) 7737483b4a4SRafael J. Wysocki { 7747483b4a4SRafael J. Wysocki suspend_state_t state = decode_state(buf, n); 7757483b4a4SRafael J. Wysocki int error; 7767483b4a4SRafael J. Wysocki 7777483b4a4SRafael J. Wysocki if (state == PM_SUSPEND_ON 778040e5bf6SArve Hjønnevåg && strcmp(buf, "off") && strcmp(buf, "off\n")) 7797483b4a4SRafael J. Wysocki return -EINVAL; 7807483b4a4SRafael J. Wysocki 781406e7938SRafael J. Wysocki if (state == PM_SUSPEND_MEM) 782406e7938SRafael J. Wysocki state = mem_sleep_current; 783406e7938SRafael J. Wysocki 7847483b4a4SRafael J. Wysocki error = pm_autosleep_set_state(state); 7857483b4a4SRafael J. Wysocki return error ? error : n; 7867483b4a4SRafael J. Wysocki } 7877483b4a4SRafael J. Wysocki 7887483b4a4SRafael J. Wysocki power_attr(autosleep); 7897483b4a4SRafael J. Wysocki #endif /* CONFIG_PM_AUTOSLEEP */ 790b86ff982SRafael J. Wysocki 791b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS 792b86ff982SRafael J. Wysocki static ssize_t wake_lock_show(struct kobject *kobj, 793b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 794b86ff982SRafael J. Wysocki char *buf) 795b86ff982SRafael J. Wysocki { 796b86ff982SRafael J. Wysocki return pm_show_wakelocks(buf, true); 797b86ff982SRafael J. Wysocki } 798b86ff982SRafael J. Wysocki 799b86ff982SRafael J. Wysocki static ssize_t wake_lock_store(struct kobject *kobj, 800b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 801b86ff982SRafael J. Wysocki const char *buf, size_t n) 802b86ff982SRafael J. Wysocki { 803b86ff982SRafael J. Wysocki int error = pm_wake_lock(buf); 804b86ff982SRafael J. Wysocki return error ? error : n; 805b86ff982SRafael J. Wysocki } 806b86ff982SRafael J. Wysocki 807b86ff982SRafael J. Wysocki power_attr(wake_lock); 808b86ff982SRafael J. Wysocki 809b86ff982SRafael J. Wysocki static ssize_t wake_unlock_show(struct kobject *kobj, 810b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 811b86ff982SRafael J. Wysocki char *buf) 812b86ff982SRafael J. Wysocki { 813b86ff982SRafael J. Wysocki return pm_show_wakelocks(buf, false); 814b86ff982SRafael J. Wysocki } 815b86ff982SRafael J. Wysocki 816b86ff982SRafael J. Wysocki static ssize_t wake_unlock_store(struct kobject *kobj, 817b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 818b86ff982SRafael J. Wysocki const char *buf, size_t n) 819b86ff982SRafael J. Wysocki { 820b86ff982SRafael J. Wysocki int error = pm_wake_unlock(buf); 821b86ff982SRafael J. Wysocki return error ? error : n; 822b86ff982SRafael J. Wysocki } 823b86ff982SRafael J. Wysocki 824b86ff982SRafael J. Wysocki power_attr(wake_unlock); 825b86ff982SRafael J. Wysocki 826b86ff982SRafael J. Wysocki #endif /* CONFIG_PM_WAKELOCKS */ 827c125e96fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 828c125e96fSRafael J. Wysocki 829c5c6ba4eSRafael J. Wysocki #ifdef CONFIG_PM_TRACE 830c5c6ba4eSRafael J. Wysocki int pm_trace_enabled; 831c5c6ba4eSRafael J. Wysocki 832386f275fSKay Sievers static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr, 833386f275fSKay Sievers char *buf) 834c5c6ba4eSRafael J. Wysocki { 835c5c6ba4eSRafael J. Wysocki return sprintf(buf, "%d\n", pm_trace_enabled); 836c5c6ba4eSRafael J. Wysocki } 837c5c6ba4eSRafael J. Wysocki 838c5c6ba4eSRafael J. Wysocki static ssize_t 839386f275fSKay Sievers pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr, 840386f275fSKay Sievers const char *buf, size_t n) 841c5c6ba4eSRafael J. Wysocki { 842c5c6ba4eSRafael J. Wysocki int val; 843c5c6ba4eSRafael J. Wysocki 844c5c6ba4eSRafael J. Wysocki if (sscanf(buf, "%d", &val) == 1) { 845c5c6ba4eSRafael J. Wysocki pm_trace_enabled = !!val; 8469dceefe4SShuah Khan if (pm_trace_enabled) { 8479dceefe4SShuah Khan pr_warn("PM: Enabling pm_trace changes system date and time during resume.\n" 8489dceefe4SShuah Khan "PM: Correct system time has to be restored manually after resume.\n"); 8499dceefe4SShuah Khan } 850c5c6ba4eSRafael J. Wysocki return n; 851c5c6ba4eSRafael J. Wysocki } 852c5c6ba4eSRafael J. Wysocki return -EINVAL; 853c5c6ba4eSRafael J. Wysocki } 854c5c6ba4eSRafael J. Wysocki 855c5c6ba4eSRafael J. Wysocki power_attr(pm_trace); 856d33ac60bSJames Hogan 857d33ac60bSJames Hogan static ssize_t pm_trace_dev_match_show(struct kobject *kobj, 858d33ac60bSJames Hogan struct kobj_attribute *attr, 859d33ac60bSJames Hogan char *buf) 860d33ac60bSJames Hogan { 861d33ac60bSJames Hogan return show_trace_dev_match(buf, PAGE_SIZE); 862d33ac60bSJames Hogan } 863d33ac60bSJames Hogan 864a1e9ca69SRafael J. Wysocki power_attr_ro(pm_trace_dev_match); 865d33ac60bSJames Hogan 8660e7d56e3SRafael J. Wysocki #endif /* CONFIG_PM_TRACE */ 867c5c6ba4eSRafael J. Wysocki 868957d1282SLi Fei #ifdef CONFIG_FREEZER 869957d1282SLi Fei static ssize_t pm_freeze_timeout_show(struct kobject *kobj, 870957d1282SLi Fei struct kobj_attribute *attr, char *buf) 871957d1282SLi Fei { 872957d1282SLi Fei return sprintf(buf, "%u\n", freeze_timeout_msecs); 873957d1282SLi Fei } 874957d1282SLi Fei 875957d1282SLi Fei static ssize_t pm_freeze_timeout_store(struct kobject *kobj, 876957d1282SLi Fei struct kobj_attribute *attr, 877957d1282SLi Fei const char *buf, size_t n) 878957d1282SLi Fei { 879957d1282SLi Fei unsigned long val; 880957d1282SLi Fei 881957d1282SLi Fei if (kstrtoul(buf, 10, &val)) 882957d1282SLi Fei return -EINVAL; 883957d1282SLi Fei 884957d1282SLi Fei freeze_timeout_msecs = val; 885957d1282SLi Fei return n; 886957d1282SLi Fei } 887957d1282SLi Fei 888957d1282SLi Fei power_attr(pm_freeze_timeout); 889957d1282SLi Fei 890957d1282SLi Fei #endif /* CONFIG_FREEZER*/ 891957d1282SLi Fei 892c5c6ba4eSRafael J. Wysocki static struct attribute * g[] = { 893c5c6ba4eSRafael J. Wysocki &state_attr.attr, 8940e7d56e3SRafael J. Wysocki #ifdef CONFIG_PM_TRACE 895c5c6ba4eSRafael J. Wysocki &pm_trace_attr.attr, 896d33ac60bSJames Hogan &pm_trace_dev_match_attr.attr, 8970e7d56e3SRafael J. Wysocki #endif 8980e06b4a8SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 8990e06b4a8SRafael J. Wysocki &pm_async_attr.attr, 900c125e96fSRafael J. Wysocki &wakeup_count_attr.attr, 901406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND 902406e7938SRafael J. Wysocki &mem_sleep_attr.attr, 903c052bf82SJonas Meurer &sync_on_suspend_attr.attr, 904406e7938SRafael J. Wysocki #endif 9057483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP 9067483b4a4SRafael J. Wysocki &autosleep_attr.attr, 9077483b4a4SRafael J. Wysocki #endif 908b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS 909b86ff982SRafael J. Wysocki &wake_lock_attr.attr, 910b86ff982SRafael J. Wysocki &wake_unlock_attr.attr, 911b86ff982SRafael J. Wysocki #endif 912b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 913e516a1dbSRafael J. Wysocki &pm_test_attr.attr, 9144b7760baSSameer Nanda &pm_print_times_attr.attr, 915a6f5f0ddSAlexandra Yates &pm_wakeup_irq_attr.attr, 9168d8b2441SRafael J. Wysocki &pm_debug_messages_attr.attr, 9170e7d56e3SRafael J. Wysocki #endif 9180e06b4a8SRafael J. Wysocki #endif 919957d1282SLi Fei #ifdef CONFIG_FREEZER 920957d1282SLi Fei &pm_freeze_timeout_attr.attr, 921957d1282SLi Fei #endif 922c5c6ba4eSRafael J. Wysocki NULL, 923c5c6ba4eSRafael J. Wysocki }; 9241da177e4SLinus Torvalds 9251d0c6e59SArvind Yadav static const struct attribute_group attr_group = { 9261da177e4SLinus Torvalds .attrs = g, 9271da177e4SLinus Torvalds }; 9281da177e4SLinus Torvalds 9292c8db5beSKalesh Singh static const struct attribute_group *attr_groups[] = { 9302c8db5beSKalesh Singh &attr_group, 9312c8db5beSKalesh Singh #ifdef CONFIG_PM_SLEEP 9322c8db5beSKalesh Singh &suspend_attr_group, 9332c8db5beSKalesh Singh #endif 9342c8db5beSKalesh Singh NULL, 9352c8db5beSKalesh Singh }; 9362c8db5beSKalesh Singh 9375e928f77SRafael J. Wysocki struct workqueue_struct *pm_wq; 9387b199ca2SAlan Stern EXPORT_SYMBOL_GPL(pm_wq); 9395e928f77SRafael J. Wysocki 9405e928f77SRafael J. Wysocki static int __init pm_start_workqueue(void) 9415e928f77SRafael J. Wysocki { 94258a69cb4STejun Heo pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0); 9435e928f77SRafael J. Wysocki 9445e928f77SRafael J. Wysocki return pm_wq ? 0 : -ENOMEM; 9455e928f77SRafael J. Wysocki } 9465e928f77SRafael J. Wysocki 9471da177e4SLinus Torvalds static int __init pm_init(void) 9481da177e4SLinus Torvalds { 9495e928f77SRafael J. Wysocki int error = pm_start_workqueue(); 9505e928f77SRafael J. Wysocki if (error) 9515e928f77SRafael J. Wysocki return error; 952ac5c24ecSRafael J. Wysocki hibernate_image_size_init(); 953ddeb6487SRafael J. Wysocki hibernate_reserved_size_init(); 954fa7fd6faSSudeep Holla pm_states_init(); 955d76e15fbSGreg Kroah-Hartman power_kobj = kobject_create_and_add("power", NULL); 956d76e15fbSGreg Kroah-Hartman if (!power_kobj) 957039a5dcdSGreg Kroah-Hartman return -ENOMEM; 9582c8db5beSKalesh Singh error = sysfs_create_groups(power_kobj, attr_groups); 9597483b4a4SRafael J. Wysocki if (error) 9607483b4a4SRafael J. Wysocki return error; 961b2df1d4fSRafael J. Wysocki pm_print_times_init(); 9627483b4a4SRafael J. Wysocki return pm_autosleep_init(); 9631da177e4SLinus Torvalds } 9641da177e4SLinus Torvalds 9651da177e4SLinus Torvalds core_initcall(pm_init); 966