11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * kernel/power/main.c - PM subsystem core functionality. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2003 Patrick Mochel 51da177e4SLinus Torvalds * Copyright (c) 2003 Open Source Development Lab 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This file is released under the GPLv2 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds 114cf30348SRalf Baechle #include <linux/module.h> 121da177e4SLinus Torvalds #include <linux/suspend.h> 131da177e4SLinus Torvalds #include <linux/kobject.h> 141da177e4SLinus Torvalds #include <linux/string.h> 151da177e4SLinus Torvalds #include <linux/delay.h> 161da177e4SLinus Torvalds #include <linux/errno.h> 171da177e4SLinus Torvalds #include <linux/init.h> 181da177e4SLinus Torvalds #include <linux/pm.h> 196cc07191SAndrew Morton #include <linux/console.h> 20e3920fb4SRafael J. Wysocki #include <linux/cpu.h> 21c5c6ba4eSRafael J. Wysocki #include <linux/resume-trace.h> 227dfb7103SNigel Cunningham #include <linux/freezer.h> 2396177299SChristoph Lameter #include <linux/vmstat.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include "power.h" 261da177e4SLinus Torvalds 275ae947ecSDavid Shaohua Li /*This is just an arbitrary number */ 285ae947ecSDavid Shaohua Li #define FREE_PAGE_NUMBER (100) 295ae947ecSDavid Shaohua Li 30a6d70980SStephen Hemminger DEFINE_MUTEX(pm_mutex); 311da177e4SLinus Torvalds 32123d3c13SPavel Machek struct pm_ops *pm_ops; 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds /** 351da177e4SLinus Torvalds * pm_set_ops - Set the global power method table. 361da177e4SLinus Torvalds * @ops: Pointer to ops structure. 371da177e4SLinus Torvalds */ 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds void pm_set_ops(struct pm_ops * ops) 401da177e4SLinus Torvalds { 41a6d70980SStephen Hemminger mutex_lock(&pm_mutex); 421da177e4SLinus Torvalds pm_ops = ops; 43a6d70980SStephen Hemminger mutex_unlock(&pm_mutex); 441da177e4SLinus Torvalds } 451da177e4SLinus Torvalds 46e8c9c502SJohannes Berg /** 47e8c9c502SJohannes Berg * pm_valid_only_mem - generic memory-only valid callback 48e8c9c502SJohannes Berg * 49e8c9c502SJohannes Berg * pm_ops drivers that implement mem suspend only and only need 50e8c9c502SJohannes Berg * to check for that in their .valid callback can use this instead 51e8c9c502SJohannes Berg * of rolling their own .valid callback. 52e8c9c502SJohannes Berg */ 53e8c9c502SJohannes Berg int pm_valid_only_mem(suspend_state_t state) 54e8c9c502SJohannes Berg { 55e8c9c502SJohannes Berg return state == PM_SUSPEND_MEM; 56e8c9c502SJohannes Berg } 57e8c9c502SJohannes Berg 58e8c9c502SJohannes Berg 59e3c7db62SRafael J. Wysocki static inline void pm_finish(suspend_state_t state) 60e3c7db62SRafael J. Wysocki { 61e3c7db62SRafael J. Wysocki if (pm_ops->finish) 62e3c7db62SRafael J. Wysocki pm_ops->finish(state); 63e3c7db62SRafael J. Wysocki } 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds /** 661da177e4SLinus Torvalds * suspend_prepare - Do prep work before entering low-power state. 671da177e4SLinus Torvalds * @state: State we're entering. 681da177e4SLinus Torvalds * 691da177e4SLinus Torvalds * This is common code that is called for each state that we're 701da177e4SLinus Torvalds * entering. Allocate a console, stop all processes, then make sure 711da177e4SLinus Torvalds * the platform can enter the requested state. 721da177e4SLinus Torvalds */ 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds static int suspend_prepare(suspend_state_t state) 751da177e4SLinus Torvalds { 76e3920fb4SRafael J. Wysocki int error; 775ae947ecSDavid Shaohua Li unsigned int free_pages; 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds if (!pm_ops || !pm_ops->enter) 801da177e4SLinus Torvalds return -EPERM; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds pm_prepare_console(); 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds if (freeze_processes()) { 851da177e4SLinus Torvalds error = -EAGAIN; 861da177e4SLinus Torvalds goto Thaw; 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds 8996177299SChristoph Lameter if ((free_pages = global_page_state(NR_FREE_PAGES)) 9096177299SChristoph Lameter < FREE_PAGE_NUMBER) { 915ae947ecSDavid Shaohua Li pr_debug("PM: free some memory\n"); 925ae947ecSDavid Shaohua Li shrink_all_memory(FREE_PAGE_NUMBER - free_pages); 935ae947ecSDavid Shaohua Li if (nr_free_pages() < FREE_PAGE_NUMBER) { 945ae947ecSDavid Shaohua Li error = -ENOMEM; 955ae947ecSDavid Shaohua Li printk(KERN_ERR "PM: No enough memory\n"); 965ae947ecSDavid Shaohua Li goto Thaw; 975ae947ecSDavid Shaohua Li } 985ae947ecSDavid Shaohua Li } 995ae947ecSDavid Shaohua Li 100557240b4SLinus Torvalds suspend_console(); 101e3c7db62SRafael J. Wysocki error = device_suspend(PMSG_SUSPEND); 102e3c7db62SRafael J. Wysocki if (error) { 1031da177e4SLinus Torvalds printk(KERN_ERR "Some devices failed to suspend\n"); 10452ade9b3SLinus Torvalds goto Resume_console; 10552ade9b3SLinus Torvalds } 10652ade9b3SLinus Torvalds if (pm_ops->prepare) { 10752ade9b3SLinus Torvalds if ((error = pm_ops->prepare(state))) 108e3c7db62SRafael J. Wysocki goto Resume_devices; 1091da177e4SLinus Torvalds } 11052ade9b3SLinus Torvalds 111e3c7db62SRafael J. Wysocki error = disable_nonboot_cpus(); 112e3c7db62SRafael J. Wysocki if (!error) 1131da177e4SLinus Torvalds return 0; 114e3c7db62SRafael J. Wysocki 115e3c7db62SRafael J. Wysocki enable_nonboot_cpus(); 116e3c7db62SRafael J. Wysocki pm_finish(state); 11752ade9b3SLinus Torvalds Resume_devices: 118e3c7db62SRafael J. Wysocki device_resume(); 11952ade9b3SLinus Torvalds Resume_console: 120e3c7db62SRafael J. Wysocki resume_console(); 1211da177e4SLinus Torvalds Thaw: 1221da177e4SLinus Torvalds thaw_processes(); 1231da177e4SLinus Torvalds pm_restore_console(); 1241da177e4SLinus Torvalds return error; 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds 127a53c46dcSJohannes Berg /* default implementation */ 128a53c46dcSJohannes Berg void __attribute__ ((weak)) arch_suspend_disable_irqs(void) 129a53c46dcSJohannes Berg { 130a53c46dcSJohannes Berg local_irq_disable(); 131a53c46dcSJohannes Berg } 132a53c46dcSJohannes Berg 133a53c46dcSJohannes Berg /* default implementation */ 134a53c46dcSJohannes Berg void __attribute__ ((weak)) arch_suspend_enable_irqs(void) 135a53c46dcSJohannes Berg { 136a53c46dcSJohannes Berg local_irq_enable(); 137a53c46dcSJohannes Berg } 1381da177e4SLinus Torvalds 1399b238205SLuca Tettamanti int suspend_enter(suspend_state_t state) 1401da177e4SLinus Torvalds { 1411da177e4SLinus Torvalds int error = 0; 1421da177e4SLinus Torvalds 143a53c46dcSJohannes Berg arch_suspend_disable_irqs(); 144a53c46dcSJohannes Berg BUG_ON(!irqs_disabled()); 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds if ((error = device_power_down(PMSG_SUSPEND))) { 1471da177e4SLinus Torvalds printk(KERN_ERR "Some devices failed to power down\n"); 1481da177e4SLinus Torvalds goto Done; 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds error = pm_ops->enter(state); 1511da177e4SLinus Torvalds device_power_up(); 1521da177e4SLinus Torvalds Done: 153a53c46dcSJohannes Berg arch_suspend_enable_irqs(); 154a53c46dcSJohannes Berg BUG_ON(irqs_disabled()); 1551da177e4SLinus Torvalds return error; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds /** 1601da177e4SLinus Torvalds * suspend_finish - Do final work before exiting suspend sequence. 1611da177e4SLinus Torvalds * @state: State we're coming out of. 1621da177e4SLinus Torvalds * 1631da177e4SLinus Torvalds * Call platform code to clean up, restart processes, and free the 1641da177e4SLinus Torvalds * console that we've allocated. This is not called for suspend-to-disk. 1651da177e4SLinus Torvalds */ 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds static void suspend_finish(suspend_state_t state) 1681da177e4SLinus Torvalds { 169e3c7db62SRafael J. Wysocki enable_nonboot_cpus(); 170e3c7db62SRafael J. Wysocki pm_finish(state); 1711da177e4SLinus Torvalds device_resume(); 172557240b4SLinus Torvalds resume_console(); 1731da177e4SLinus Torvalds thaw_processes(); 1741da177e4SLinus Torvalds pm_restore_console(); 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds 1803b364b8dSAndreas Mohr static const char * const pm_states[PM_SUSPEND_MAX] = { 1811da177e4SLinus Torvalds [PM_SUSPEND_STANDBY] = "standby", 1821da177e4SLinus Torvalds [PM_SUSPEND_MEM] = "mem", 1831da177e4SLinus Torvalds }; 1841da177e4SLinus Torvalds 185123d3c13SPavel Machek static inline int valid_state(suspend_state_t state) 186123d3c13SPavel Machek { 187a3d25c27SRafael J. Wysocki /* All states need lowlevel support and need to be valid 188a3d25c27SRafael J. Wysocki * to the lowlevel implementation, no valid callback 1899684e51cSJohannes Berg * implies that none are valid. */ 1909684e51cSJohannes Berg if (!pm_ops || !pm_ops->valid || !pm_ops->valid(state)) 191123d3c13SPavel Machek return 0; 192123d3c13SPavel Machek return 1; 193123d3c13SPavel Machek } 194123d3c13SPavel Machek 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds /** 1971da177e4SLinus Torvalds * enter_state - Do common work of entering low-power state. 1981da177e4SLinus Torvalds * @state: pm_state structure for state we're entering. 1991da177e4SLinus Torvalds * 2001da177e4SLinus Torvalds * Make sure we're the only ones trying to enter a sleep state. Fail 2011da177e4SLinus Torvalds * if someone has beat us to it, since we don't want anything weird to 2021da177e4SLinus Torvalds * happen when we wake up. 2031da177e4SLinus Torvalds * Then, do the setup for suspend, enter the state, and cleaup (after 2041da177e4SLinus Torvalds * we've woken up). 2051da177e4SLinus Torvalds */ 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds static int enter_state(suspend_state_t state) 2081da177e4SLinus Torvalds { 2091da177e4SLinus Torvalds int error; 2101da177e4SLinus Torvalds 211123d3c13SPavel Machek if (!valid_state(state)) 212eb9289ebSShaohua Li return -ENODEV; 213a6d70980SStephen Hemminger if (!mutex_trylock(&pm_mutex)) 2141da177e4SLinus Torvalds return -EBUSY; 2151da177e4SLinus Torvalds 21682428b62SDavid Brownell pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); 2171da177e4SLinus Torvalds if ((error = suspend_prepare(state))) 2181da177e4SLinus Torvalds goto Unlock; 2191da177e4SLinus Torvalds 22082428b62SDavid Brownell pr_debug("PM: Entering %s sleep\n", pm_states[state]); 2211da177e4SLinus Torvalds error = suspend_enter(state); 2221da177e4SLinus Torvalds 22382428b62SDavid Brownell pr_debug("PM: Finishing wakeup.\n"); 2241da177e4SLinus Torvalds suspend_finish(state); 2251da177e4SLinus Torvalds Unlock: 226a6d70980SStephen Hemminger mutex_unlock(&pm_mutex); 2271da177e4SLinus Torvalds return error; 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds /** 2321da177e4SLinus Torvalds * pm_suspend - Externally visible function for suspending system. 233a3d25c27SRafael J. Wysocki * @state: Enumerated value of state to enter. 2341da177e4SLinus Torvalds * 2351da177e4SLinus Torvalds * Determine whether or not value is within range, get state 2361da177e4SLinus Torvalds * structure, and enter (above). 2371da177e4SLinus Torvalds */ 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds int pm_suspend(suspend_state_t state) 2401da177e4SLinus Torvalds { 241e2a5b420SAlexey Starikovskiy if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX) 2421da177e4SLinus Torvalds return enter_state(state); 2431da177e4SLinus Torvalds return -EINVAL; 2441da177e4SLinus Torvalds } 2451da177e4SLinus Torvalds 2464cf30348SRalf Baechle EXPORT_SYMBOL(pm_suspend); 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds decl_subsys(power,NULL,NULL); 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds /** 2521da177e4SLinus Torvalds * state - control system power state. 2531da177e4SLinus Torvalds * 2541da177e4SLinus Torvalds * show() returns what states are supported, which is hard-coded to 2551da177e4SLinus Torvalds * 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and 2561da177e4SLinus Torvalds * 'disk' (Suspend-to-Disk). 2571da177e4SLinus Torvalds * 2581da177e4SLinus Torvalds * store() accepts one of those strings, translates it into the 2591da177e4SLinus Torvalds * proper enumerated value, and initiates a suspend transition. 2601da177e4SLinus Torvalds */ 2611da177e4SLinus Torvalds 262823bccfcSGreg Kroah-Hartman static ssize_t state_show(struct kset *kset, char *buf) 2631da177e4SLinus Torvalds { 2641da177e4SLinus Torvalds int i; 2651da177e4SLinus Torvalds char * s = buf; 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds for (i = 0; i < PM_SUSPEND_MAX; i++) { 268123d3c13SPavel Machek if (pm_states[i] && valid_state(i)) 2691da177e4SLinus Torvalds s += sprintf(s,"%s ", pm_states[i]); 2701da177e4SLinus Torvalds } 271a3d25c27SRafael J. Wysocki #ifdef CONFIG_SOFTWARE_SUSPEND 272a3d25c27SRafael J. Wysocki s += sprintf(s, "%s\n", "disk"); 273a3d25c27SRafael J. Wysocki #else 274a3d25c27SRafael J. Wysocki if (s != buf) 275a3d25c27SRafael J. Wysocki /* convert the last space to a newline */ 276a3d25c27SRafael J. Wysocki *(s-1) = '\n'; 277a3d25c27SRafael J. Wysocki #endif 2781da177e4SLinus Torvalds return (s - buf); 2791da177e4SLinus Torvalds } 2801da177e4SLinus Torvalds 281823bccfcSGreg Kroah-Hartman static ssize_t state_store(struct kset *kset, const char *buf, size_t n) 2821da177e4SLinus Torvalds { 2831da177e4SLinus Torvalds suspend_state_t state = PM_SUSPEND_STANDBY; 2843b364b8dSAndreas Mohr const char * const *s; 2851da177e4SLinus Torvalds char *p; 2861da177e4SLinus Torvalds int error; 2871da177e4SLinus Torvalds int len; 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds p = memchr(buf, '\n', n); 2901da177e4SLinus Torvalds len = p ? p - buf : n; 2911da177e4SLinus Torvalds 292a3d25c27SRafael J. Wysocki /* First, check if we are requested to hibernate */ 293*8d98a690SRafael J. Wysocki if (len == 4 && !strncmp(buf, "disk", len)) { 294a3d25c27SRafael J. Wysocki error = hibernate(); 295a3d25c27SRafael J. Wysocki return error ? error : n; 296a3d25c27SRafael J. Wysocki } 297a3d25c27SRafael J. Wysocki 2981da177e4SLinus Torvalds for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) { 299*8d98a690SRafael J. Wysocki if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) 3001da177e4SLinus Torvalds break; 3011da177e4SLinus Torvalds } 30247bb7899Sdean gaudet if (state < PM_SUSPEND_MAX && *s) 3031da177e4SLinus Torvalds error = enter_state(state); 3041da177e4SLinus Torvalds else 3051da177e4SLinus Torvalds error = -EINVAL; 3061da177e4SLinus Torvalds return error ? error : n; 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds power_attr(state); 3101da177e4SLinus Torvalds 311c5c6ba4eSRafael J. Wysocki #ifdef CONFIG_PM_TRACE 312c5c6ba4eSRafael J. Wysocki int pm_trace_enabled; 313c5c6ba4eSRafael J. Wysocki 314823bccfcSGreg Kroah-Hartman static ssize_t pm_trace_show(struct kset *kset, char *buf) 315c5c6ba4eSRafael J. Wysocki { 316c5c6ba4eSRafael J. Wysocki return sprintf(buf, "%d\n", pm_trace_enabled); 317c5c6ba4eSRafael J. Wysocki } 318c5c6ba4eSRafael J. Wysocki 319c5c6ba4eSRafael J. Wysocki static ssize_t 320823bccfcSGreg Kroah-Hartman pm_trace_store(struct kset *kset, const char *buf, size_t n) 321c5c6ba4eSRafael J. Wysocki { 322c5c6ba4eSRafael J. Wysocki int val; 323c5c6ba4eSRafael J. Wysocki 324c5c6ba4eSRafael J. Wysocki if (sscanf(buf, "%d", &val) == 1) { 325c5c6ba4eSRafael J. Wysocki pm_trace_enabled = !!val; 326c5c6ba4eSRafael J. Wysocki return n; 327c5c6ba4eSRafael J. Wysocki } 328c5c6ba4eSRafael J. Wysocki return -EINVAL; 329c5c6ba4eSRafael J. Wysocki } 330c5c6ba4eSRafael J. Wysocki 331c5c6ba4eSRafael J. Wysocki power_attr(pm_trace); 332c5c6ba4eSRafael J. Wysocki 333c5c6ba4eSRafael J. Wysocki static struct attribute * g[] = { 334c5c6ba4eSRafael J. Wysocki &state_attr.attr, 335c5c6ba4eSRafael J. Wysocki &pm_trace_attr.attr, 336c5c6ba4eSRafael J. Wysocki NULL, 337c5c6ba4eSRafael J. Wysocki }; 338c5c6ba4eSRafael J. Wysocki #else 3391da177e4SLinus Torvalds static struct attribute * g[] = { 3401da177e4SLinus Torvalds &state_attr.attr, 3411da177e4SLinus Torvalds NULL, 3421da177e4SLinus Torvalds }; 343c5c6ba4eSRafael J. Wysocki #endif /* CONFIG_PM_TRACE */ 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds static struct attribute_group attr_group = { 3461da177e4SLinus Torvalds .attrs = g, 3471da177e4SLinus Torvalds }; 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds static int __init pm_init(void) 3511da177e4SLinus Torvalds { 3521da177e4SLinus Torvalds int error = subsystem_register(&power_subsys); 3531da177e4SLinus Torvalds if (!error) 354823bccfcSGreg Kroah-Hartman error = sysfs_create_group(&power_subsys.kobj,&attr_group); 3551da177e4SLinus Torvalds return error; 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds core_initcall(pm_init); 359