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> 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds #include "power.h" 201da177e4SLinus Torvalds 21cd51e61cSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 22cd51e61cSRafael J. Wysocki 234bf236a3SBart Van Assche void lock_system_sleep(void) 244bf236a3SBart Van Assche { 254bf236a3SBart Van Assche current->flags |= PF_FREEZER_SKIP; 2655f2503cSPingfan Liu mutex_lock(&system_transition_mutex); 274bf236a3SBart Van Assche } 284bf236a3SBart Van Assche EXPORT_SYMBOL_GPL(lock_system_sleep); 294bf236a3SBart Van Assche 304bf236a3SBart Van Assche void unlock_system_sleep(void) 314bf236a3SBart Van Assche { 324bf236a3SBart Van Assche /* 334bf236a3SBart Van Assche * Don't use freezer_count() because we don't want the call to 344bf236a3SBart Van Assche * try_to_freeze() here. 354bf236a3SBart Van Assche * 364bf236a3SBart Van Assche * Reason: 374bf236a3SBart Van Assche * Fundamentally, we just don't need it, because freezing condition 3855f2503cSPingfan Liu * doesn't come into effect until we release the 3955f2503cSPingfan Liu * system_transition_mutex lock, since the freezer always works with 4055f2503cSPingfan Liu * system_transition_mutex held. 414bf236a3SBart Van Assche * 424bf236a3SBart Van Assche * More importantly, in the case of hibernation, 434bf236a3SBart Van Assche * unlock_system_sleep() gets called in snapshot_read() and 444bf236a3SBart Van Assche * snapshot_write() when the freezing condition is still in effect. 454bf236a3SBart Van Assche * Which means, if we use try_to_freeze() here, it would make them 464bf236a3SBart Van Assche * enter the refrigerator, thus causing hibernation to lockup. 474bf236a3SBart Van Assche */ 484bf236a3SBart Van Assche current->flags &= ~PF_FREEZER_SKIP; 4955f2503cSPingfan Liu mutex_unlock(&system_transition_mutex); 504bf236a3SBart Van Assche } 514bf236a3SBart Van Assche EXPORT_SYMBOL_GPL(unlock_system_sleep); 524bf236a3SBart Van Assche 53b5dee313SHarry Pan void ksys_sync_helper(void) 54b5dee313SHarry Pan { 55c64546b1SHarry Pan ktime_t start; 56c64546b1SHarry Pan long elapsed_msecs; 57c64546b1SHarry Pan 58c64546b1SHarry Pan start = ktime_get(); 59b5dee313SHarry Pan ksys_sync(); 60c64546b1SHarry Pan elapsed_msecs = ktime_to_ms(ktime_sub(ktime_get(), start)); 61c64546b1SHarry Pan pr_info("Filesystems sync: %ld.%03ld seconds\n", 62c64546b1SHarry Pan elapsed_msecs / MSEC_PER_SEC, elapsed_msecs % MSEC_PER_SEC); 63b5dee313SHarry Pan } 64b5dee313SHarry Pan EXPORT_SYMBOL_GPL(ksys_sync_helper); 65b5dee313SHarry Pan 6682525756SAlan Stern /* Routines for PM-transition notifications */ 6782525756SAlan Stern 6882525756SAlan Stern static BLOCKING_NOTIFIER_HEAD(pm_chain_head); 6982525756SAlan Stern 7082525756SAlan Stern int register_pm_notifier(struct notifier_block *nb) 7182525756SAlan Stern { 7282525756SAlan Stern return blocking_notifier_chain_register(&pm_chain_head, nb); 7382525756SAlan Stern } 7482525756SAlan Stern EXPORT_SYMBOL_GPL(register_pm_notifier); 7582525756SAlan Stern 7682525756SAlan Stern int unregister_pm_notifier(struct notifier_block *nb) 7782525756SAlan Stern { 7882525756SAlan Stern return blocking_notifier_chain_unregister(&pm_chain_head, nb); 7982525756SAlan Stern } 8082525756SAlan Stern EXPORT_SYMBOL_GPL(unregister_pm_notifier); 8182525756SAlan Stern 82ea00f4f4SLianwei Wang int __pm_notifier_call_chain(unsigned long val, int nr_to_call, int *nr_calls) 8382525756SAlan Stern { 84ea00f4f4SLianwei Wang int ret; 85ea00f4f4SLianwei Wang 86ea00f4f4SLianwei Wang ret = __blocking_notifier_call_chain(&pm_chain_head, val, NULL, 87ea00f4f4SLianwei Wang nr_to_call, nr_calls); 88f0c077a8SAkinobu Mita 89f0c077a8SAkinobu Mita return notifier_to_errno(ret); 9082525756SAlan Stern } 91ea00f4f4SLianwei Wang int pm_notifier_call_chain(unsigned long val) 92ea00f4f4SLianwei Wang { 93ea00f4f4SLianwei Wang return __pm_notifier_call_chain(val, -1, NULL); 94ea00f4f4SLianwei Wang } 9582525756SAlan Stern 960e06b4a8SRafael J. Wysocki /* If set, devices may be suspended and resumed asynchronously. */ 970e06b4a8SRafael J. Wysocki int pm_async_enabled = 1; 980e06b4a8SRafael J. Wysocki 990e06b4a8SRafael J. Wysocki static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr, 1000e06b4a8SRafael J. Wysocki char *buf) 1010e06b4a8SRafael J. Wysocki { 1020e06b4a8SRafael J. Wysocki return sprintf(buf, "%d\n", pm_async_enabled); 1030e06b4a8SRafael J. Wysocki } 1040e06b4a8SRafael J. Wysocki 1050e06b4a8SRafael J. Wysocki static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr, 1060e06b4a8SRafael J. Wysocki const char *buf, size_t n) 1070e06b4a8SRafael J. Wysocki { 1080e06b4a8SRafael J. Wysocki unsigned long val; 1090e06b4a8SRafael J. Wysocki 110883ee4f7SDaniel Walter if (kstrtoul(buf, 10, &val)) 1110e06b4a8SRafael J. Wysocki return -EINVAL; 1120e06b4a8SRafael J. Wysocki 1130e06b4a8SRafael J. Wysocki if (val > 1) 1140e06b4a8SRafael J. Wysocki return -EINVAL; 1150e06b4a8SRafael J. Wysocki 1160e06b4a8SRafael J. Wysocki pm_async_enabled = val; 1170e06b4a8SRafael J. Wysocki return n; 1180e06b4a8SRafael J. Wysocki } 1190e06b4a8SRafael J. Wysocki 1200e06b4a8SRafael J. Wysocki power_attr(pm_async); 1210e06b4a8SRafael J. Wysocki 122406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND 123406e7938SRafael J. Wysocki static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr, 124406e7938SRafael J. Wysocki char *buf) 125406e7938SRafael J. Wysocki { 126406e7938SRafael J. Wysocki char *s = buf; 127406e7938SRafael J. Wysocki suspend_state_t i; 128406e7938SRafael J. Wysocki 129406e7938SRafael J. Wysocki for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) 130406e7938SRafael J. Wysocki if (mem_sleep_states[i]) { 131406e7938SRafael J. Wysocki const char *label = mem_sleep_states[i]; 132406e7938SRafael J. Wysocki 133406e7938SRafael J. Wysocki if (mem_sleep_current == i) 134406e7938SRafael J. Wysocki s += sprintf(s, "[%s] ", label); 135406e7938SRafael J. Wysocki else 136406e7938SRafael J. Wysocki s += sprintf(s, "%s ", label); 137406e7938SRafael J. Wysocki } 138406e7938SRafael J. Wysocki 139406e7938SRafael J. Wysocki /* Convert the last space to a newline if needed. */ 140406e7938SRafael J. Wysocki if (s != buf) 141406e7938SRafael J. Wysocki *(s-1) = '\n'; 142406e7938SRafael J. Wysocki 143406e7938SRafael J. Wysocki return (s - buf); 144406e7938SRafael J. Wysocki } 145406e7938SRafael J. Wysocki 146406e7938SRafael J. Wysocki static suspend_state_t decode_suspend_state(const char *buf, size_t n) 147406e7938SRafael J. Wysocki { 148406e7938SRafael J. Wysocki suspend_state_t state; 149406e7938SRafael J. Wysocki char *p; 150406e7938SRafael J. Wysocki int len; 151406e7938SRafael J. Wysocki 152406e7938SRafael J. Wysocki p = memchr(buf, '\n', n); 153406e7938SRafael J. Wysocki len = p ? p - buf : n; 154406e7938SRafael J. Wysocki 155406e7938SRafael J. Wysocki for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) { 156406e7938SRafael J. Wysocki const char *label = mem_sleep_states[state]; 157406e7938SRafael J. Wysocki 158406e7938SRafael J. Wysocki if (label && len == strlen(label) && !strncmp(buf, label, len)) 159406e7938SRafael J. Wysocki return state; 160406e7938SRafael J. Wysocki } 161406e7938SRafael J. Wysocki 162406e7938SRafael J. Wysocki return PM_SUSPEND_ON; 163406e7938SRafael J. Wysocki } 164406e7938SRafael J. Wysocki 165406e7938SRafael J. Wysocki static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr, 166406e7938SRafael J. Wysocki const char *buf, size_t n) 167406e7938SRafael J. Wysocki { 168406e7938SRafael J. Wysocki suspend_state_t state; 169406e7938SRafael J. Wysocki int error; 170406e7938SRafael J. Wysocki 171406e7938SRafael J. Wysocki error = pm_autosleep_lock(); 172406e7938SRafael J. Wysocki if (error) 173406e7938SRafael J. Wysocki return error; 174406e7938SRafael J. Wysocki 175406e7938SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 176406e7938SRafael J. Wysocki error = -EBUSY; 177406e7938SRafael J. Wysocki goto out; 178406e7938SRafael J. Wysocki } 179406e7938SRafael J. Wysocki 180406e7938SRafael J. Wysocki state = decode_suspend_state(buf, n); 181406e7938SRafael J. Wysocki if (state < PM_SUSPEND_MAX && state > PM_SUSPEND_ON) 182406e7938SRafael J. Wysocki mem_sleep_current = state; 183406e7938SRafael J. Wysocki else 184406e7938SRafael J. Wysocki error = -EINVAL; 185406e7938SRafael J. Wysocki 186406e7938SRafael J. Wysocki out: 187406e7938SRafael J. Wysocki pm_autosleep_unlock(); 188406e7938SRafael J. Wysocki return error ? error : n; 189406e7938SRafael J. Wysocki } 190406e7938SRafael J. Wysocki 191406e7938SRafael J. Wysocki power_attr(mem_sleep); 192406e7938SRafael J. Wysocki #endif /* CONFIG_SUSPEND */ 193406e7938SRafael J. Wysocki 194e516a1dbSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 1950e7d56e3SRafael J. Wysocki int pm_test_level = TEST_NONE; 1960e7d56e3SRafael J. Wysocki 1970e7d56e3SRafael J. Wysocki static const char * const pm_tests[__TEST_AFTER_LAST] = { 1980e7d56e3SRafael J. Wysocki [TEST_NONE] = "none", 1990e7d56e3SRafael J. Wysocki [TEST_CORE] = "core", 2000e7d56e3SRafael J. Wysocki [TEST_CPUS] = "processors", 2010e7d56e3SRafael J. Wysocki [TEST_PLATFORM] = "platform", 2020e7d56e3SRafael J. Wysocki [TEST_DEVICES] = "devices", 2030e7d56e3SRafael J. Wysocki [TEST_FREEZER] = "freezer", 2040e7d56e3SRafael J. Wysocki }; 2050e7d56e3SRafael J. Wysocki 206039a75c6SRafael J. Wysocki static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr, 207039a75c6SRafael J. Wysocki char *buf) 2080e7d56e3SRafael J. Wysocki { 2090e7d56e3SRafael J. Wysocki char *s = buf; 2100e7d56e3SRafael J. Wysocki int level; 2110e7d56e3SRafael J. Wysocki 2120e7d56e3SRafael J. Wysocki for (level = TEST_FIRST; level <= TEST_MAX; level++) 2130e7d56e3SRafael J. Wysocki if (pm_tests[level]) { 2140e7d56e3SRafael J. Wysocki if (level == pm_test_level) 2150e7d56e3SRafael J. Wysocki s += sprintf(s, "[%s] ", pm_tests[level]); 2160e7d56e3SRafael J. Wysocki else 2170e7d56e3SRafael J. Wysocki s += sprintf(s, "%s ", pm_tests[level]); 2180e7d56e3SRafael J. Wysocki } 2190e7d56e3SRafael J. Wysocki 2200e7d56e3SRafael J. Wysocki if (s != buf) 2210e7d56e3SRafael J. Wysocki /* convert the last space to a newline */ 2220e7d56e3SRafael J. Wysocki *(s-1) = '\n'; 2230e7d56e3SRafael J. Wysocki 2240e7d56e3SRafael J. Wysocki return (s - buf); 2250e7d56e3SRafael J. Wysocki } 2260e7d56e3SRafael J. Wysocki 227039a75c6SRafael J. Wysocki static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, 228039a75c6SRafael J. Wysocki const char *buf, size_t n) 2290e7d56e3SRafael J. Wysocki { 2300e7d56e3SRafael J. Wysocki const char * const *s; 2310e7d56e3SRafael J. Wysocki int level; 2320e7d56e3SRafael J. Wysocki char *p; 2330e7d56e3SRafael J. Wysocki int len; 2340e7d56e3SRafael J. Wysocki int error = -EINVAL; 2350e7d56e3SRafael J. Wysocki 2360e7d56e3SRafael J. Wysocki p = memchr(buf, '\n', n); 2370e7d56e3SRafael J. Wysocki len = p ? p - buf : n; 2380e7d56e3SRafael J. Wysocki 239bcda53faSSrivatsa S. Bhat lock_system_sleep(); 2400e7d56e3SRafael J. Wysocki 2410e7d56e3SRafael J. Wysocki level = TEST_FIRST; 2420e7d56e3SRafael J. Wysocki for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++) 2430e7d56e3SRafael J. Wysocki if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) { 2440e7d56e3SRafael J. Wysocki pm_test_level = level; 2450e7d56e3SRafael J. Wysocki error = 0; 2460e7d56e3SRafael J. Wysocki break; 2470e7d56e3SRafael J. Wysocki } 2480e7d56e3SRafael J. Wysocki 249bcda53faSSrivatsa S. Bhat unlock_system_sleep(); 2500e7d56e3SRafael J. Wysocki 2510e7d56e3SRafael J. Wysocki return error ? error : n; 2520e7d56e3SRafael J. Wysocki } 2530e7d56e3SRafael J. Wysocki 2540e7d56e3SRafael J. Wysocki power_attr(pm_test); 255e516a1dbSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */ 2560e7d56e3SRafael J. Wysocki 2572a77c46dSShuoX Liu static char *suspend_step_name(enum suspend_stat_step step) 2582a77c46dSShuoX Liu { 2592a77c46dSShuoX Liu switch (step) { 2602a77c46dSShuoX Liu case SUSPEND_FREEZE: 2612a77c46dSShuoX Liu return "freeze"; 2622a77c46dSShuoX Liu case SUSPEND_PREPARE: 2632a77c46dSShuoX Liu return "prepare"; 2642a77c46dSShuoX Liu case SUSPEND_SUSPEND: 2652a77c46dSShuoX Liu return "suspend"; 2662a77c46dSShuoX Liu case SUSPEND_SUSPEND_NOIRQ: 2672a77c46dSShuoX Liu return "suspend_noirq"; 2682a77c46dSShuoX Liu case SUSPEND_RESUME_NOIRQ: 2692a77c46dSShuoX Liu return "resume_noirq"; 2702a77c46dSShuoX Liu case SUSPEND_RESUME: 2712a77c46dSShuoX Liu return "resume"; 2722a77c46dSShuoX Liu default: 2732a77c46dSShuoX Liu return ""; 2742a77c46dSShuoX Liu } 2752a77c46dSShuoX Liu } 2762a77c46dSShuoX Liu 277*2c8db5beSKalesh Singh #define suspend_attr(_name) \ 278*2c8db5beSKalesh Singh static ssize_t _name##_show(struct kobject *kobj, \ 279*2c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) \ 280*2c8db5beSKalesh Singh { \ 281*2c8db5beSKalesh Singh return sprintf(buf, "%d\n", suspend_stats._name); \ 282*2c8db5beSKalesh Singh } \ 283*2c8db5beSKalesh Singh static struct kobj_attribute _name = __ATTR_RO(_name) 284*2c8db5beSKalesh Singh 285*2c8db5beSKalesh Singh suspend_attr(success); 286*2c8db5beSKalesh Singh suspend_attr(fail); 287*2c8db5beSKalesh Singh suspend_attr(failed_freeze); 288*2c8db5beSKalesh Singh suspend_attr(failed_prepare); 289*2c8db5beSKalesh Singh suspend_attr(failed_suspend); 290*2c8db5beSKalesh Singh suspend_attr(failed_suspend_late); 291*2c8db5beSKalesh Singh suspend_attr(failed_suspend_noirq); 292*2c8db5beSKalesh Singh suspend_attr(failed_resume); 293*2c8db5beSKalesh Singh suspend_attr(failed_resume_early); 294*2c8db5beSKalesh Singh suspend_attr(failed_resume_noirq); 295*2c8db5beSKalesh Singh 296*2c8db5beSKalesh Singh static ssize_t last_failed_dev_show(struct kobject *kobj, 297*2c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 298*2c8db5beSKalesh Singh { 299*2c8db5beSKalesh Singh int index; 300*2c8db5beSKalesh Singh char *last_failed_dev = NULL; 301*2c8db5beSKalesh Singh 302*2c8db5beSKalesh Singh index = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; 303*2c8db5beSKalesh Singh index %= REC_FAILED_NUM; 304*2c8db5beSKalesh Singh last_failed_dev = suspend_stats.failed_devs[index]; 305*2c8db5beSKalesh Singh 306*2c8db5beSKalesh Singh return sprintf(buf, "%s\n", last_failed_dev); 307*2c8db5beSKalesh Singh } 308*2c8db5beSKalesh Singh static struct kobj_attribute last_failed_dev = __ATTR_RO(last_failed_dev); 309*2c8db5beSKalesh Singh 310*2c8db5beSKalesh Singh static ssize_t last_failed_errno_show(struct kobject *kobj, 311*2c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 312*2c8db5beSKalesh Singh { 313*2c8db5beSKalesh Singh int index; 314*2c8db5beSKalesh Singh int last_failed_errno; 315*2c8db5beSKalesh Singh 316*2c8db5beSKalesh Singh index = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1; 317*2c8db5beSKalesh Singh index %= REC_FAILED_NUM; 318*2c8db5beSKalesh Singh last_failed_errno = suspend_stats.errno[index]; 319*2c8db5beSKalesh Singh 320*2c8db5beSKalesh Singh return sprintf(buf, "%d\n", last_failed_errno); 321*2c8db5beSKalesh Singh } 322*2c8db5beSKalesh Singh static struct kobj_attribute last_failed_errno = __ATTR_RO(last_failed_errno); 323*2c8db5beSKalesh Singh 324*2c8db5beSKalesh Singh static ssize_t last_failed_step_show(struct kobject *kobj, 325*2c8db5beSKalesh Singh struct kobj_attribute *attr, char *buf) 326*2c8db5beSKalesh Singh { 327*2c8db5beSKalesh Singh int index; 328*2c8db5beSKalesh Singh enum suspend_stat_step step; 329*2c8db5beSKalesh Singh char *last_failed_step = NULL; 330*2c8db5beSKalesh Singh 331*2c8db5beSKalesh Singh index = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; 332*2c8db5beSKalesh Singh index %= REC_FAILED_NUM; 333*2c8db5beSKalesh Singh step = suspend_stats.failed_steps[index]; 334*2c8db5beSKalesh Singh last_failed_step = suspend_step_name(step); 335*2c8db5beSKalesh Singh 336*2c8db5beSKalesh Singh return sprintf(buf, "%s\n", last_failed_step); 337*2c8db5beSKalesh Singh } 338*2c8db5beSKalesh Singh static struct kobj_attribute last_failed_step = __ATTR_RO(last_failed_step); 339*2c8db5beSKalesh Singh 340*2c8db5beSKalesh Singh static struct attribute *suspend_attrs[] = { 341*2c8db5beSKalesh Singh &success.attr, 342*2c8db5beSKalesh Singh &fail.attr, 343*2c8db5beSKalesh Singh &failed_freeze.attr, 344*2c8db5beSKalesh Singh &failed_prepare.attr, 345*2c8db5beSKalesh Singh &failed_suspend.attr, 346*2c8db5beSKalesh Singh &failed_suspend_late.attr, 347*2c8db5beSKalesh Singh &failed_suspend_noirq.attr, 348*2c8db5beSKalesh Singh &failed_resume.attr, 349*2c8db5beSKalesh Singh &failed_resume_early.attr, 350*2c8db5beSKalesh Singh &failed_resume_noirq.attr, 351*2c8db5beSKalesh Singh &last_failed_dev.attr, 352*2c8db5beSKalesh Singh &last_failed_errno.attr, 353*2c8db5beSKalesh Singh &last_failed_step.attr, 354*2c8db5beSKalesh Singh NULL, 355*2c8db5beSKalesh Singh }; 356*2c8db5beSKalesh Singh 357*2c8db5beSKalesh Singh static struct attribute_group suspend_attr_group = { 358*2c8db5beSKalesh Singh .name = "suspend_stats", 359*2c8db5beSKalesh Singh .attrs = suspend_attrs, 360*2c8db5beSKalesh Singh }; 361*2c8db5beSKalesh Singh 362*2c8db5beSKalesh Singh #ifdef CONFIG_DEBUG_FS 3632a77c46dSShuoX Liu static int suspend_stats_show(struct seq_file *s, void *unused) 3642a77c46dSShuoX Liu { 3652a77c46dSShuoX Liu int i, index, last_dev, last_errno, last_step; 3662a77c46dSShuoX Liu 3672a77c46dSShuoX Liu last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; 3682a77c46dSShuoX Liu last_dev %= REC_FAILED_NUM; 3692a77c46dSShuoX Liu last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1; 3702a77c46dSShuoX Liu last_errno %= REC_FAILED_NUM; 3712a77c46dSShuoX Liu last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; 3722a77c46dSShuoX Liu last_step %= REC_FAILED_NUM; 373cf579dfbSRafael J. Wysocki seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n" 374cf579dfbSRafael J. Wysocki "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n", 3752a77c46dSShuoX Liu "success", suspend_stats.success, 3762a77c46dSShuoX Liu "fail", suspend_stats.fail, 3772a77c46dSShuoX Liu "failed_freeze", suspend_stats.failed_freeze, 3782a77c46dSShuoX Liu "failed_prepare", suspend_stats.failed_prepare, 3792a77c46dSShuoX Liu "failed_suspend", suspend_stats.failed_suspend, 380cf579dfbSRafael J. Wysocki "failed_suspend_late", 381cf579dfbSRafael J. Wysocki suspend_stats.failed_suspend_late, 3822a77c46dSShuoX Liu "failed_suspend_noirq", 3832a77c46dSShuoX Liu suspend_stats.failed_suspend_noirq, 3842a77c46dSShuoX Liu "failed_resume", suspend_stats.failed_resume, 385cf579dfbSRafael J. Wysocki "failed_resume_early", 386cf579dfbSRafael J. Wysocki suspend_stats.failed_resume_early, 3872a77c46dSShuoX Liu "failed_resume_noirq", 3882a77c46dSShuoX Liu suspend_stats.failed_resume_noirq); 3892a77c46dSShuoX Liu seq_printf(s, "failures:\n last_failed_dev:\t%-s\n", 3902a77c46dSShuoX Liu suspend_stats.failed_devs[last_dev]); 3912a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 3922a77c46dSShuoX Liu index = last_dev + REC_FAILED_NUM - i; 3932a77c46dSShuoX Liu index %= REC_FAILED_NUM; 3942a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-s\n", 3952a77c46dSShuoX Liu suspend_stats.failed_devs[index]); 3962a77c46dSShuoX Liu } 3972a77c46dSShuoX Liu seq_printf(s, " last_failed_errno:\t%-d\n", 3982a77c46dSShuoX Liu suspend_stats.errno[last_errno]); 3992a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4002a77c46dSShuoX Liu index = last_errno + REC_FAILED_NUM - i; 4012a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4022a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-d\n", 4032a77c46dSShuoX Liu suspend_stats.errno[index]); 4042a77c46dSShuoX Liu } 4052a77c46dSShuoX Liu seq_printf(s, " last_failed_step:\t%-s\n", 4062a77c46dSShuoX Liu suspend_step_name( 4072a77c46dSShuoX Liu suspend_stats.failed_steps[last_step])); 4082a77c46dSShuoX Liu for (i = 1; i < REC_FAILED_NUM; i++) { 4092a77c46dSShuoX Liu index = last_step + REC_FAILED_NUM - i; 4102a77c46dSShuoX Liu index %= REC_FAILED_NUM; 4112a77c46dSShuoX Liu seq_printf(s, "\t\t\t%-s\n", 4122a77c46dSShuoX Liu suspend_step_name( 4132a77c46dSShuoX Liu suspend_stats.failed_steps[index])); 4142a77c46dSShuoX Liu } 4152a77c46dSShuoX Liu 4162a77c46dSShuoX Liu return 0; 4172a77c46dSShuoX Liu } 418943a10f8SYangtao Li DEFINE_SHOW_ATTRIBUTE(suspend_stats); 4192a77c46dSShuoX Liu 4202a77c46dSShuoX Liu static int __init pm_debugfs_init(void) 4212a77c46dSShuoX Liu { 4222a77c46dSShuoX Liu debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO, 423943a10f8SYangtao Li NULL, NULL, &suspend_stats_fops); 4242a77c46dSShuoX Liu return 0; 4252a77c46dSShuoX Liu } 4262a77c46dSShuoX Liu 4272a77c46dSShuoX Liu late_initcall(pm_debugfs_init); 4282a77c46dSShuoX Liu #endif /* CONFIG_DEBUG_FS */ 4292a77c46dSShuoX Liu 430ca123102SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 431ca123102SRafael J. Wysocki 432b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 433b2df1d4fSRafael J. Wysocki /* 434b2df1d4fSRafael J. Wysocki * pm_print_times: print time taken by devices to suspend and resume. 435b2df1d4fSRafael J. Wysocki * 436b2df1d4fSRafael J. Wysocki * show() returns whether printing of suspend and resume times is enabled. 437b2df1d4fSRafael J. Wysocki * store() accepts 0 or 1. 0 disables printing and 1 enables it. 438b2df1d4fSRafael J. Wysocki */ 439b2df1d4fSRafael J. Wysocki bool pm_print_times_enabled; 440b2df1d4fSRafael J. Wysocki 441b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_show(struct kobject *kobj, 442b2df1d4fSRafael J. Wysocki struct kobj_attribute *attr, char *buf) 443b2df1d4fSRafael J. Wysocki { 444b2df1d4fSRafael J. Wysocki return sprintf(buf, "%d\n", pm_print_times_enabled); 445b2df1d4fSRafael J. Wysocki } 446b2df1d4fSRafael J. Wysocki 447b2df1d4fSRafael J. Wysocki static ssize_t pm_print_times_store(struct kobject *kobj, 448b2df1d4fSRafael J. Wysocki struct kobj_attribute *attr, 449b2df1d4fSRafael J. Wysocki const char *buf, size_t n) 450b2df1d4fSRafael J. Wysocki { 451b2df1d4fSRafael J. Wysocki unsigned long val; 452b2df1d4fSRafael J. Wysocki 453b2df1d4fSRafael J. Wysocki if (kstrtoul(buf, 10, &val)) 454b2df1d4fSRafael J. Wysocki return -EINVAL; 455b2df1d4fSRafael J. Wysocki 456b2df1d4fSRafael J. Wysocki if (val > 1) 457b2df1d4fSRafael J. Wysocki return -EINVAL; 458b2df1d4fSRafael J. Wysocki 459b2df1d4fSRafael J. Wysocki pm_print_times_enabled = !!val; 460b2df1d4fSRafael J. Wysocki return n; 461b2df1d4fSRafael J. Wysocki } 462b2df1d4fSRafael J. Wysocki 463b2df1d4fSRafael J. Wysocki power_attr(pm_print_times); 464b2df1d4fSRafael J. Wysocki 465b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) 466b2df1d4fSRafael J. Wysocki { 467b2df1d4fSRafael J. Wysocki pm_print_times_enabled = !!initcall_debug; 468b2df1d4fSRafael J. Wysocki } 469a6f5f0ddSAlexandra Yates 470a6f5f0ddSAlexandra Yates static ssize_t pm_wakeup_irq_show(struct kobject *kobj, 471a6f5f0ddSAlexandra Yates struct kobj_attribute *attr, 472a6f5f0ddSAlexandra Yates char *buf) 473a6f5f0ddSAlexandra Yates { 474a6f5f0ddSAlexandra Yates return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA; 475a6f5f0ddSAlexandra Yates } 476a6f5f0ddSAlexandra Yates 477a1e9ca69SRafael J. Wysocki power_attr_ro(pm_wakeup_irq); 478a6f5f0ddSAlexandra Yates 479726fb6b4SSrinivas Pandruvada bool pm_debug_messages_on __read_mostly; 4808d8b2441SRafael J. Wysocki 4818d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_show(struct kobject *kobj, 4828d8b2441SRafael J. Wysocki struct kobj_attribute *attr, char *buf) 4838d8b2441SRafael J. Wysocki { 4848d8b2441SRafael J. Wysocki return sprintf(buf, "%d\n", pm_debug_messages_on); 4858d8b2441SRafael J. Wysocki } 4868d8b2441SRafael J. Wysocki 4878d8b2441SRafael J. Wysocki static ssize_t pm_debug_messages_store(struct kobject *kobj, 4888d8b2441SRafael J. Wysocki struct kobj_attribute *attr, 4898d8b2441SRafael J. Wysocki const char *buf, size_t n) 4908d8b2441SRafael J. Wysocki { 4918d8b2441SRafael J. Wysocki unsigned long val; 4928d8b2441SRafael J. Wysocki 4938d8b2441SRafael J. Wysocki if (kstrtoul(buf, 10, &val)) 4948d8b2441SRafael J. Wysocki return -EINVAL; 4958d8b2441SRafael J. Wysocki 4968d8b2441SRafael J. Wysocki if (val > 1) 4978d8b2441SRafael J. Wysocki return -EINVAL; 4988d8b2441SRafael J. Wysocki 4998d8b2441SRafael J. Wysocki pm_debug_messages_on = !!val; 5008d8b2441SRafael J. Wysocki return n; 5018d8b2441SRafael J. Wysocki } 5028d8b2441SRafael J. Wysocki 5038d8b2441SRafael J. Wysocki power_attr(pm_debug_messages); 5048d8b2441SRafael J. Wysocki 5058d8b2441SRafael J. Wysocki /** 506cb08e035SRafael J. Wysocki * __pm_pr_dbg - Print a suspend debug message to the kernel log. 507cb08e035SRafael J. Wysocki * @defer: Whether or not to use printk_deferred() to print the message. 5088d8b2441SRafael J. Wysocki * @fmt: Message format. 5098d8b2441SRafael J. Wysocki * 5108d8b2441SRafael J. Wysocki * The message will be emitted if enabled through the pm_debug_messages 5118d8b2441SRafael J. Wysocki * sysfs attribute. 5128d8b2441SRafael J. Wysocki */ 513cb08e035SRafael J. Wysocki void __pm_pr_dbg(bool defer, const char *fmt, ...) 5148d8b2441SRafael J. Wysocki { 5158d8b2441SRafael J. Wysocki struct va_format vaf; 5168d8b2441SRafael J. Wysocki va_list args; 5178d8b2441SRafael J. Wysocki 5188d8b2441SRafael J. Wysocki if (!pm_debug_messages_on) 5198d8b2441SRafael J. Wysocki return; 5208d8b2441SRafael J. Wysocki 5218d8b2441SRafael J. Wysocki va_start(args, fmt); 5228d8b2441SRafael J. Wysocki 5238d8b2441SRafael J. Wysocki vaf.fmt = fmt; 5248d8b2441SRafael J. Wysocki vaf.va = &args; 5258d8b2441SRafael J. Wysocki 526cb08e035SRafael J. Wysocki if (defer) 527cb08e035SRafael J. Wysocki printk_deferred(KERN_DEBUG "PM: %pV", &vaf); 528cb08e035SRafael J. Wysocki else 5298d8b2441SRafael J. Wysocki printk(KERN_DEBUG "PM: %pV", &vaf); 5308d8b2441SRafael J. Wysocki 5318d8b2441SRafael J. Wysocki va_end(args); 5328d8b2441SRafael J. Wysocki } 5338d8b2441SRafael J. Wysocki 534819b1bb3SRafael J. Wysocki #else /* !CONFIG_PM_SLEEP_DEBUG */ 535b2df1d4fSRafael J. Wysocki static inline void pm_print_times_init(void) {} 536b2df1d4fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_DEBUG */ 537b2df1d4fSRafael J. Wysocki 538d76e15fbSGreg Kroah-Hartman struct kobject *power_kobj; 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds /** 5410399d4dbSRafael J. Wysocki * state - control system sleep states. 5421da177e4SLinus Torvalds * 5430399d4dbSRafael J. Wysocki * show() returns available sleep state labels, which may be "mem", "standby", 54444348e8aSMauro Carvalho Chehab * "freeze" and "disk" (hibernation). 54544348e8aSMauro Carvalho Chehab * See Documentation/admin-guide/pm/sleep-states.rst for a description of 54644348e8aSMauro Carvalho Chehab * what they mean. 5471da177e4SLinus Torvalds * 5480399d4dbSRafael J. Wysocki * store() accepts one of those strings, translates it into the proper 5490399d4dbSRafael J. Wysocki * enumerated value, and initiates a suspend transition. 5501da177e4SLinus Torvalds */ 551386f275fSKay Sievers static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, 552386f275fSKay Sievers char *buf) 5531da177e4SLinus Torvalds { 5541da177e4SLinus Torvalds char *s = buf; 555296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 55627ddcc65SRafael J. Wysocki suspend_state_t i; 5571da177e4SLinus Torvalds 55827ddcc65SRafael J. Wysocki for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) 559d431cbc5SRafael J. Wysocki if (pm_states[i]) 560d431cbc5SRafael J. Wysocki s += sprintf(s,"%s ", pm_states[i]); 56127ddcc65SRafael J. Wysocki 562296699deSRafael J. Wysocki #endif 563a6e15a39SKees Cook if (hibernation_available()) 564a6e15a39SKees Cook s += sprintf(s, "disk "); 565a3d25c27SRafael J. Wysocki if (s != buf) 566a3d25c27SRafael J. Wysocki /* convert the last space to a newline */ 567a3d25c27SRafael J. Wysocki *(s-1) = '\n'; 5681da177e4SLinus Torvalds return (s - buf); 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds 5717483b4a4SRafael J. Wysocki static suspend_state_t decode_state(const char *buf, size_t n) 5721da177e4SLinus Torvalds { 573296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 574d431cbc5SRafael J. Wysocki suspend_state_t state; 575296699deSRafael J. Wysocki #endif 5761da177e4SLinus Torvalds char *p; 5771da177e4SLinus Torvalds int len; 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds p = memchr(buf, '\n', n); 5801da177e4SLinus Torvalds len = p ? p - buf : n; 5811da177e4SLinus Torvalds 5827483b4a4SRafael J. Wysocki /* Check hibernation first. */ 5837483b4a4SRafael J. Wysocki if (len == 4 && !strncmp(buf, "disk", len)) 5847483b4a4SRafael J. Wysocki return PM_SUSPEND_MAX; 585a3d25c27SRafael J. Wysocki 586296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 587d431cbc5SRafael J. Wysocki for (state = PM_SUSPEND_MIN; state < PM_SUSPEND_MAX; state++) { 588d431cbc5SRafael J. Wysocki const char *label = pm_states[state]; 589d431cbc5SRafael J. Wysocki 590d431cbc5SRafael J. Wysocki if (label && len == strlen(label) && !strncmp(buf, label, len)) 591d431cbc5SRafael J. Wysocki return state; 592d431cbc5SRafael J. Wysocki } 593296699deSRafael J. Wysocki #endif 594296699deSRafael J. Wysocki 5957483b4a4SRafael J. Wysocki return PM_SUSPEND_ON; 5967483b4a4SRafael J. Wysocki } 5977483b4a4SRafael J. Wysocki 5987483b4a4SRafael J. Wysocki static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, 5997483b4a4SRafael J. Wysocki const char *buf, size_t n) 6007483b4a4SRafael J. Wysocki { 6017483b4a4SRafael J. Wysocki suspend_state_t state; 6027483b4a4SRafael J. Wysocki int error; 6037483b4a4SRafael J. Wysocki 6047483b4a4SRafael J. Wysocki error = pm_autosleep_lock(); 6057483b4a4SRafael J. Wysocki if (error) 6067483b4a4SRafael J. Wysocki return error; 6077483b4a4SRafael J. Wysocki 6087483b4a4SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 6097483b4a4SRafael J. Wysocki error = -EBUSY; 6107483b4a4SRafael J. Wysocki goto out; 6117483b4a4SRafael J. Wysocki } 6127483b4a4SRafael J. Wysocki 6137483b4a4SRafael J. Wysocki state = decode_state(buf, n); 614406e7938SRafael J. Wysocki if (state < PM_SUSPEND_MAX) { 615406e7938SRafael J. Wysocki if (state == PM_SUSPEND_MEM) 616406e7938SRafael J. Wysocki state = mem_sleep_current; 617406e7938SRafael J. Wysocki 6187483b4a4SRafael J. Wysocki error = pm_suspend(state); 619406e7938SRafael J. Wysocki } else if (state == PM_SUSPEND_MAX) { 6207483b4a4SRafael J. Wysocki error = hibernate(); 621406e7938SRafael J. Wysocki } else { 6227483b4a4SRafael J. Wysocki error = -EINVAL; 623406e7938SRafael J. Wysocki } 6247483b4a4SRafael J. Wysocki 6257483b4a4SRafael J. Wysocki out: 6267483b4a4SRafael J. Wysocki pm_autosleep_unlock(); 6271da177e4SLinus Torvalds return error ? error : n; 6281da177e4SLinus Torvalds } 6291da177e4SLinus Torvalds 6301da177e4SLinus Torvalds power_attr(state); 6311da177e4SLinus Torvalds 632c125e96fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 633c125e96fSRafael J. Wysocki /* 634c125e96fSRafael J. Wysocki * The 'wakeup_count' attribute, along with the functions defined in 635c125e96fSRafael J. Wysocki * drivers/base/power/wakeup.c, provides a means by which wakeup events can be 636c125e96fSRafael J. Wysocki * handled in a non-racy way. 637c125e96fSRafael J. Wysocki * 638c125e96fSRafael J. Wysocki * If a wakeup event occurs when the system is in a sleep state, it simply is 639c125e96fSRafael J. Wysocki * woken up. In turn, if an event that would wake the system up from a sleep 640c125e96fSRafael J. Wysocki * state occurs when it is undergoing a transition to that sleep state, the 641c125e96fSRafael J. Wysocki * transition should be aborted. Moreover, if such an event occurs when the 642c125e96fSRafael J. Wysocki * system is in the working state, an attempt to start a transition to the 643c125e96fSRafael J. Wysocki * given sleep state should fail during certain period after the detection of 644c125e96fSRafael J. Wysocki * the event. Using the 'state' attribute alone is not sufficient to satisfy 645c125e96fSRafael J. Wysocki * these requirements, because a wakeup event may occur exactly when 'state' 646c125e96fSRafael J. Wysocki * is being written to and may be delivered to user space right before it is 647c125e96fSRafael J. Wysocki * frozen, so the event will remain only partially processed until the system is 648c125e96fSRafael J. Wysocki * woken up by another event. In particular, it won't cause the transition to 649c125e96fSRafael J. Wysocki * a sleep state to be aborted. 650c125e96fSRafael J. Wysocki * 651c125e96fSRafael J. Wysocki * This difficulty may be overcome if user space uses 'wakeup_count' before 652c125e96fSRafael J. Wysocki * writing to 'state'. It first should read from 'wakeup_count' and store 653c125e96fSRafael J. Wysocki * the read value. Then, after carrying out its own preparations for the system 654c125e96fSRafael J. Wysocki * transition to a sleep state, it should write the stored value to 65525985edcSLucas De Marchi * 'wakeup_count'. If that fails, at least one wakeup event has occurred since 656c125e96fSRafael J. Wysocki * 'wakeup_count' was read and 'state' should not be written to. Otherwise, it 657c125e96fSRafael J. Wysocki * is allowed to write to 'state', but the transition will be aborted if there 658c125e96fSRafael J. Wysocki * are any wakeup events detected after 'wakeup_count' was written to. 659c125e96fSRafael J. Wysocki */ 660c125e96fSRafael J. Wysocki 661c125e96fSRafael J. Wysocki static ssize_t wakeup_count_show(struct kobject *kobj, 662c125e96fSRafael J. Wysocki struct kobj_attribute *attr, 663c125e96fSRafael J. Wysocki char *buf) 664c125e96fSRafael J. Wysocki { 665074037ecSRafael J. Wysocki unsigned int val; 666c125e96fSRafael J. Wysocki 6677483b4a4SRafael J. Wysocki return pm_get_wakeup_count(&val, true) ? 6687483b4a4SRafael J. Wysocki sprintf(buf, "%u\n", val) : -EINTR; 669c125e96fSRafael J. Wysocki } 670c125e96fSRafael J. Wysocki 671c125e96fSRafael J. Wysocki static ssize_t wakeup_count_store(struct kobject *kobj, 672c125e96fSRafael J. Wysocki struct kobj_attribute *attr, 673c125e96fSRafael J. Wysocki const char *buf, size_t n) 674c125e96fSRafael J. Wysocki { 675074037ecSRafael J. Wysocki unsigned int val; 6767483b4a4SRafael J. Wysocki int error; 677c125e96fSRafael J. Wysocki 6787483b4a4SRafael J. Wysocki error = pm_autosleep_lock(); 6797483b4a4SRafael J. Wysocki if (error) 6807483b4a4SRafael J. Wysocki return error; 6817483b4a4SRafael J. Wysocki 6827483b4a4SRafael J. Wysocki if (pm_autosleep_state() > PM_SUSPEND_ON) { 6837483b4a4SRafael J. Wysocki error = -EBUSY; 6847483b4a4SRafael J. Wysocki goto out; 6857483b4a4SRafael J. Wysocki } 6867483b4a4SRafael J. Wysocki 6877483b4a4SRafael J. Wysocki error = -EINVAL; 688074037ecSRafael J. Wysocki if (sscanf(buf, "%u", &val) == 1) { 689c125e96fSRafael J. Wysocki if (pm_save_wakeup_count(val)) 6907483b4a4SRafael J. Wysocki error = n; 691bb177fedSJulius Werner else 692bb177fedSJulius Werner pm_print_active_wakeup_sources(); 693c125e96fSRafael J. Wysocki } 6947483b4a4SRafael J. Wysocki 6957483b4a4SRafael J. Wysocki out: 6967483b4a4SRafael J. Wysocki pm_autosleep_unlock(); 6977483b4a4SRafael J. Wysocki return error; 698c125e96fSRafael J. Wysocki } 699c125e96fSRafael J. Wysocki 700c125e96fSRafael J. Wysocki power_attr(wakeup_count); 7017483b4a4SRafael J. Wysocki 7027483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP 7037483b4a4SRafael J. Wysocki static ssize_t autosleep_show(struct kobject *kobj, 7047483b4a4SRafael J. Wysocki struct kobj_attribute *attr, 7057483b4a4SRafael J. Wysocki char *buf) 7067483b4a4SRafael J. Wysocki { 7077483b4a4SRafael J. Wysocki suspend_state_t state = pm_autosleep_state(); 7087483b4a4SRafael J. Wysocki 7097483b4a4SRafael J. Wysocki if (state == PM_SUSPEND_ON) 7107483b4a4SRafael J. Wysocki return sprintf(buf, "off\n"); 7117483b4a4SRafael J. Wysocki 7127483b4a4SRafael J. Wysocki #ifdef CONFIG_SUSPEND 7137483b4a4SRafael J. Wysocki if (state < PM_SUSPEND_MAX) 714d431cbc5SRafael J. Wysocki return sprintf(buf, "%s\n", pm_states[state] ? 715d431cbc5SRafael J. Wysocki pm_states[state] : "error"); 7167483b4a4SRafael J. Wysocki #endif 7177483b4a4SRafael J. Wysocki #ifdef CONFIG_HIBERNATION 7187483b4a4SRafael J. Wysocki return sprintf(buf, "disk\n"); 7197483b4a4SRafael J. Wysocki #else 7207483b4a4SRafael J. Wysocki return sprintf(buf, "error"); 7217483b4a4SRafael J. Wysocki #endif 7227483b4a4SRafael J. Wysocki } 7237483b4a4SRafael J. Wysocki 7247483b4a4SRafael J. Wysocki static ssize_t autosleep_store(struct kobject *kobj, 7257483b4a4SRafael J. Wysocki struct kobj_attribute *attr, 7267483b4a4SRafael J. Wysocki const char *buf, size_t n) 7277483b4a4SRafael J. Wysocki { 7287483b4a4SRafael J. Wysocki suspend_state_t state = decode_state(buf, n); 7297483b4a4SRafael J. Wysocki int error; 7307483b4a4SRafael J. Wysocki 7317483b4a4SRafael J. Wysocki if (state == PM_SUSPEND_ON 732040e5bf6SArve Hjønnevåg && strcmp(buf, "off") && strcmp(buf, "off\n")) 7337483b4a4SRafael J. Wysocki return -EINVAL; 7347483b4a4SRafael J. Wysocki 735406e7938SRafael J. Wysocki if (state == PM_SUSPEND_MEM) 736406e7938SRafael J. Wysocki state = mem_sleep_current; 737406e7938SRafael J. Wysocki 7387483b4a4SRafael J. Wysocki error = pm_autosleep_set_state(state); 7397483b4a4SRafael J. Wysocki return error ? error : n; 7407483b4a4SRafael J. Wysocki } 7417483b4a4SRafael J. Wysocki 7427483b4a4SRafael J. Wysocki power_attr(autosleep); 7437483b4a4SRafael J. Wysocki #endif /* CONFIG_PM_AUTOSLEEP */ 744b86ff982SRafael J. Wysocki 745b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS 746b86ff982SRafael J. Wysocki static ssize_t wake_lock_show(struct kobject *kobj, 747b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 748b86ff982SRafael J. Wysocki char *buf) 749b86ff982SRafael J. Wysocki { 750b86ff982SRafael J. Wysocki return pm_show_wakelocks(buf, true); 751b86ff982SRafael J. Wysocki } 752b86ff982SRafael J. Wysocki 753b86ff982SRafael J. Wysocki static ssize_t wake_lock_store(struct kobject *kobj, 754b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 755b86ff982SRafael J. Wysocki const char *buf, size_t n) 756b86ff982SRafael J. Wysocki { 757b86ff982SRafael J. Wysocki int error = pm_wake_lock(buf); 758b86ff982SRafael J. Wysocki return error ? error : n; 759b86ff982SRafael J. Wysocki } 760b86ff982SRafael J. Wysocki 761b86ff982SRafael J. Wysocki power_attr(wake_lock); 762b86ff982SRafael J. Wysocki 763b86ff982SRafael J. Wysocki static ssize_t wake_unlock_show(struct kobject *kobj, 764b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 765b86ff982SRafael J. Wysocki char *buf) 766b86ff982SRafael J. Wysocki { 767b86ff982SRafael J. Wysocki return pm_show_wakelocks(buf, false); 768b86ff982SRafael J. Wysocki } 769b86ff982SRafael J. Wysocki 770b86ff982SRafael J. Wysocki static ssize_t wake_unlock_store(struct kobject *kobj, 771b86ff982SRafael J. Wysocki struct kobj_attribute *attr, 772b86ff982SRafael J. Wysocki const char *buf, size_t n) 773b86ff982SRafael J. Wysocki { 774b86ff982SRafael J. Wysocki int error = pm_wake_unlock(buf); 775b86ff982SRafael J. Wysocki return error ? error : n; 776b86ff982SRafael J. Wysocki } 777b86ff982SRafael J. Wysocki 778b86ff982SRafael J. Wysocki power_attr(wake_unlock); 779b86ff982SRafael J. Wysocki 780b86ff982SRafael J. Wysocki #endif /* CONFIG_PM_WAKELOCKS */ 781c125e96fSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 782c125e96fSRafael J. Wysocki 783c5c6ba4eSRafael J. Wysocki #ifdef CONFIG_PM_TRACE 784c5c6ba4eSRafael J. Wysocki int pm_trace_enabled; 785c5c6ba4eSRafael J. Wysocki 786386f275fSKay Sievers static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr, 787386f275fSKay Sievers char *buf) 788c5c6ba4eSRafael J. Wysocki { 789c5c6ba4eSRafael J. Wysocki return sprintf(buf, "%d\n", pm_trace_enabled); 790c5c6ba4eSRafael J. Wysocki } 791c5c6ba4eSRafael J. Wysocki 792c5c6ba4eSRafael J. Wysocki static ssize_t 793386f275fSKay Sievers pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr, 794386f275fSKay Sievers const char *buf, size_t n) 795c5c6ba4eSRafael J. Wysocki { 796c5c6ba4eSRafael J. Wysocki int val; 797c5c6ba4eSRafael J. Wysocki 798c5c6ba4eSRafael J. Wysocki if (sscanf(buf, "%d", &val) == 1) { 799c5c6ba4eSRafael J. Wysocki pm_trace_enabled = !!val; 8009dceefe4SShuah Khan if (pm_trace_enabled) { 8019dceefe4SShuah Khan pr_warn("PM: Enabling pm_trace changes system date and time during resume.\n" 8029dceefe4SShuah Khan "PM: Correct system time has to be restored manually after resume.\n"); 8039dceefe4SShuah Khan } 804c5c6ba4eSRafael J. Wysocki return n; 805c5c6ba4eSRafael J. Wysocki } 806c5c6ba4eSRafael J. Wysocki return -EINVAL; 807c5c6ba4eSRafael J. Wysocki } 808c5c6ba4eSRafael J. Wysocki 809c5c6ba4eSRafael J. Wysocki power_attr(pm_trace); 810d33ac60bSJames Hogan 811d33ac60bSJames Hogan static ssize_t pm_trace_dev_match_show(struct kobject *kobj, 812d33ac60bSJames Hogan struct kobj_attribute *attr, 813d33ac60bSJames Hogan char *buf) 814d33ac60bSJames Hogan { 815d33ac60bSJames Hogan return show_trace_dev_match(buf, PAGE_SIZE); 816d33ac60bSJames Hogan } 817d33ac60bSJames Hogan 818a1e9ca69SRafael J. Wysocki power_attr_ro(pm_trace_dev_match); 819d33ac60bSJames Hogan 8200e7d56e3SRafael J. Wysocki #endif /* CONFIG_PM_TRACE */ 821c5c6ba4eSRafael J. Wysocki 822957d1282SLi Fei #ifdef CONFIG_FREEZER 823957d1282SLi Fei static ssize_t pm_freeze_timeout_show(struct kobject *kobj, 824957d1282SLi Fei struct kobj_attribute *attr, char *buf) 825957d1282SLi Fei { 826957d1282SLi Fei return sprintf(buf, "%u\n", freeze_timeout_msecs); 827957d1282SLi Fei } 828957d1282SLi Fei 829957d1282SLi Fei static ssize_t pm_freeze_timeout_store(struct kobject *kobj, 830957d1282SLi Fei struct kobj_attribute *attr, 831957d1282SLi Fei const char *buf, size_t n) 832957d1282SLi Fei { 833957d1282SLi Fei unsigned long val; 834957d1282SLi Fei 835957d1282SLi Fei if (kstrtoul(buf, 10, &val)) 836957d1282SLi Fei return -EINVAL; 837957d1282SLi Fei 838957d1282SLi Fei freeze_timeout_msecs = val; 839957d1282SLi Fei return n; 840957d1282SLi Fei } 841957d1282SLi Fei 842957d1282SLi Fei power_attr(pm_freeze_timeout); 843957d1282SLi Fei 844957d1282SLi Fei #endif /* CONFIG_FREEZER*/ 845957d1282SLi Fei 846c5c6ba4eSRafael J. Wysocki static struct attribute * g[] = { 847c5c6ba4eSRafael J. Wysocki &state_attr.attr, 8480e7d56e3SRafael J. Wysocki #ifdef CONFIG_PM_TRACE 849c5c6ba4eSRafael J. Wysocki &pm_trace_attr.attr, 850d33ac60bSJames Hogan &pm_trace_dev_match_attr.attr, 8510e7d56e3SRafael J. Wysocki #endif 8520e06b4a8SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 8530e06b4a8SRafael J. Wysocki &pm_async_attr.attr, 854c125e96fSRafael J. Wysocki &wakeup_count_attr.attr, 855406e7938SRafael J. Wysocki #ifdef CONFIG_SUSPEND 856406e7938SRafael J. Wysocki &mem_sleep_attr.attr, 857406e7938SRafael J. Wysocki #endif 8587483b4a4SRafael J. Wysocki #ifdef CONFIG_PM_AUTOSLEEP 8597483b4a4SRafael J. Wysocki &autosleep_attr.attr, 8607483b4a4SRafael J. Wysocki #endif 861b86ff982SRafael J. Wysocki #ifdef CONFIG_PM_WAKELOCKS 862b86ff982SRafael J. Wysocki &wake_lock_attr.attr, 863b86ff982SRafael J. Wysocki &wake_unlock_attr.attr, 864b86ff982SRafael J. Wysocki #endif 865b2df1d4fSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_DEBUG 866e516a1dbSRafael J. Wysocki &pm_test_attr.attr, 8674b7760baSSameer Nanda &pm_print_times_attr.attr, 868a6f5f0ddSAlexandra Yates &pm_wakeup_irq_attr.attr, 8698d8b2441SRafael J. Wysocki &pm_debug_messages_attr.attr, 8700e7d56e3SRafael J. Wysocki #endif 8710e06b4a8SRafael J. Wysocki #endif 872957d1282SLi Fei #ifdef CONFIG_FREEZER 873957d1282SLi Fei &pm_freeze_timeout_attr.attr, 874957d1282SLi Fei #endif 875c5c6ba4eSRafael J. Wysocki NULL, 876c5c6ba4eSRafael J. Wysocki }; 8771da177e4SLinus Torvalds 8781d0c6e59SArvind Yadav static const struct attribute_group attr_group = { 8791da177e4SLinus Torvalds .attrs = g, 8801da177e4SLinus Torvalds }; 8811da177e4SLinus Torvalds 882*2c8db5beSKalesh Singh static const struct attribute_group *attr_groups[] = { 883*2c8db5beSKalesh Singh &attr_group, 884*2c8db5beSKalesh Singh #ifdef CONFIG_PM_SLEEP 885*2c8db5beSKalesh Singh &suspend_attr_group, 886*2c8db5beSKalesh Singh #endif 887*2c8db5beSKalesh Singh NULL, 888*2c8db5beSKalesh Singh }; 889*2c8db5beSKalesh Singh 8905e928f77SRafael J. Wysocki struct workqueue_struct *pm_wq; 8917b199ca2SAlan Stern EXPORT_SYMBOL_GPL(pm_wq); 8925e928f77SRafael J. Wysocki 8935e928f77SRafael J. Wysocki static int __init pm_start_workqueue(void) 8945e928f77SRafael J. Wysocki { 89558a69cb4STejun Heo pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0); 8965e928f77SRafael J. Wysocki 8975e928f77SRafael J. Wysocki return pm_wq ? 0 : -ENOMEM; 8985e928f77SRafael J. Wysocki } 8995e928f77SRafael J. Wysocki 9001da177e4SLinus Torvalds static int __init pm_init(void) 9011da177e4SLinus Torvalds { 9025e928f77SRafael J. Wysocki int error = pm_start_workqueue(); 9035e928f77SRafael J. Wysocki if (error) 9045e928f77SRafael J. Wysocki return error; 905ac5c24ecSRafael J. Wysocki hibernate_image_size_init(); 906ddeb6487SRafael J. Wysocki hibernate_reserved_size_init(); 907fa7fd6faSSudeep Holla pm_states_init(); 908d76e15fbSGreg Kroah-Hartman power_kobj = kobject_create_and_add("power", NULL); 909d76e15fbSGreg Kroah-Hartman if (!power_kobj) 910039a5dcdSGreg Kroah-Hartman return -ENOMEM; 911*2c8db5beSKalesh Singh error = sysfs_create_groups(power_kobj, attr_groups); 9127483b4a4SRafael J. Wysocki if (error) 9137483b4a4SRafael J. Wysocki return error; 914b2df1d4fSRafael J. Wysocki pm_print_times_init(); 9157483b4a4SRafael J. Wysocki return pm_autosleep_init(); 9161da177e4SLinus Torvalds } 9171da177e4SLinus Torvalds 9181da177e4SLinus Torvalds core_initcall(pm_init); 919