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> 186cc07191SAndrew Morton #include <linux/console.h> 19e3920fb4SRafael J. Wysocki #include <linux/cpu.h> 20c5c6ba4eSRafael J. Wysocki #include <linux/resume-trace.h> 217dfb7103SNigel Cunningham #include <linux/freezer.h> 2296177299SChristoph Lameter #include <linux/vmstat.h> 23*232b1432SRafael J. Wysocki #include <linux/syscalls.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include "power.h" 261da177e4SLinus Torvalds 27b10d9117SRafael J. Wysocki BLOCKING_NOTIFIER_HEAD(pm_chain_head); 28b10d9117SRafael J. Wysocki 29296699deSRafael J. Wysocki DEFINE_MUTEX(pm_mutex); 30296699deSRafael J. Wysocki 31296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 32296699deSRafael J. Wysocki 335ae947ecSDavid Shaohua Li /* This is just an arbitrary number */ 345ae947ecSDavid Shaohua Li #define FREE_PAGE_NUMBER (100) 355ae947ecSDavid Shaohua Li 36f242d919SRafael J. Wysocki static struct platform_suspend_ops *suspend_ops; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /** 3926398a70SRafael J. Wysocki * suspend_set_ops - Set the global suspend method table. 401da177e4SLinus Torvalds * @ops: Pointer to ops structure. 411da177e4SLinus Torvalds */ 421da177e4SLinus Torvalds 4326398a70SRafael J. Wysocki void suspend_set_ops(struct platform_suspend_ops *ops) 441da177e4SLinus Torvalds { 45a6d70980SStephen Hemminger mutex_lock(&pm_mutex); 4626398a70SRafael J. Wysocki suspend_ops = ops; 47a6d70980SStephen Hemminger mutex_unlock(&pm_mutex); 481da177e4SLinus Torvalds } 491da177e4SLinus Torvalds 50e8c9c502SJohannes Berg /** 5126398a70SRafael J. Wysocki * suspend_valid_only_mem - generic memory-only valid callback 52e8c9c502SJohannes Berg * 5326398a70SRafael J. Wysocki * Platform drivers that implement mem suspend only and only need 54e8c9c502SJohannes Berg * to check for that in their .valid callback can use this instead 55e8c9c502SJohannes Berg * of rolling their own .valid callback. 56e8c9c502SJohannes Berg */ 5726398a70SRafael J. Wysocki int suspend_valid_only_mem(suspend_state_t state) 58e8c9c502SJohannes Berg { 59e8c9c502SJohannes Berg return state == PM_SUSPEND_MEM; 60e8c9c502SJohannes Berg } 61e8c9c502SJohannes Berg 621da177e4SLinus Torvalds /** 631da177e4SLinus Torvalds * suspend_prepare - Do prep work before entering low-power state. 641da177e4SLinus Torvalds * 656c961dfbSRafael J. Wysocki * This is common code that is called for each state that we're entering. 666c961dfbSRafael J. Wysocki * Run suspend notifiers, allocate a console and stop all processes. 671da177e4SLinus Torvalds */ 686c961dfbSRafael J. Wysocki static int suspend_prepare(void) 691da177e4SLinus Torvalds { 70e3920fb4SRafael J. Wysocki int error; 715ae947ecSDavid Shaohua Li unsigned int free_pages; 721da177e4SLinus Torvalds 7326398a70SRafael J. Wysocki if (!suspend_ops || !suspend_ops->enter) 741da177e4SLinus Torvalds return -EPERM; 751da177e4SLinus Torvalds 76b10d9117SRafael J. Wysocki error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); 77b10d9117SRafael J. Wysocki if (error) 78b10d9117SRafael J. Wysocki goto Finish; 79b10d9117SRafael J. Wysocki 801da177e4SLinus Torvalds pm_prepare_console(); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds if (freeze_processes()) { 831da177e4SLinus Torvalds error = -EAGAIN; 841da177e4SLinus Torvalds goto Thaw; 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 876c961dfbSRafael J. Wysocki free_pages = global_page_state(NR_FREE_PAGES); 886c961dfbSRafael J. Wysocki if (free_pages < FREE_PAGE_NUMBER) { 895ae947ecSDavid Shaohua Li pr_debug("PM: free some memory\n"); 905ae947ecSDavid Shaohua Li shrink_all_memory(FREE_PAGE_NUMBER - free_pages); 915ae947ecSDavid Shaohua Li if (nr_free_pages() < FREE_PAGE_NUMBER) { 925ae947ecSDavid Shaohua Li error = -ENOMEM; 935ae947ecSDavid Shaohua Li printk(KERN_ERR "PM: No enough memory\n"); 945ae947ecSDavid Shaohua Li } 955ae947ecSDavid Shaohua Li } 96e3c7db62SRafael J. Wysocki if (!error) 971da177e4SLinus Torvalds return 0; 98e3c7db62SRafael J. Wysocki 991da177e4SLinus Torvalds Thaw: 1001da177e4SLinus Torvalds thaw_processes(); 1011da177e4SLinus Torvalds pm_restore_console(); 102b10d9117SRafael J. Wysocki Finish: 103b10d9117SRafael J. Wysocki pm_notifier_call_chain(PM_POST_SUSPEND); 1041da177e4SLinus Torvalds return error; 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 107a53c46dcSJohannes Berg /* default implementation */ 108a53c46dcSJohannes Berg void __attribute__ ((weak)) arch_suspend_disable_irqs(void) 109a53c46dcSJohannes Berg { 110a53c46dcSJohannes Berg local_irq_disable(); 111a53c46dcSJohannes Berg } 112a53c46dcSJohannes Berg 113a53c46dcSJohannes Berg /* default implementation */ 114a53c46dcSJohannes Berg void __attribute__ ((weak)) arch_suspend_enable_irqs(void) 115a53c46dcSJohannes Berg { 116a53c46dcSJohannes Berg local_irq_enable(); 117a53c46dcSJohannes Berg } 1181da177e4SLinus Torvalds 1196c961dfbSRafael J. Wysocki /** 1206c961dfbSRafael J. Wysocki * suspend_enter - enter the desired system sleep state. 1216c961dfbSRafael J. Wysocki * @state: state to enter 1226c961dfbSRafael J. Wysocki * 1236c961dfbSRafael J. Wysocki * This function should be called after devices have been suspended. 1246c961dfbSRafael J. Wysocki */ 125a065c86eSAdrian Bunk static int suspend_enter(suspend_state_t state) 1261da177e4SLinus Torvalds { 1271da177e4SLinus Torvalds int error = 0; 1281da177e4SLinus Torvalds 129a53c46dcSJohannes Berg arch_suspend_disable_irqs(); 130a53c46dcSJohannes Berg BUG_ON(!irqs_disabled()); 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds if ((error = device_power_down(PMSG_SUSPEND))) { 1331da177e4SLinus Torvalds printk(KERN_ERR "Some devices failed to power down\n"); 1341da177e4SLinus Torvalds goto Done; 1351da177e4SLinus Torvalds } 13626398a70SRafael J. Wysocki error = suspend_ops->enter(state); 1371da177e4SLinus Torvalds device_power_up(); 1381da177e4SLinus Torvalds Done: 139a53c46dcSJohannes Berg arch_suspend_enable_irqs(); 140a53c46dcSJohannes Berg BUG_ON(irqs_disabled()); 1411da177e4SLinus Torvalds return error; 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1446c961dfbSRafael J. Wysocki /** 1456c961dfbSRafael J. Wysocki * suspend_devices_and_enter - suspend devices and enter the desired system sleep 1466c961dfbSRafael J. Wysocki * state. 1476c961dfbSRafael J. Wysocki * @state: state to enter 1486c961dfbSRafael J. Wysocki */ 1496c961dfbSRafael J. Wysocki int suspend_devices_and_enter(suspend_state_t state) 1506c961dfbSRafael J. Wysocki { 1516c961dfbSRafael J. Wysocki int error; 1526c961dfbSRafael J. Wysocki 15326398a70SRafael J. Wysocki if (!suspend_ops) 1546c961dfbSRafael J. Wysocki return -ENOSYS; 1556c961dfbSRafael J. Wysocki 15626398a70SRafael J. Wysocki if (suspend_ops->set_target) { 15726398a70SRafael J. Wysocki error = suspend_ops->set_target(state); 1586c961dfbSRafael J. Wysocki if (error) 1596c961dfbSRafael J. Wysocki return error; 1606c961dfbSRafael J. Wysocki } 1616c961dfbSRafael J. Wysocki suspend_console(); 1626c961dfbSRafael J. Wysocki error = device_suspend(PMSG_SUSPEND); 1636c961dfbSRafael J. Wysocki if (error) { 1646c961dfbSRafael J. Wysocki printk(KERN_ERR "Some devices failed to suspend\n"); 1656c961dfbSRafael J. Wysocki goto Resume_console; 1666c961dfbSRafael J. Wysocki } 16726398a70SRafael J. Wysocki if (suspend_ops->prepare) { 168e6c5eb95SRafael J. Wysocki error = suspend_ops->prepare(); 1696c961dfbSRafael J. Wysocki if (error) 1706c961dfbSRafael J. Wysocki goto Resume_devices; 1716c961dfbSRafael J. Wysocki } 1726c961dfbSRafael J. Wysocki error = disable_nonboot_cpus(); 1736c961dfbSRafael J. Wysocki if (!error) 1746c961dfbSRafael J. Wysocki suspend_enter(state); 1756c961dfbSRafael J. Wysocki 1766c961dfbSRafael J. Wysocki enable_nonboot_cpus(); 177e6c5eb95SRafael J. Wysocki if (suspend_ops->finish) 178e6c5eb95SRafael J. Wysocki suspend_ops->finish(); 1796c961dfbSRafael J. Wysocki Resume_devices: 1806c961dfbSRafael J. Wysocki device_resume(); 1816c961dfbSRafael J. Wysocki Resume_console: 1826c961dfbSRafael J. Wysocki resume_console(); 1836c961dfbSRafael J. Wysocki return error; 1846c961dfbSRafael J. Wysocki } 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds /** 1871da177e4SLinus Torvalds * suspend_finish - Do final work before exiting suspend sequence. 1881da177e4SLinus Torvalds * 1891da177e4SLinus Torvalds * Call platform code to clean up, restart processes, and free the 1901da177e4SLinus Torvalds * console that we've allocated. This is not called for suspend-to-disk. 1911da177e4SLinus Torvalds */ 1926c961dfbSRafael J. Wysocki static void suspend_finish(void) 1931da177e4SLinus Torvalds { 1941da177e4SLinus Torvalds thaw_processes(); 1951da177e4SLinus Torvalds pm_restore_console(); 196b10d9117SRafael J. Wysocki pm_notifier_call_chain(PM_POST_SUSPEND); 1971da177e4SLinus Torvalds } 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds 2023b364b8dSAndreas Mohr static const char * const pm_states[PM_SUSPEND_MAX] = { 2031da177e4SLinus Torvalds [PM_SUSPEND_STANDBY] = "standby", 2041da177e4SLinus Torvalds [PM_SUSPEND_MEM] = "mem", 2051da177e4SLinus Torvalds }; 2061da177e4SLinus Torvalds 207123d3c13SPavel Machek static inline int valid_state(suspend_state_t state) 208123d3c13SPavel Machek { 209a3d25c27SRafael J. Wysocki /* All states need lowlevel support and need to be valid 210a3d25c27SRafael J. Wysocki * to the lowlevel implementation, no valid callback 2119684e51cSJohannes Berg * implies that none are valid. */ 21226398a70SRafael J. Wysocki if (!suspend_ops || !suspend_ops->valid || !suspend_ops->valid(state)) 213123d3c13SPavel Machek return 0; 214123d3c13SPavel Machek return 1; 215123d3c13SPavel Machek } 216123d3c13SPavel Machek 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds /** 2191da177e4SLinus Torvalds * enter_state - Do common work of entering low-power state. 2201da177e4SLinus Torvalds * @state: pm_state structure for state we're entering. 2211da177e4SLinus Torvalds * 2221da177e4SLinus Torvalds * Make sure we're the only ones trying to enter a sleep state. Fail 2231da177e4SLinus Torvalds * if someone has beat us to it, since we don't want anything weird to 2241da177e4SLinus Torvalds * happen when we wake up. 2251da177e4SLinus Torvalds * Then, do the setup for suspend, enter the state, and cleaup (after 2261da177e4SLinus Torvalds * we've woken up). 2271da177e4SLinus Torvalds */ 2281da177e4SLinus Torvalds static int enter_state(suspend_state_t state) 2291da177e4SLinus Torvalds { 2301da177e4SLinus Torvalds int error; 2311da177e4SLinus Torvalds 232123d3c13SPavel Machek if (!valid_state(state)) 233eb9289ebSShaohua Li return -ENODEV; 234*232b1432SRafael J. Wysocki 235a6d70980SStephen Hemminger if (!mutex_trylock(&pm_mutex)) 2361da177e4SLinus Torvalds return -EBUSY; 2371da177e4SLinus Torvalds 238*232b1432SRafael J. Wysocki printk("Syncing filesystems ... "); 239*232b1432SRafael J. Wysocki sys_sync(); 240*232b1432SRafael J. Wysocki printk("done.\n"); 241*232b1432SRafael J. Wysocki 24282428b62SDavid Brownell pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); 2436c961dfbSRafael J. Wysocki if ((error = suspend_prepare())) 2441da177e4SLinus Torvalds goto Unlock; 2451da177e4SLinus Torvalds 24682428b62SDavid Brownell pr_debug("PM: Entering %s sleep\n", pm_states[state]); 2476c961dfbSRafael J. Wysocki error = suspend_devices_and_enter(state); 2481da177e4SLinus Torvalds 24982428b62SDavid Brownell pr_debug("PM: Finishing wakeup.\n"); 2506c961dfbSRafael J. Wysocki suspend_finish(); 2511da177e4SLinus Torvalds Unlock: 252a6d70980SStephen Hemminger mutex_unlock(&pm_mutex); 2531da177e4SLinus Torvalds return error; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds /** 2581da177e4SLinus Torvalds * pm_suspend - Externally visible function for suspending system. 259a3d25c27SRafael J. Wysocki * @state: Enumerated value of state to enter. 2601da177e4SLinus Torvalds * 2611da177e4SLinus Torvalds * Determine whether or not value is within range, get state 2621da177e4SLinus Torvalds * structure, and enter (above). 2631da177e4SLinus Torvalds */ 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds int pm_suspend(suspend_state_t state) 2661da177e4SLinus Torvalds { 267e2a5b420SAlexey Starikovskiy if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX) 2681da177e4SLinus Torvalds return enter_state(state); 2691da177e4SLinus Torvalds return -EINVAL; 2701da177e4SLinus Torvalds } 2711da177e4SLinus Torvalds 2724cf30348SRalf Baechle EXPORT_SYMBOL(pm_suspend); 2731da177e4SLinus Torvalds 274296699deSRafael J. Wysocki #endif /* CONFIG_SUSPEND */ 275296699deSRafael J. Wysocki 2761da177e4SLinus Torvalds decl_subsys(power,NULL,NULL); 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds /** 2801da177e4SLinus Torvalds * state - control system power state. 2811da177e4SLinus Torvalds * 2821da177e4SLinus Torvalds * show() returns what states are supported, which is hard-coded to 2831da177e4SLinus Torvalds * 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and 2841da177e4SLinus Torvalds * 'disk' (Suspend-to-Disk). 2851da177e4SLinus Torvalds * 2861da177e4SLinus Torvalds * store() accepts one of those strings, translates it into the 2871da177e4SLinus Torvalds * proper enumerated value, and initiates a suspend transition. 2881da177e4SLinus Torvalds */ 2891da177e4SLinus Torvalds 290823bccfcSGreg Kroah-Hartman static ssize_t state_show(struct kset *kset, char *buf) 2911da177e4SLinus Torvalds { 2921da177e4SLinus Torvalds char *s = buf; 293296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 294296699deSRafael J. Wysocki int i; 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds for (i = 0; i < PM_SUSPEND_MAX; i++) { 297123d3c13SPavel Machek if (pm_states[i] && valid_state(i)) 2981da177e4SLinus Torvalds s += sprintf(s,"%s ", pm_states[i]); 2991da177e4SLinus Torvalds } 300296699deSRafael J. Wysocki #endif 301b0cb1a19SRafael J. Wysocki #ifdef CONFIG_HIBERNATION 302a3d25c27SRafael J. Wysocki s += sprintf(s, "%s\n", "disk"); 303a3d25c27SRafael J. Wysocki #else 304a3d25c27SRafael J. Wysocki if (s != buf) 305a3d25c27SRafael J. Wysocki /* convert the last space to a newline */ 306a3d25c27SRafael J. Wysocki *(s-1) = '\n'; 307a3d25c27SRafael J. Wysocki #endif 3081da177e4SLinus Torvalds return (s - buf); 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds 311823bccfcSGreg Kroah-Hartman static ssize_t state_store(struct kset *kset, const char *buf, size_t n) 3121da177e4SLinus Torvalds { 313296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 3141da177e4SLinus Torvalds suspend_state_t state = PM_SUSPEND_STANDBY; 3153b364b8dSAndreas Mohr const char * const *s; 316296699deSRafael J. Wysocki #endif 3171da177e4SLinus Torvalds char *p; 3181da177e4SLinus Torvalds int len; 319296699deSRafael J. Wysocki int error = -EINVAL; 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds p = memchr(buf, '\n', n); 3221da177e4SLinus Torvalds len = p ? p - buf : n; 3231da177e4SLinus Torvalds 324a3d25c27SRafael J. Wysocki /* First, check if we are requested to hibernate */ 3258d98a690SRafael J. Wysocki if (len == 4 && !strncmp(buf, "disk", len)) { 326a3d25c27SRafael J. Wysocki error = hibernate(); 327296699deSRafael J. Wysocki goto Exit; 328a3d25c27SRafael J. Wysocki } 329a3d25c27SRafael J. Wysocki 330296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 3311da177e4SLinus Torvalds for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) { 3328d98a690SRafael J. Wysocki if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) 3331da177e4SLinus Torvalds break; 3341da177e4SLinus Torvalds } 33547bb7899Sdean gaudet if (state < PM_SUSPEND_MAX && *s) 3361da177e4SLinus Torvalds error = enter_state(state); 337296699deSRafael J. Wysocki #endif 338296699deSRafael J. Wysocki 339296699deSRafael J. Wysocki Exit: 3401da177e4SLinus Torvalds return error ? error : n; 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds power_attr(state); 3441da177e4SLinus Torvalds 345c5c6ba4eSRafael J. Wysocki #ifdef CONFIG_PM_TRACE 346c5c6ba4eSRafael J. Wysocki int pm_trace_enabled; 347c5c6ba4eSRafael J. Wysocki 348823bccfcSGreg Kroah-Hartman static ssize_t pm_trace_show(struct kset *kset, char *buf) 349c5c6ba4eSRafael J. Wysocki { 350c5c6ba4eSRafael J. Wysocki return sprintf(buf, "%d\n", pm_trace_enabled); 351c5c6ba4eSRafael J. Wysocki } 352c5c6ba4eSRafael J. Wysocki 353c5c6ba4eSRafael J. Wysocki static ssize_t 354823bccfcSGreg Kroah-Hartman pm_trace_store(struct kset *kset, const char *buf, size_t n) 355c5c6ba4eSRafael J. Wysocki { 356c5c6ba4eSRafael J. Wysocki int val; 357c5c6ba4eSRafael J. Wysocki 358c5c6ba4eSRafael J. Wysocki if (sscanf(buf, "%d", &val) == 1) { 359c5c6ba4eSRafael J. Wysocki pm_trace_enabled = !!val; 360c5c6ba4eSRafael J. Wysocki return n; 361c5c6ba4eSRafael J. Wysocki } 362c5c6ba4eSRafael J. Wysocki return -EINVAL; 363c5c6ba4eSRafael J. Wysocki } 364c5c6ba4eSRafael J. Wysocki 365c5c6ba4eSRafael J. Wysocki power_attr(pm_trace); 366c5c6ba4eSRafael J. Wysocki 367c5c6ba4eSRafael J. Wysocki static struct attribute * g[] = { 368c5c6ba4eSRafael J. Wysocki &state_attr.attr, 369c5c6ba4eSRafael J. Wysocki &pm_trace_attr.attr, 370c5c6ba4eSRafael J. Wysocki NULL, 371c5c6ba4eSRafael J. Wysocki }; 372c5c6ba4eSRafael J. Wysocki #else 3731da177e4SLinus Torvalds static struct attribute * g[] = { 3741da177e4SLinus Torvalds &state_attr.attr, 3751da177e4SLinus Torvalds NULL, 3761da177e4SLinus Torvalds }; 377c5c6ba4eSRafael J. Wysocki #endif /* CONFIG_PM_TRACE */ 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds static struct attribute_group attr_group = { 3801da177e4SLinus Torvalds .attrs = g, 3811da177e4SLinus Torvalds }; 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds static int __init pm_init(void) 3851da177e4SLinus Torvalds { 3861da177e4SLinus Torvalds int error = subsystem_register(&power_subsys); 3871da177e4SLinus Torvalds if (!error) 388823bccfcSGreg Kroah-Hartman error = sysfs_create_group(&power_subsys.kobj,&attr_group); 3891da177e4SLinus Torvalds return error; 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds core_initcall(pm_init); 393