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 83ea00f4f4SLianwei Wang int __pm_notifier_call_chain(unsigned long val, int nr_to_call, int *nr_calls) 8482525756SAlan Stern { 85ea00f4f4SLianwei Wang int ret; 86ea00f4f4SLianwei Wang 87ea00f4f4SLianwei Wang ret = __blocking_notifier_call_chain(&pm_chain_head, val, NULL, 88ea00f4f4SLianwei Wang nr_to_call, nr_calls); 89f0c077a8SAkinobu Mita 90f0c077a8SAkinobu Mita return notifier_to_errno(ret); 9182525756SAlan Stern } 92ea00f4f4SLianwei Wang int pm_notifier_call_chain(unsigned long val) 93ea00f4f4SLianwei Wang { 94ea00f4f4SLianwei Wang return __pm_notifier_call_chain(val, -1, NULL); 95ea00f4f4SLianwei Wang } 9682525756SAlan Stern 970e06b4a8SRafael J. Wysocki /* If set, devices may be suspended and resumed asynchronously. */ 980e06b4a8SRafael J. Wysocki int pm_async_enabled = 1; 990e06b4a8SRafael J. Wysocki 1000e06b4a8SRafael J. Wysocki static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr, 1010e06b4a8SRafael J. Wysocki char *buf) 1020e06b4a8SRafael J. Wysocki { 1030e06b4a8SRafael J. Wysocki return sprintf(buf, "%d\n", pm_async_enabled); 1040e06b4a8SRafael J. Wysocki } 1050e06b4a8SRafael J. Wysocki 1060e06b4a8SRafael J. Wysocki static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr, 1070e06b4a8SRafael J. Wysocki const char *buf, size_t n) 1080e06b4a8SRafael J. Wysocki { 1090e06b4a8SRafael J. Wysocki unsigned long val; 1100e06b4a8SRafael J. Wysocki 111883ee4f7SDaniel Walter if (kstrtoul(buf, 10, &val)) 1120e06b4a8SRafael J. Wysocki return -EINVAL; 1130e06b4a8SRafael J. Wysocki 1140e06b4a8SRafael J. Wysocki if (val > 1) 1150e06b4a8SRafael J. Wysocki return -EINVAL; 1160e06b4a8SRafael J. Wysocki 1170e06b4a8SRafael J. Wysocki pm_async_enabled = val; 1180e06b4a8SRafael J. Wysocki return n; 1190e06b4a8SRafael J. Wysocki } 1200e06b4a8SRafael J. Wysocki 1210e06b4a8SRafael J. Wysocki power_attr(pm_async); 1220e06b4a8SRafael J. Wysocki 123406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND 124406e7938SRafael J. Wysocki static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr, 125406e7938SRafael J. Wysocki char *buf) 126406e7938SRafael J. Wysocki { 127406e7938SRafael J. Wysocki char *s = buf; 128406e7938SRafael J. Wysocki suspend_state_t i; 129406e7938SRafael J. Wysocki 130406e7938SRafael J. Wysocki for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) 131406e7938SRafael J. Wysocki if (mem_sleep_states[i]) { 132406e7938SRafael J. Wysocki const char *label = mem_sleep_states[i]; 133406e7938SRafael J. Wysocki 134406e7938SRafael J. Wysocki if (mem_sleep_current == i) 135406e7938SRafael J. Wysocki s += sprintf(s, "[%s] ", label); 136406e7938SRafael J. Wysocki else 137406e7938SRafael J. Wysocki s += sprintf(s, "%s ", label); 138406e7938SRafael J. Wysocki } 139406e7938SRafael J. Wysocki 140406e7938SRafael J. Wysocki /* Convert the last space to a newline if needed. */ 141406e7938SRafael J. Wysocki if (s != buf) 142406e7938SRafael J. Wysocki *(s-1) = '\n'; 143406e7938SRafael J. Wysocki 144406e7938SRafael J. Wysocki return (s - buf); 145406e7938SRafael J. Wysocki } 146406e7938SRafael J. Wysocki 147406e7938SRafael J. Wysocki static suspend_state_t decode_suspend_state(const char *buf, size_t n) 148406e7938SRafael J. Wysocki { 149406e7938SRafael J. Wysocki suspend_state_t state; 150406e7938SRafael J. Wysocki char *p; 151406e7938SRafael J. Wysocki int len; 152406e7938SRafael J. Wysocki 153406e7938SRafael J. Wysocki p = memchr(buf, '\n', n); 154406e7938SRafael J. Wysocki len = p ? p - buf : n; 155406e7938SRafael J. Wysocki 156406e7938SRafael J. Wysocki for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) { 157406e7938SRafael J. Wysocki const char *label = mem_sleep_states[state]; 158406e7938SRafael J. Wysocki 159406e7938SRafael J. Wysocki if (label && len == strlen(label) && !strncmp(buf, label, len)) 160406e7938SRafael J. Wysocki return state; 161406e7938SRafael J. Wysocki } 162406e7938SRafael J. Wysocki 163406e7938SRafael J. Wysocki return PM_SUSPEND_ON; 164406e7938SRafael J. Wysocki } 165406e7938SRafael J. Wysocki 166406e7938SRafael J. Wysocki static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr, 167406e7938SRafael J. Wysocki const char *buf, size_t n) 168406e7938SRafael J. Wysocki { 169406e7938SRafael J. Wysocki suspend_state_t state; 170406e7938SRafael J. Wysocki int error; 171406e7938SRafael J. Wysocki 172406e7938SRafael J. Wysocki error = pm_autosleep_lock(); 173406e7938SRafael J. Wysocki if (error) 174406e7938SRafael J. Wysocki return error; 175406e7938SRafael J. Wysocki 176406e7938SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 177406e7938SRafael J. Wysocki error = -EBUSY; 178406e7938SRafael J. Wysocki goto out; 179406e7938SRafael J. Wysocki } 180406e7938SRafael J. Wysocki 181406e7938SRafael J. Wysocki state = decode_suspend_state(buf, n); 182406e7938SRafael J. Wysocki if (state < PM_SUSPEND_MAX && state > PM_SUSPEND_ON) 183406e7938SRafael J. Wysocki mem_sleep_current = state; 184406e7938SRafael J. Wysocki else 185406e7938SRafael J. Wysocki error = -EINVAL; 186406e7938SRafael J. Wysocki 187406e7938SRafael J. Wysocki out: 188406e7938SRafael J. Wysocki pm_autosleep_unlock(); 189406e7938SRafael J. Wysocki return error ? error : n; 190406e7938SRafael J. Wysocki } 191406e7938SRafael J. Wysocki 192406e7938SRafael J. Wysocki power_attr(mem_sleep); 193*c052bf82SJonas Meurer 194*c052bf82SJonas Meurer /* 195*c052bf82SJonas Meurer * sync_on_suspend: invoke ksys_sync_helper() before suspend. 196*c052bf82SJonas Meurer * 197*c052bf82SJonas Meurer * show() returns whether ksys_sync_helper() is invoked before suspend. 198*c052bf82SJonas Meurer * store() accepts 0 or 1. 0 disables ksys_sync_helper() and 1 enables it. 199*c052bf82SJonas Meurer */ 200*c052bf82SJonas Meurer bool sync_on_suspend_enabled = !IS_ENABLED(CONFIG_SUSPEND_SKIP_SYNC); 201*c052bf82SJonas Meurer 202*c052bf82SJonas Meurer static ssize_t sync_on_suspend_show(struct kobject *kobj, 203*c052bf82SJonas Meurer struct kobj_attribute *attr, char *buf) 204*c052bf82SJonas Meurer { 205*c052bf82SJonas Meurer return sprintf(buf, "%d\n", sync_on_suspend_enabled); 206*c052bf82SJonas Meurer } 207*c052bf82SJonas Meurer 208*c052bf82SJonas Meurer static ssize_t sync_on_suspend_store(struct kobject *kobj, 209*c052bf82SJonas Meurer struct kobj_attribute *attr, 210*c052bf82SJonas Meurer const char *buf, size_t n) 211*c052bf82SJonas Meurer { 212*c052bf82SJonas Meurer unsigned long val; 213*c052bf82SJonas Meurer 214*c052bf82SJonas Meurer if (kstrtoul(buf, 10, &val)) 215*c052bf82SJonas Meurer return -EINVAL; 216*c052bf82SJonas Meurer 217*c052bf82SJonas Meurer if (val > 1) 218*c052bf82SJonas Meurer return -EINVAL; 219*c052bf82SJonas Meurer 220*c052bf82SJonas Meurer sync_on_suspend_enabled = !!val; 221*c052bf82SJonas Meurer return n; 222*c052bf82SJonas Meurer } 223*c052bf82SJonas Meurer 224*c052bf82SJonas Meurer power_attr(sync_on_suspend); 225406e7938SRafael J. Wysocki #endif /* CONFIG_SUSPEND */ 226406e7938SRafael J. Wysocki 227e516a1dbSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 2280e7d56e3SRafael J. Wysocki int pm_test_level = TEST_NONE; 2290e7d56e3SRafael J. Wysocki 2300e7d56e3SRafael J. Wysocki static const char * const pm_tests[__TEST_AFTER_LAST] = { 2310e7d56e3SRafael J. Wysocki [TEST_NONE] = "none", 2320e7d56e3SRafael J. Wysocki [TEST_CORE] = "core", 2330e7d56e3SRafael J. Wysocki [TEST_CPUS] = "processors", 2340e7d56e3SRafael J. Wysocki [TEST_PLATFORM] = "platform", 2350e7d56e3SRafael J. Wysocki [TEST_DEVICES] = "devices", 2360e7d56e3SRafael J. Wysocki [TEST_FREEZER] = "freezer", 2370e7d56e3SRafael J. Wysocki }; 2380e7d56e3SRafael J. Wysocki 239039a75c6SRafael J. Wysocki static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr, 240039a75c6SRafael J. Wysocki char *buf) 2410e7d56e3SRafael J. Wysocki { 2420e7d56e3SRafael J. Wysocki char *s = buf; 2430e7d56e3SRafael J. Wysocki int level; 2440e7d56e3SRafael J. Wysocki 2450e7d56e3SRafael J. Wysocki for (level = TEST_FIRST; level <= TEST_MAX; level++) 2460e7d56e3SRafael J. Wysocki if (pm_tests[level]) { 2470e7d56e3SRafael J. Wysocki if (level == pm_test_level) 2480e7d56e3SRafael J. Wysocki s += sprintf(s, "[%s] ", pm_tests[level]); 2490e7d56e3SRafael J. Wysocki else 2500e7d56e3SRafael J. Wysocki s += sprintf(s, "%s ", pm_tests[level]); 2510e7d56e3SRafael J. Wysocki } 2520e7d56e3SRafael J. Wysocki 2530e7d56e3SRafael J. Wysocki if (s != buf) 2540e7d56e3SRafael J. Wysocki /* convert the last space to a newline */ 2550e7d56e3SRafael J. Wysocki *(s-1) = '\n'; 2560e7d56e3SRafael J. Wysocki 2570e7d56e3SRafael J. Wysocki return (s - buf); 2580e7d56e3SRafael J. Wysocki } 2590e7d56e3SRafael J. Wysocki 260039a75c6SRafael J. Wysocki static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, 261039a75c6SRafael J. Wysocki const char *buf, size_t n) 2620e7d56e3SRafael J. Wysocki { 2630e7d56e3SRafael J. Wysocki const char * const *s; 2640e7d56e3SRafael J. Wysocki int level; 2650e7d56e3SRafael J. Wysocki char *p; 2660e7d56e3SRafael J. Wysocki int len; 2670e7d56e3SRafael J. Wysocki int error = -EINVAL; 2680e7d56e3SRafael J. Wysocki 2690e7d56e3SRafael J. Wysocki p = memchr(buf, '\n', n); 2700e7d56e3SRafael J. Wysocki len = p ? p - buf : n; 2710e7d56e3SRafael J. Wysocki 272bcda53faSSrivatsa S. Bhat lock_system_sleep(); 2730e7d56e3SRafael J. Wysocki 2740e7d56e3SRafael J. Wysocki level = TEST_FIRST; 2750e7d56e3SRafael J. Wysocki for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++) 2760e7d56e3SRafael J. Wysocki if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) { 2770e7d56e3SRafael J. Wysocki pm_test_level = level; 2780e7d56e3SRafael J. Wysocki error = 0; 2790e7d56e3SRafael J. Wysocki break; 2800e7d56e3SRafael J. Wysocki } 2810e7d56e3SRafael J. Wysocki 282bcda53faSSrivatsa S. Bhat unlock_system_sleep(); 2830e7d56e3SRafael J. Wysocki 2840e7d56e3SRafael J. Wysocki return error ? error : n; 2850e7d56e3SRafael J. Wysocki } 2860e7d56e3SRafael J. Wysocki 2870e7d56e3SRafael J. Wysocki power_attr(pm_test); 288e516a1dbSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */ 2890e7d56e3SRafael J. Wysocki 2902a77c46dSShuoX Liu static char *suspend_step_name(enum suspend_stat_step step) 2912a77c46dSShuoX Liu { 2922a77c46dSShuoX Liu switch (step) { 2932a77c46dSShuoX Liu case SUSPEND_FREEZE: 2942a77c46dSShuoX Liu return "freeze"; 2952a77c46dSShuoX Liu case SUSPEND_PREPARE: 2962a77c46dSShuoX Liu return "prepare"; 2972a77c46dSShuoX Liu case SUSPEND_SUSPEND: 2982a77c46dSShuoX Liu return "suspend"; 2992a77c46dSShuoX Liu case SUSPEND_SUSPEND_NOIRQ: 3002a77c46dSShuoX Liu return "suspend_noirq"; 3012a77c46dSShuoX Liu case SUSPEND_RESUME_NOIRQ: 3022a77c46dSShuoX Liu return "resume_noirq"; 3032a77c46dSShuoX Liu case SUSPEND_RESUME: 3042a77c46dSShuoX Liu return "resume"; 3052a77c46dSShuoX Liu default: 3062a77c46dSShuoX Liu return ""; 3072a77c46dSShuoX Liu } 3082a77c46dSShuoX Liu } 3092a77c46dSShuoX Liu 3102c8db5beSKalesh Singh #define suspend_attr(_name) \ 3112c8db5beSKalesh Singh static ssize_t _name##_show(struct kobject *kobj, \ 3122c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) \ 3132c8db5beSKalesh Singh { \ 3142c8db5beSKalesh Singh return sprintf(buf, "%d\n", suspend_stats._name); \ 3152c8db5beSKalesh Singh } \ 3162c8db5beSKalesh Singh static struct kobj_attribute _name = __ATTR_RO(_name) 3172c8db5beSKalesh Singh 3182c8db5beSKalesh Singh suspend_attr(success); 3192c8db5beSKalesh Singh suspend_attr(fail); 3202c8db5beSKalesh Singh suspend_attr(failed_freeze); 3212c8db5beSKalesh Singh suspend_attr(failed_prepare); 3222c8db5beSKalesh Singh suspend_attr(failed_suspend); 3232c8db5beSKalesh Singh suspend_attr(failed_suspend_late); 3242c8db5beSKalesh Singh suspend_attr(failed_suspend_noirq); 3252c8db5beSKalesh Singh suspend_attr(failed_resume); 3262c8db5beSKalesh Singh suspend_attr(failed_resume_early); 3272c8db5beSKalesh Singh suspend_attr(failed_resume_noirq); 3282c8db5beSKalesh Singh 3292c8db5beSKalesh Singh static ssize_t last_failed_dev_show(struct kobject *kobj, 3302c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 3312c8db5beSKalesh Singh { 3322c8db5beSKalesh Singh int index; 3332c8db5beSKalesh Singh char *last_failed_dev = NULL; 3342c8db5beSKalesh Singh 3352c8db5beSKalesh Singh index = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; 3362c8db5beSKalesh Singh index %= REC_FAILED_NUM; 3372c8db5beSKalesh Singh last_failed_dev = suspend_stats.failed_devs[index]; 3382c8db5beSKalesh Singh 3392c8db5beSKalesh Singh return sprintf(buf, "%s\n", last_failed_dev); 3402c8db5beSKalesh Singh } 3412c8db5beSKalesh Singh static struct kobj_attribute last_failed_dev = __ATTR_RO(last_failed_dev); 3422c8db5beSKalesh Singh 3432c8db5beSKalesh Singh static ssize_t last_failed_errno_show(struct kobject *kobj, 3442c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 3452c8db5beSKalesh Singh { 3462c8db5beSKalesh Singh int index; 3472c8db5beSKalesh Singh int last_failed_errno; 3482c8db5beSKalesh Singh 3492c8db5beSKalesh Singh index = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1; 3502c8db5beSKalesh Singh index %= REC_FAILED_NUM; 3512c8db5beSKalesh Singh last_failed_errno = suspend_stats.errno[index]; 3522c8db5beSKalesh Singh 3532c8db5beSKalesh Singh return sprintf(buf, "%d\n", last_failed_errno); 3542c8db5beSKalesh Singh } 3552c8db5beSKalesh Singh static struct kobj_attribute last_failed_errno = __ATTR_RO(last_failed_errno); 3562c8db5beSKalesh Singh 3572c8db5beSKalesh Singh static ssize_t last_failed_step_show(struct kobject *kobj, 3582c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 3592c8db5beSKalesh Singh { 3602c8db5beSKalesh Singh int index; 3612c8db5beSKalesh Singh enum suspend_stat_step step; 3622c8db5beSKalesh Singh char *last_failed_step = NULL; 3632c8db5beSKalesh Singh 3642c8db5beSKalesh Singh index = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; 3652c8db5beSKalesh Singh index %= REC_FAILED_NUM; 3662c8db5beSKalesh Singh step = suspend_stats.failed_steps[index]; 3672c8db5beSKalesh Singh last_failed_step = suspend_step_name(step); 3682c8db5beSKalesh Singh 3692c8db5beSKalesh Singh return sprintf(buf, "%s\n", last_failed_step); 3702c8db5beSKalesh Singh } 3712c8db5beSKalesh Singh static struct kobj_attribute last_failed_step = __ATTR_RO(last_failed_step); 3722c8db5beSKalesh Singh 3732c8db5beSKalesh Singh static struct attribute *suspend_attrs[] = { 3742c8db5beSKalesh Singh &success.attr, 3752c8db5beSKalesh Singh &fail.attr, 3762c8db5beSKalesh Singh &failed_freeze.attr, 3772c8db5beSKalesh Singh &failed_prepare.attr, 3782c8db5beSKalesh Singh &failed_suspend.attr, 3792c8db5beSKalesh Singh &failed_suspend_late.attr, 3802c8db5beSKalesh Singh &failed_suspend_noirq.attr, 3812c8db5beSKalesh Singh &failed_resume.attr, 3822c8db5beSKalesh Singh &failed_resume_early.attr, 3832c8db5beSKalesh Singh &failed_resume_noirq.attr, 3842c8db5beSKalesh Singh &last_failed_dev.attr, 3852c8db5beSKalesh Singh &last_failed_errno.attr, 3862c8db5beSKalesh Singh &last_failed_step.attr, 3872c8db5beSKalesh Singh NULL, 3882c8db5beSKalesh Singh }; 3892c8db5beSKalesh Singh 3902c8db5beSKalesh Singh static struct attribute_group suspend_attr_group = { 3912c8db5beSKalesh Singh .name = "suspend_stats", 3922c8db5beSKalesh Singh .attrs = suspend_attrs, 3932c8db5beSKalesh Singh }; 3942c8db5beSKalesh Singh 3952c8db5beSKalesh Singh #ifdef CONFIG_DEBUG_FS 3962a77c46dSShuoX Liu static int suspend_stats_show(struct seq_file *s, void *unused) 3972a77c46dSShuoX Liu { 3982a77c46dSShuoX Liu int i, index, last_dev, last_errno, last_step; 3992a77c46dSShuoX Liu 4002a77c46dSShuoX Liu last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; 4012a77c46dSShuoX Liu last_dev %= REC_FAILED_NUM; 4022a77c46dSShuoX Liu last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1; 4032a77c46dSShuoX Liu last_errno %= REC_FAILED_NUM; 4042a77c46dSShuoX Liu last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; 4052a77c46dSShuoX Liu last_step %= REC_FAILED_NUM; 406cf579dfbSRafael J. Wysocki seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n" 407cf579dfbSRafael J. Wysocki "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n", 4082a77c46dSShuoX Liu "success", suspend_stats.success, 4092a77c46dSShuoX Liu "fail", suspend_stats.fail, 4102a77c46dSShuoX Liu "failed_freeze", suspend_stats.failed_freeze, 4112a77c46dSShuoX Liu "failed_prepare", suspend_stats.failed_prepare, 4122a77c46dSShuoX Liu "failed_suspend", suspend_stats.failed_suspend, 413cf579dfbSRafael J. Wysocki "failed_suspend_late", 414cf579dfbSRafael J. Wysocki suspend_stats.failed_suspend_late, 4152a77c46dSShuoX Liu "failed_suspend_noirq", 4162a77c46dSShuoX Liu suspend_stats.failed_suspend_noirq, 4172a77c46dSShuoX Liu "failed_resume", suspend_stats.failed_resume, 418cf579dfbSRafael J. Wysocki "failed_resume_early", 419cf579dfbSRafael J. Wysocki suspend_stats.failed_resume_early, 4202a77c46dSShuoX Liu "failed_resume_noirq", 4212a77c46dSShuoX Liu suspend_stats.failed_resume_noirq); 4222a77c46dSShuoX Liu seq_printf(s, "failures:\n last_failed_dev:\t%-s\n", 4232a77c46dSShuoX Liu suspend_stats.failed_devs[last_dev]); 4242a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4252a77c46dSShuoX Liu index = last_dev + REC_FAILED_NUM - i; 4262a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4272a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-s\n", 4282a77c46dSShuoX Liu suspend_stats.failed_devs[index]); 4292a77c46dSShuoX Liu } 4302a77c46dSShuoX Liu seq_printf(s, " last_failed_errno:\t%-d\n", 4312a77c46dSShuoX Liu suspend_stats.errno[last_errno]); 4322a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4332a77c46dSShuoX Liu index = last_errno + REC_FAILED_NUM - i; 4342a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4352a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-d\n", 4362a77c46dSShuoX Liu suspend_stats.errno[index]); 4372a77c46dSShuoX Liu } 4382a77c46dSShuoX Liu seq_printf(s, " last_failed_step:\t%-s\n", 4392a77c46dSShuoX Liu suspend_step_name( 4402a77c46dSShuoX Liu suspend_stats.failed_steps[last_step])); 4412a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4422a77c46dSShuoX Liu index = last_step + REC_FAILED_NUM - i; 4432a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4442a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-s\n", 4452a77c46dSShuoX Liu suspend_step_name( 4462a77c46dSShuoX Liu suspend_stats.failed_steps[index])); 4472a77c46dSShuoX Liu } 4482a77c46dSShuoX Liu 4492a77c46dSShuoX Liu return 0; 4502a77c46dSShuoX Liu } 451943a10f8SYangtao Li DEFINE_SHOW_ATTRIBUTE(suspend_stats); 4522a77c46dSShuoX Liu 4532a77c46dSShuoX Liu static int __init pm_debugfs_init(void) 4542a77c46dSShuoX Liu { 4552a77c46dSShuoX Liu debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO, 456943a10f8SYangtao Li NULL, NULL, &suspend_stats_fops); 4572a77c46dSShuoX Liu return 0; 4582a77c46dSShuoX Liu } 4592a77c46dSShuoX Liu 4602a77c46dSShuoX Liu late_initcall(pm_debugfs_init); 4612a77c46dSShuoX Liu #endif /* CONFIG_DEBUG_FS */ 4622a77c46dSShuoX Liu 463ca123102SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 464ca123102SRafael J. Wysocki 465b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 466b2df1d4fSRafael J. Wysocki /* 467b2df1d4fSRafael J. Wysocki * pm_print_times: print time taken by devices to suspend and resume. 468b2df1d4fSRafael J. Wysocki * 469b2df1d4fSRafael J. Wysocki * show() returns whether printing of suspend and resume times is enabled. 470b2df1d4fSRafael J. Wysocki * store() accepts 0 or 1. 0 disables printing and 1 enables it. 471b2df1d4fSRafael J. Wysocki */ 472b2df1d4fSRafael J. Wysocki bool pm_print_times_enabled; 473b2df1d4fSRafael J. Wysocki 474b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_show(struct kobject *kobj, 475b2df1d4fSRafael J. Wysocki struct kobj_attribute *attr, char *buf) 476b2df1d4fSRafael J. Wysocki { 477b2df1d4fSRafael J. Wysocki return sprintf(buf, "%d\n", pm_print_times_enabled); 478b2df1d4fSRafael J. Wysocki } 479b2df1d4fSRafael J. Wysocki 480b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_store(struct kobject *kobj, 481b2df1d4fSRafael J. Wysocki struct kobj_attribute *attr, 482b2df1d4fSRafael J. Wysocki const char *buf, size_t n) 483b2df1d4fSRafael J. Wysocki { 484b2df1d4fSRafael J. Wysocki unsigned long val; 485b2df1d4fSRafael J. Wysocki 486b2df1d4fSRafael J. Wysocki if (kstrtoul(buf, 10, &val)) 487b2df1d4fSRafael J. Wysocki return -EINVAL; 488b2df1d4fSRafael J. Wysocki 489b2df1d4fSRafael J. Wysocki if (val > 1) 490b2df1d4fSRafael J. Wysocki return -EINVAL; 491b2df1d4fSRafael J. Wysocki 492b2df1d4fSRafael J. Wysocki pm_print_times_enabled = !!val; 493b2df1d4fSRafael J. Wysocki return n; 494b2df1d4fSRafael J. Wysocki } 495b2df1d4fSRafael J. Wysocki 496b2df1d4fSRafael J. Wysocki power_attr(pm_print_times); 497b2df1d4fSRafael J. Wysocki 498b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) 499b2df1d4fSRafael J. Wysocki { 500b2df1d4fSRafael J. Wysocki pm_print_times_enabled = !!initcall_debug; 501b2df1d4fSRafael J. Wysocki } 502a6f5f0ddSAlexandra Yates 503a6f5f0ddSAlexandra Yates static ssize_t pm_wakeup_irq_show(struct kobject *kobj, 504a6f5f0ddSAlexandra Yates struct kobj_attribute *attr, 505a6f5f0ddSAlexandra Yates char *buf) 506a6f5f0ddSAlexandra Yates { 507a6f5f0ddSAlexandra Yates return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA; 508a6f5f0ddSAlexandra Yates } 509a6f5f0ddSAlexandra Yates 510a1e9ca69SRafael J. Wysocki power_attr_ro(pm_wakeup_irq); 511a6f5f0ddSAlexandra Yates 512726fb6b4SSrinivas Pandruvada bool pm_debug_messages_on __read_mostly; 5138d8b2441SRafael J. Wysocki 5148d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_show(struct kobject *kobj, 5158d8b2441SRafael J. Wysocki struct kobj_attribute *attr, char *buf) 5168d8b2441SRafael J. Wysocki { 5178d8b2441SRafael J. Wysocki return sprintf(buf, "%d\n", pm_debug_messages_on); 5188d8b2441SRafael J. Wysocki } 5198d8b2441SRafael J. Wysocki 5208d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_store(struct kobject *kobj, 5218d8b2441SRafael J. Wysocki struct kobj_attribute *attr, 5228d8b2441SRafael J. Wysocki const char *buf, size_t n) 5238d8b2441SRafael J. Wysocki { 5248d8b2441SRafael J. Wysocki unsigned long val; 5258d8b2441SRafael J. Wysocki 5268d8b2441SRafael J. Wysocki if (kstrtoul(buf, 10, &val)) 5278d8b2441SRafael J. Wysocki return -EINVAL; 5288d8b2441SRafael J. Wysocki 5298d8b2441SRafael J. Wysocki if (val > 1) 5308d8b2441SRafael J. Wysocki return -EINVAL; 5318d8b2441SRafael J. Wysocki 5328d8b2441SRafael J. Wysocki pm_debug_messages_on = !!val; 5338d8b2441SRafael J. Wysocki return n; 5348d8b2441SRafael J. Wysocki } 5358d8b2441SRafael J. Wysocki 5368d8b2441SRafael J. Wysocki power_attr(pm_debug_messages); 5378d8b2441SRafael J. Wysocki 5388d8b2441SRafael J. Wysocki /** 539cb08e035SRafael J. Wysocki * __pm_pr_dbg - Print a suspend debug message to the kernel log. 540cb08e035SRafael J. Wysocki * @defer: Whether or not to use printk_deferred() to print the message. 5418d8b2441SRafael J. Wysocki * @fmt: Message format. 5428d8b2441SRafael J. Wysocki * 5438d8b2441SRafael J. Wysocki * The message will be emitted if enabled through the pm_debug_messages 5448d8b2441SRafael J. Wysocki * sysfs attribute. 5458d8b2441SRafael J. Wysocki */ 546cb08e035SRafael J. Wysocki void __pm_pr_dbg(bool defer, const char *fmt, ...) 5478d8b2441SRafael J. Wysocki { 5488d8b2441SRafael J. Wysocki struct va_format vaf; 5498d8b2441SRafael J. Wysocki va_list args; 5508d8b2441SRafael J. Wysocki 5518d8b2441SRafael J. Wysocki if (!pm_debug_messages_on) 5528d8b2441SRafael J. Wysocki return; 5538d8b2441SRafael J. Wysocki 5548d8b2441SRafael J. Wysocki va_start(args, fmt); 5558d8b2441SRafael J. Wysocki 5568d8b2441SRafael J. Wysocki vaf.fmt = fmt; 5578d8b2441SRafael J. Wysocki vaf.va = &args; 5588d8b2441SRafael J. Wysocki 559cb08e035SRafael J. Wysocki if (defer) 560cb08e035SRafael J. Wysocki printk_deferred(KERN_DEBUG "PM: %pV", &vaf); 561cb08e035SRafael J. Wysocki else 5628d8b2441SRafael J. Wysocki printk(KERN_DEBUG "PM: %pV", &vaf); 5638d8b2441SRafael J. Wysocki 5648d8b2441SRafael J. Wysocki va_end(args); 5658d8b2441SRafael J. Wysocki } 5668d8b2441SRafael J. Wysocki 567819b1bb3SRafael J. Wysocki #else /* !CONFIG_PM_SLEEP_DEBUG */ 568b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) {} 569b2df1d4fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */ 570b2df1d4fSRafael J. Wysocki 571d76e15fbSGreg Kroah-Hartman struct kobject *power_kobj; 5721da177e4SLinus Torvalds 5731da177e4SLinus Torvalds /** 5740399d4dbSRafael J. Wysocki * state - control system sleep states. 5751da177e4SLinus Torvalds * 5760399d4dbSRafael J. Wysocki * show() returns available sleep state labels, which may be "mem", "standby", 57744348e8aSMauro Carvalho Chehab * "freeze" and "disk" (hibernation). 57844348e8aSMauro Carvalho Chehab * See Documentation/admin-guide/pm/sleep-states.rst for a description of 57944348e8aSMauro Carvalho Chehab * what they mean. 5801da177e4SLinus Torvalds * 5810399d4dbSRafael J. Wysocki * store() accepts one of those strings, translates it into the proper 5820399d4dbSRafael J. Wysocki * enumerated value, and initiates a suspend transition. 5831da177e4SLinus Torvalds */ 584386f275fSKay Sievers static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, 585386f275fSKay Sievers char *buf) 5861da177e4SLinus Torvalds { 5871da177e4SLinus Torvalds char *s = buf; 588296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 58927ddcc65SRafael J. Wysocki suspend_state_t i; 5901da177e4SLinus Torvalds 59127ddcc65SRafael J. Wysocki for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) 592d431cbc5SRafael J. Wysocki if (pm_states[i]) 593d431cbc5SRafael J. Wysocki s += sprintf(s,"%s ", pm_states[i]); 59427ddcc65SRafael J. Wysocki 595296699deSRafael J. Wysocki #endif 596a6e15a39SKees Cook if (hibernation_available()) 597a6e15a39SKees Cook s += sprintf(s, "disk "); 598a3d25c27SRafael J. Wysocki if (s != buf) 599a3d25c27SRafael J. Wysocki /* convert the last space to a newline */ 600a3d25c27SRafael J. Wysocki *(s-1) = '\n'; 6011da177e4SLinus Torvalds return (s - buf); 6021da177e4SLinus Torvalds } 6031da177e4SLinus Torvalds 6047483b4a4SRafael J. Wysocki static suspend_state_t decode_state(const char *buf, size_t n) 6051da177e4SLinus Torvalds { 606296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 607d431cbc5SRafael J. Wysocki suspend_state_t state; 608296699deSRafael J. Wysocki #endif 6091da177e4SLinus Torvalds char *p; 6101da177e4SLinus Torvalds int len; 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds p = memchr(buf, '\n', n); 6131da177e4SLinus Torvalds len = p ? p - buf : n; 6141da177e4SLinus Torvalds 6157483b4a4SRafael J. Wysocki /* Check hibernation first. */ 616d30bdfc0SChuhong Yuan if (len == 4 && str_has_prefix(buf, "disk")) 6177483b4a4SRafael J. Wysocki return PM_SUSPEND_MAX; 618a3d25c27SRafael J. Wysocki 619296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 620d431cbc5SRafael J. Wysocki for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) { 621d431cbc5SRafael J. Wysocki const char *label = pm_states[state]; 622d431cbc5SRafael J. Wysocki 623d431cbc5SRafael J. Wysocki if (label && len == strlen(label) && !strncmp(buf, label, len)) 624d431cbc5SRafael J. Wysocki return state; 625d431cbc5SRafael J. Wysocki } 626296699deSRafael J. Wysocki #endif 627296699deSRafael J. Wysocki 6287483b4a4SRafael J. Wysocki return PM_SUSPEND_ON; 6297483b4a4SRafael J. Wysocki } 6307483b4a4SRafael J. Wysocki 6317483b4a4SRafael J. Wysocki static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, 6327483b4a4SRafael J. Wysocki const char *buf, size_t n) 6337483b4a4SRafael J. Wysocki { 6347483b4a4SRafael J. Wysocki suspend_state_t state; 6357483b4a4SRafael J. Wysocki int error; 6367483b4a4SRafael J. Wysocki 6377483b4a4SRafael J. Wysocki error = pm_autosleep_lock(); 6387483b4a4SRafael J. Wysocki if (error) 6397483b4a4SRafael J. Wysocki return error; 6407483b4a4SRafael J. Wysocki 6417483b4a4SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 6427483b4a4SRafael J. Wysocki error = -EBUSY; 6437483b4a4SRafael J. Wysocki goto out; 6447483b4a4SRafael J. Wysocki } 6457483b4a4SRafael J. Wysocki 6467483b4a4SRafael J. Wysocki state = decode_state(buf, n); 647406e7938SRafael J. Wysocki if (state < PM_SUSPEND_MAX) { 648406e7938SRafael J. Wysocki if (state == PM_SUSPEND_MEM) 649406e7938SRafael J. Wysocki state = mem_sleep_current; 650406e7938SRafael J. Wysocki 6517483b4a4SRafael J. Wysocki error = pm_suspend(state); 652406e7938SRafael J. Wysocki } else if (state == PM_SUSPEND_MAX) { 6537483b4a4SRafael J. Wysocki error = hibernate(); 654406e7938SRafael J. Wysocki } else { 6557483b4a4SRafael J. Wysocki error = -EINVAL; 656406e7938SRafael J. Wysocki } 6577483b4a4SRafael J. Wysocki 6587483b4a4SRafael J. Wysocki out: 6597483b4a4SRafael J. Wysocki pm_autosleep_unlock(); 6601da177e4SLinus Torvalds return error ? error : n; 6611da177e4SLinus Torvalds } 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds power_attr(state); 6641da177e4SLinus Torvalds 665c125e96fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 666c125e96fSRafael J. Wysocki /* 667c125e96fSRafael J. Wysocki * The 'wakeup_count' attribute, along with the functions defined in 668c125e96fSRafael J. Wysocki * drivers/base/power/wakeup.c, provides a means by which wakeup events can be 669c125e96fSRafael J. Wysocki * handled in a non-racy way. 670c125e96fSRafael J. Wysocki * 671c125e96fSRafael J. Wysocki * If a wakeup event occurs when the system is in a sleep state, it simply is 672c125e96fSRafael J. Wysocki * woken up. In turn, if an event that would wake the system up from a sleep 673c125e96fSRafael J. Wysocki * state occurs when it is undergoing a transition to that sleep state, the 674c125e96fSRafael J. Wysocki * transition should be aborted. Moreover, if such an event occurs when the 675c125e96fSRafael J. Wysocki * system is in the working state, an attempt to start a transition to the 676c125e96fSRafael J. Wysocki * given sleep state should fail during certain period after the detection of 677c125e96fSRafael J. Wysocki * the event. Using the 'state' attribute alone is not sufficient to satisfy 678c125e96fSRafael J. Wysocki * these requirements, because a wakeup event may occur exactly when 'state' 679c125e96fSRafael J. Wysocki * is being written to and may be delivered to user space right before it is 680c125e96fSRafael J. Wysocki * frozen, so the event will remain only partially processed until the system is 681c125e96fSRafael J. Wysocki * woken up by another event. In particular, it won't cause the transition to 682c125e96fSRafael J. Wysocki * a sleep state to be aborted. 683c125e96fSRafael J. Wysocki * 684c125e96fSRafael J. Wysocki * This difficulty may be overcome if user space uses 'wakeup_count' before 685c125e96fSRafael J. Wysocki * writing to 'state'. It first should read from 'wakeup_count' and store 686c125e96fSRafael J. Wysocki * the read value. Then, after carrying out its own preparations for the system 687c125e96fSRafael J. Wysocki * transition to a sleep state, it should write the stored value to 68825985edcSLucas De Marchi * 'wakeup_count'. If that fails, at least one wakeup event has occurred since 689c125e96fSRafael J. Wysocki * 'wakeup_count' was read and 'state' should not be written to. Otherwise, it 690c125e96fSRafael J. Wysocki * is allowed to write to 'state', but the transition will be aborted if there 691c125e96fSRafael J. Wysocki * are any wakeup events detected after 'wakeup_count' was written to. 692c125e96fSRafael J. Wysocki */ 693c125e96fSRafael J. Wysocki 694c125e96fSRafael J. Wysocki static ssize_t wakeup_count_show(struct kobject *kobj, 695c125e96fSRafael J. Wysocki struct kobj_attribute *attr, 696c125e96fSRafael J. Wysocki char *buf) 697c125e96fSRafael J. Wysocki { 698074037ecSRafael J. Wysocki unsigned int val; 699c125e96fSRafael J. Wysocki 7007483b4a4SRafael J. Wysocki return pm_get_wakeup_count(&val, true) ? 7017483b4a4SRafael J. Wysocki sprintf(buf, "%u\n", val) : -EINTR; 702c125e96fSRafael J. Wysocki } 703c125e96fSRafael J. Wysocki 704c125e96fSRafael J. Wysocki static ssize_t wakeup_count_store(struct kobject *kobj, 705c125e96fSRafael J. Wysocki struct kobj_attribute *attr, 706c125e96fSRafael J. Wysocki const char *buf, size_t n) 707c125e96fSRafael J. Wysocki { 708074037ecSRafael J. Wysocki unsigned int val; 7097483b4a4SRafael J. Wysocki int error; 710c125e96fSRafael J. Wysocki 7117483b4a4SRafael J. Wysocki error = pm_autosleep_lock(); 7127483b4a4SRafael J. Wysocki if (error) 7137483b4a4SRafael J. Wysocki return error; 7147483b4a4SRafael J. Wysocki 7157483b4a4SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 7167483b4a4SRafael J. Wysocki error = -EBUSY; 7177483b4a4SRafael J. Wysocki goto out; 7187483b4a4SRafael J. Wysocki } 7197483b4a4SRafael J. Wysocki 7207483b4a4SRafael J. Wysocki error = -EINVAL; 721074037ecSRafael J. Wysocki if (sscanf(buf, "%u", &val) == 1) { 722c125e96fSRafael J. Wysocki if (pm_save_wakeup_count(val)) 7237483b4a4SRafael J. Wysocki error = n; 724bb177fedSJulius Werner else 725bb177fedSJulius Werner pm_print_active_wakeup_sources(); 726c125e96fSRafael J. Wysocki } 7277483b4a4SRafael J. Wysocki 7287483b4a4SRafael J. Wysocki out: 7297483b4a4SRafael J. Wysocki pm_autosleep_unlock(); 7307483b4a4SRafael J. Wysocki return error; 731c125e96fSRafael J. Wysocki } 732c125e96fSRafael J. Wysocki 733c125e96fSRafael J. Wysocki power_attr(wakeup_count); 7347483b4a4SRafael J. Wysocki 7357483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP 7367483b4a4SRafael J. Wysocki static ssize_t autosleep_show(struct kobject *kobj, 7377483b4a4SRafael J. Wysocki struct kobj_attribute *attr, 7387483b4a4SRafael J. Wysocki char *buf) 7397483b4a4SRafael J. Wysocki { 7407483b4a4SRafael J. Wysocki suspend_state_t state = pm_autosleep_state(); 7417483b4a4SRafael J. Wysocki 7427483b4a4SRafael J. Wysocki if (state == PM_SUSPEND_ON) 7437483b4a4SRafael J. Wysocki return sprintf(buf, "off\n"); 7447483b4a4SRafael J. Wysocki 7457483b4a4SRafael J. Wysocki #ifdef CONFIG_SUSPEND 7467483b4a4SRafael J. Wysocki if (state < PM_SUSPEND_MAX) 747d431cbc5SRafael J. Wysocki return sprintf(buf, "%s\n", pm_states[state] ? 748d431cbc5SRafael J. Wysocki pm_states[state] : "error"); 7497483b4a4SRafael J. Wysocki #endif 7507483b4a4SRafael J. Wysocki #ifdef CONFIG_HIBERNATION 7517483b4a4SRafael J. Wysocki return sprintf(buf, "disk\n"); 7527483b4a4SRafael J. Wysocki #else 7537483b4a4SRafael J. Wysocki return sprintf(buf, "error"); 7547483b4a4SRafael J. Wysocki #endif 7557483b4a4SRafael J. Wysocki } 7567483b4a4SRafael J. Wysocki 7577483b4a4SRafael J. Wysocki static ssize_t autosleep_store(struct kobject *kobj, 7587483b4a4SRafael J. Wysocki struct kobj_attribute *attr, 7597483b4a4SRafael J. Wysocki const char *buf, size_t n) 7607483b4a4SRafael J. Wysocki { 7617483b4a4SRafael J. Wysocki suspend_state_t state = decode_state(buf, n); 7627483b4a4SRafael J. Wysocki int error; 7637483b4a4SRafael J. Wysocki 7647483b4a4SRafael J. Wysocki if (state == PM_SUSPEND_ON 765040e5bf6SArve Hjønnevåg && strcmp(buf, "off") && strcmp(buf, "off\n")) 7667483b4a4SRafael J. Wysocki return -EINVAL; 7677483b4a4SRafael J. Wysocki 768406e7938SRafael J. Wysocki if (state == PM_SUSPEND_MEM) 769406e7938SRafael J. Wysocki state = mem_sleep_current; 770406e7938SRafael J. Wysocki 7717483b4a4SRafael J. Wysocki error = pm_autosleep_set_state(state); 7727483b4a4SRafael J. Wysocki return error ? error : n; 7737483b4a4SRafael J. Wysocki } 7747483b4a4SRafael J. Wysocki 7757483b4a4SRafael J. Wysocki power_attr(autosleep); 7767483b4a4SRafael J. Wysocki #endif /* CONFIG_PM_AUTOSLEEP */ 777b86ff982SRafael J. Wysocki 778b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS 779b86ff982SRafael J. Wysocki static ssize_t wake_lock_show(struct kobject *kobj, 780b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 781b86ff982SRafael J. Wysocki char *buf) 782b86ff982SRafael J. Wysocki { 783b86ff982SRafael J. Wysocki return pm_show_wakelocks(buf, true); 784b86ff982SRafael J. Wysocki } 785b86ff982SRafael J. Wysocki 786b86ff982SRafael J. Wysocki static ssize_t wake_lock_store(struct kobject *kobj, 787b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 788b86ff982SRafael J. Wysocki const char *buf, size_t n) 789b86ff982SRafael J. Wysocki { 790b86ff982SRafael J. Wysocki int error = pm_wake_lock(buf); 791b86ff982SRafael J. Wysocki return error ? error : n; 792b86ff982SRafael J. Wysocki } 793b86ff982SRafael J. Wysocki 794b86ff982SRafael J. Wysocki power_attr(wake_lock); 795b86ff982SRafael J. Wysocki 796b86ff982SRafael J. Wysocki static ssize_t wake_unlock_show(struct kobject *kobj, 797b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 798b86ff982SRafael J. Wysocki char *buf) 799b86ff982SRafael J. Wysocki { 800b86ff982SRafael J. Wysocki return pm_show_wakelocks(buf, false); 801b86ff982SRafael J. Wysocki } 802b86ff982SRafael J. Wysocki 803b86ff982SRafael J. Wysocki static ssize_t wake_unlock_store(struct kobject *kobj, 804b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 805b86ff982SRafael J. Wysocki const char *buf, size_t n) 806b86ff982SRafael J. Wysocki { 807b86ff982SRafael J. Wysocki int error = pm_wake_unlock(buf); 808b86ff982SRafael J. Wysocki return error ? error : n; 809b86ff982SRafael J. Wysocki } 810b86ff982SRafael J. Wysocki 811b86ff982SRafael J. Wysocki power_attr(wake_unlock); 812b86ff982SRafael J. Wysocki 813b86ff982SRafael J. Wysocki #endif /* CONFIG_PM_WAKELOCKS */ 814c125e96fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 815c125e96fSRafael J. Wysocki 816c5c6ba4eSRafael J. Wysocki #ifdef CONFIG_PM_TRACE 817c5c6ba4eSRafael J. Wysocki int pm_trace_enabled; 818c5c6ba4eSRafael J. Wysocki 819386f275fSKay Sievers static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr, 820386f275fSKay Sievers char *buf) 821c5c6ba4eSRafael J. Wysocki { 822c5c6ba4eSRafael J. Wysocki return sprintf(buf, "%d\n", pm_trace_enabled); 823c5c6ba4eSRafael J. Wysocki } 824c5c6ba4eSRafael J. Wysocki 825c5c6ba4eSRafael J. Wysocki static ssize_t 826386f275fSKay Sievers pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr, 827386f275fSKay Sievers const char *buf, size_t n) 828c5c6ba4eSRafael J. Wysocki { 829c5c6ba4eSRafael J. Wysocki int val; 830c5c6ba4eSRafael J. Wysocki 831c5c6ba4eSRafael J. Wysocki if (sscanf(buf, "%d", &val) == 1) { 832c5c6ba4eSRafael J. Wysocki pm_trace_enabled = !!val; 8339dceefe4SShuah Khan if (pm_trace_enabled) { 8349dceefe4SShuah Khan pr_warn("PM: Enabling pm_trace changes system date and time during resume.\n" 8359dceefe4SShuah Khan "PM: Correct system time has to be restored manually after resume.\n"); 8369dceefe4SShuah Khan } 837c5c6ba4eSRafael J. Wysocki return n; 838c5c6ba4eSRafael J. Wysocki } 839c5c6ba4eSRafael J. Wysocki return -EINVAL; 840c5c6ba4eSRafael J. Wysocki } 841c5c6ba4eSRafael J. Wysocki 842c5c6ba4eSRafael J. Wysocki power_attr(pm_trace); 843d33ac60bSJames Hogan 844d33ac60bSJames Hogan static ssize_t pm_trace_dev_match_show(struct kobject *kobj, 845d33ac60bSJames Hogan struct kobj_attribute *attr, 846d33ac60bSJames Hogan char *buf) 847d33ac60bSJames Hogan { 848d33ac60bSJames Hogan return show_trace_dev_match(buf, PAGE_SIZE); 849d33ac60bSJames Hogan } 850d33ac60bSJames Hogan 851a1e9ca69SRafael J. Wysocki power_attr_ro(pm_trace_dev_match); 852d33ac60bSJames Hogan 8530e7d56e3SRafael J. Wysocki #endif /* CONFIG_PM_TRACE */ 854c5c6ba4eSRafael J. Wysocki 855957d1282SLi Fei #ifdef CONFIG_FREEZER 856957d1282SLi Fei static ssize_t pm_freeze_timeout_show(struct kobject *kobj, 857957d1282SLi Fei struct kobj_attribute *attr, char *buf) 858957d1282SLi Fei { 859957d1282SLi Fei return sprintf(buf, "%u\n", freeze_timeout_msecs); 860957d1282SLi Fei } 861957d1282SLi Fei 862957d1282SLi Fei static ssize_t pm_freeze_timeout_store(struct kobject *kobj, 863957d1282SLi Fei struct kobj_attribute *attr, 864957d1282SLi Fei const char *buf, size_t n) 865957d1282SLi Fei { 866957d1282SLi Fei unsigned long val; 867957d1282SLi Fei 868957d1282SLi Fei if (kstrtoul(buf, 10, &val)) 869957d1282SLi Fei return -EINVAL; 870957d1282SLi Fei 871957d1282SLi Fei freeze_timeout_msecs = val; 872957d1282SLi Fei return n; 873957d1282SLi Fei } 874957d1282SLi Fei 875957d1282SLi Fei power_attr(pm_freeze_timeout); 876957d1282SLi Fei 877957d1282SLi Fei #endif /* CONFIG_FREEZER*/ 878957d1282SLi Fei 879c5c6ba4eSRafael J. Wysocki static struct attribute * g[] = { 880c5c6ba4eSRafael J. Wysocki &state_attr.attr, 8810e7d56e3SRafael J. Wysocki #ifdef CONFIG_PM_TRACE 882c5c6ba4eSRafael J. Wysocki &pm_trace_attr.attr, 883d33ac60bSJames Hogan &pm_trace_dev_match_attr.attr, 8840e7d56e3SRafael J. Wysocki #endif 8850e06b4a8SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 8860e06b4a8SRafael J. Wysocki &pm_async_attr.attr, 887c125e96fSRafael J. Wysocki &wakeup_count_attr.attr, 888406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND 889406e7938SRafael J. Wysocki &mem_sleep_attr.attr, 890*c052bf82SJonas Meurer &sync_on_suspend_attr.attr, 891406e7938SRafael J. Wysocki #endif 8927483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP 8937483b4a4SRafael J. Wysocki &autosleep_attr.attr, 8947483b4a4SRafael J. Wysocki #endif 895b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS 896b86ff982SRafael J. Wysocki &wake_lock_attr.attr, 897b86ff982SRafael J. Wysocki &wake_unlock_attr.attr, 898b86ff982SRafael J. Wysocki #endif 899b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 900e516a1dbSRafael J. Wysocki &pm_test_attr.attr, 9014b7760baSSameer Nanda &pm_print_times_attr.attr, 902a6f5f0ddSAlexandra Yates &pm_wakeup_irq_attr.attr, 9038d8b2441SRafael J. Wysocki &pm_debug_messages_attr.attr, 9040e7d56e3SRafael J. Wysocki #endif 9050e06b4a8SRafael J. Wysocki #endif 906957d1282SLi Fei #ifdef CONFIG_FREEZER 907957d1282SLi Fei &pm_freeze_timeout_attr.attr, 908957d1282SLi Fei #endif 909c5c6ba4eSRafael J. Wysocki NULL, 910c5c6ba4eSRafael J. Wysocki }; 9111da177e4SLinus Torvalds 9121d0c6e59SArvind Yadav static const struct attribute_group attr_group = { 9131da177e4SLinus Torvalds .attrs = g, 9141da177e4SLinus Torvalds }; 9151da177e4SLinus Torvalds 9162c8db5beSKalesh Singh static const struct attribute_group *attr_groups[] = { 9172c8db5beSKalesh Singh &attr_group, 9182c8db5beSKalesh Singh #ifdef CONFIG_PM_SLEEP 9192c8db5beSKalesh Singh &suspend_attr_group, 9202c8db5beSKalesh Singh #endif 9212c8db5beSKalesh Singh NULL, 9222c8db5beSKalesh Singh }; 9232c8db5beSKalesh Singh 9245e928f77SRafael J. Wysocki struct workqueue_struct *pm_wq; 9257b199ca2SAlan Stern EXPORT_SYMBOL_GPL(pm_wq); 9265e928f77SRafael J. Wysocki 9275e928f77SRafael J. Wysocki static int __init pm_start_workqueue(void) 9285e928f77SRafael J. Wysocki { 92958a69cb4STejun Heo pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0); 9305e928f77SRafael J. Wysocki 9315e928f77SRafael J. Wysocki return pm_wq ? 0 : -ENOMEM; 9325e928f77SRafael J. Wysocki } 9335e928f77SRafael J. Wysocki 9341da177e4SLinus Torvalds static int __init pm_init(void) 9351da177e4SLinus Torvalds { 9365e928f77SRafael J. Wysocki int error = pm_start_workqueue(); 9375e928f77SRafael J. Wysocki if (error) 9385e928f77SRafael J. Wysocki return error; 939ac5c24ecSRafael J. Wysocki hibernate_image_size_init(); 940ddeb6487SRafael J. Wysocki hibernate_reserved_size_init(); 941fa7fd6faSSudeep Holla pm_states_init(); 942d76e15fbSGreg Kroah-Hartman power_kobj = kobject_create_and_add("power", NULL); 943d76e15fbSGreg Kroah-Hartman if (!power_kobj) 944039a5dcdSGreg Kroah-Hartman return -ENOMEM; 9452c8db5beSKalesh Singh error = sysfs_create_groups(power_kobj, attr_groups); 9467483b4a4SRafael J. Wysocki if (error) 9477483b4a4SRafael J. Wysocki return error; 948b2df1d4fSRafael J. Wysocki pm_print_times_init(); 9497483b4a4SRafael J. Wysocki return pm_autosleep_init(); 9501da177e4SLinus Torvalds } 9511da177e4SLinus Torvalds 9521da177e4SLinus Torvalds core_initcall(pm_init); 953