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> 23232b1432SRafael 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 319f9adecdSLen Brown unsigned int pm_flags; 329f9adecdSLen Brown EXPORT_SYMBOL(pm_flags); 339f9adecdSLen Brown 34296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 35296699deSRafael J. Wysocki 365ae947ecSDavid Shaohua Li /* This is just an arbitrary number */ 375ae947ecSDavid Shaohua Li #define FREE_PAGE_NUMBER (100) 385ae947ecSDavid Shaohua Li 39f242d919SRafael J. Wysocki static struct platform_suspend_ops *suspend_ops; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds /** 4226398a70SRafael J. Wysocki * suspend_set_ops - Set the global suspend method table. 431da177e4SLinus Torvalds * @ops: Pointer to ops structure. 441da177e4SLinus Torvalds */ 451da177e4SLinus Torvalds 4626398a70SRafael J. Wysocki void suspend_set_ops(struct platform_suspend_ops *ops) 471da177e4SLinus Torvalds { 48a6d70980SStephen Hemminger mutex_lock(&pm_mutex); 4926398a70SRafael J. Wysocki suspend_ops = ops; 50a6d70980SStephen Hemminger mutex_unlock(&pm_mutex); 511da177e4SLinus Torvalds } 521da177e4SLinus Torvalds 53e8c9c502SJohannes Berg /** 5426398a70SRafael J. Wysocki * suspend_valid_only_mem - generic memory-only valid callback 55e8c9c502SJohannes Berg * 5626398a70SRafael J. Wysocki * Platform drivers that implement mem suspend only and only need 57e8c9c502SJohannes Berg * to check for that in their .valid callback can use this instead 58e8c9c502SJohannes Berg * of rolling their own .valid callback. 59e8c9c502SJohannes Berg */ 6026398a70SRafael J. Wysocki int suspend_valid_only_mem(suspend_state_t state) 61e8c9c502SJohannes Berg { 62e8c9c502SJohannes Berg return state == PM_SUSPEND_MEM; 63e8c9c502SJohannes Berg } 64e8c9c502SJohannes Berg 651da177e4SLinus Torvalds /** 661da177e4SLinus Torvalds * suspend_prepare - Do prep work before entering low-power state. 671da177e4SLinus Torvalds * 686c961dfbSRafael J. Wysocki * This is common code that is called for each state that we're entering. 696c961dfbSRafael J. Wysocki * Run suspend notifiers, allocate a console and stop all processes. 701da177e4SLinus Torvalds */ 716c961dfbSRafael J. Wysocki static int suspend_prepare(void) 721da177e4SLinus Torvalds { 73e3920fb4SRafael J. Wysocki int error; 745ae947ecSDavid Shaohua Li unsigned int free_pages; 751da177e4SLinus Torvalds 7626398a70SRafael J. Wysocki if (!suspend_ops || !suspend_ops->enter) 771da177e4SLinus Torvalds return -EPERM; 781da177e4SLinus Torvalds 79b10d9117SRafael J. Wysocki error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); 80b10d9117SRafael J. Wysocki if (error) 81b10d9117SRafael J. Wysocki goto Finish; 82b10d9117SRafael J. Wysocki 831da177e4SLinus Torvalds pm_prepare_console(); 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds if (freeze_processes()) { 861da177e4SLinus Torvalds error = -EAGAIN; 871da177e4SLinus Torvalds goto Thaw; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 906c961dfbSRafael J. Wysocki free_pages = global_page_state(NR_FREE_PAGES); 916c961dfbSRafael J. Wysocki if (free_pages < FREE_PAGE_NUMBER) { 925ae947ecSDavid Shaohua Li pr_debug("PM: free some memory\n"); 935ae947ecSDavid Shaohua Li shrink_all_memory(FREE_PAGE_NUMBER - free_pages); 945ae947ecSDavid Shaohua Li if (nr_free_pages() < FREE_PAGE_NUMBER) { 955ae947ecSDavid Shaohua Li error = -ENOMEM; 965ae947ecSDavid Shaohua Li printk(KERN_ERR "PM: No enough memory\n"); 975ae947ecSDavid Shaohua Li } 985ae947ecSDavid Shaohua Li } 99e3c7db62SRafael J. Wysocki if (!error) 1001da177e4SLinus Torvalds return 0; 101e3c7db62SRafael J. Wysocki 1021da177e4SLinus Torvalds Thaw: 1031da177e4SLinus Torvalds thaw_processes(); 1041da177e4SLinus Torvalds pm_restore_console(); 105b10d9117SRafael J. Wysocki Finish: 106b10d9117SRafael J. Wysocki pm_notifier_call_chain(PM_POST_SUSPEND); 1071da177e4SLinus Torvalds return error; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 110a53c46dcSJohannes Berg /* default implementation */ 111a53c46dcSJohannes Berg void __attribute__ ((weak)) arch_suspend_disable_irqs(void) 112a53c46dcSJohannes Berg { 113a53c46dcSJohannes Berg local_irq_disable(); 114a53c46dcSJohannes Berg } 115a53c46dcSJohannes Berg 116a53c46dcSJohannes Berg /* default implementation */ 117a53c46dcSJohannes Berg void __attribute__ ((weak)) arch_suspend_enable_irqs(void) 118a53c46dcSJohannes Berg { 119a53c46dcSJohannes Berg local_irq_enable(); 120a53c46dcSJohannes Berg } 1211da177e4SLinus Torvalds 1226c961dfbSRafael J. Wysocki /** 1236c961dfbSRafael J. Wysocki * suspend_enter - enter the desired system sleep state. 1246c961dfbSRafael J. Wysocki * @state: state to enter 1256c961dfbSRafael J. Wysocki * 1266c961dfbSRafael J. Wysocki * This function should be called after devices have been suspended. 1276c961dfbSRafael J. Wysocki */ 128a065c86eSAdrian Bunk static int suspend_enter(suspend_state_t state) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds int error = 0; 1311da177e4SLinus Torvalds 132a53c46dcSJohannes Berg arch_suspend_disable_irqs(); 133a53c46dcSJohannes Berg BUG_ON(!irqs_disabled()); 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds if ((error = device_power_down(PMSG_SUSPEND))) { 1361da177e4SLinus Torvalds printk(KERN_ERR "Some devices failed to power down\n"); 1371da177e4SLinus Torvalds goto Done; 1381da177e4SLinus Torvalds } 13926398a70SRafael J. Wysocki error = suspend_ops->enter(state); 1401da177e4SLinus Torvalds device_power_up(); 1411da177e4SLinus Torvalds Done: 142a53c46dcSJohannes Berg arch_suspend_enable_irqs(); 143a53c46dcSJohannes Berg BUG_ON(irqs_disabled()); 1441da177e4SLinus Torvalds return error; 1451da177e4SLinus Torvalds } 1461da177e4SLinus Torvalds 1476c961dfbSRafael J. Wysocki /** 1486c961dfbSRafael J. Wysocki * suspend_devices_and_enter - suspend devices and enter the desired system sleep 1496c961dfbSRafael J. Wysocki * state. 1506c961dfbSRafael J. Wysocki * @state: state to enter 1516c961dfbSRafael J. Wysocki */ 1526c961dfbSRafael J. Wysocki int suspend_devices_and_enter(suspend_state_t state) 1536c961dfbSRafael J. Wysocki { 1546c961dfbSRafael J. Wysocki int error; 1556c961dfbSRafael J. Wysocki 15626398a70SRafael J. Wysocki if (!suspend_ops) 1576c961dfbSRafael J. Wysocki return -ENOSYS; 1586c961dfbSRafael J. Wysocki 15926398a70SRafael J. Wysocki if (suspend_ops->set_target) { 16026398a70SRafael J. Wysocki error = suspend_ops->set_target(state); 1616c961dfbSRafael J. Wysocki if (error) 1626c961dfbSRafael J. Wysocki return error; 1636c961dfbSRafael J. Wysocki } 1646c961dfbSRafael J. Wysocki suspend_console(); 1656c961dfbSRafael J. Wysocki error = device_suspend(PMSG_SUSPEND); 1666c961dfbSRafael J. Wysocki if (error) { 1676c961dfbSRafael J. Wysocki printk(KERN_ERR "Some devices failed to suspend\n"); 1686c961dfbSRafael J. Wysocki goto Resume_console; 1696c961dfbSRafael J. Wysocki } 17026398a70SRafael J. Wysocki if (suspend_ops->prepare) { 171e6c5eb95SRafael J. Wysocki error = suspend_ops->prepare(); 1726c961dfbSRafael J. Wysocki if (error) 1736c961dfbSRafael J. Wysocki goto Resume_devices; 1746c961dfbSRafael J. Wysocki } 1756c961dfbSRafael J. Wysocki error = disable_nonboot_cpus(); 1766c961dfbSRafael J. Wysocki if (!error) 1776c961dfbSRafael J. Wysocki suspend_enter(state); 1786c961dfbSRafael J. Wysocki 1796c961dfbSRafael J. Wysocki enable_nonboot_cpus(); 180e6c5eb95SRafael J. Wysocki if (suspend_ops->finish) 181e6c5eb95SRafael J. Wysocki suspend_ops->finish(); 1826c961dfbSRafael J. Wysocki Resume_devices: 1836c961dfbSRafael J. Wysocki device_resume(); 1846c961dfbSRafael J. Wysocki Resume_console: 1856c961dfbSRafael J. Wysocki resume_console(); 1866c961dfbSRafael J. Wysocki return error; 1876c961dfbSRafael J. Wysocki } 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds /** 1901da177e4SLinus Torvalds * suspend_finish - Do final work before exiting suspend sequence. 1911da177e4SLinus Torvalds * 1921da177e4SLinus Torvalds * Call platform code to clean up, restart processes, and free the 1931da177e4SLinus Torvalds * console that we've allocated. This is not called for suspend-to-disk. 1941da177e4SLinus Torvalds */ 1956c961dfbSRafael J. Wysocki static void suspend_finish(void) 1961da177e4SLinus Torvalds { 1971da177e4SLinus Torvalds thaw_processes(); 1981da177e4SLinus Torvalds pm_restore_console(); 199b10d9117SRafael J. Wysocki pm_notifier_call_chain(PM_POST_SUSPEND); 2001da177e4SLinus Torvalds } 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds 2053b364b8dSAndreas Mohr static const char * const pm_states[PM_SUSPEND_MAX] = { 2061da177e4SLinus Torvalds [PM_SUSPEND_STANDBY] = "standby", 2071da177e4SLinus Torvalds [PM_SUSPEND_MEM] = "mem", 2081da177e4SLinus Torvalds }; 2091da177e4SLinus Torvalds 210123d3c13SPavel Machek static inline int valid_state(suspend_state_t state) 211123d3c13SPavel Machek { 212a3d25c27SRafael J. Wysocki /* All states need lowlevel support and need to be valid 213a3d25c27SRafael J. Wysocki * to the lowlevel implementation, no valid callback 2149684e51cSJohannes Berg * implies that none are valid. */ 21526398a70SRafael J. Wysocki if (!suspend_ops || !suspend_ops->valid || !suspend_ops->valid(state)) 216123d3c13SPavel Machek return 0; 217123d3c13SPavel Machek return 1; 218123d3c13SPavel Machek } 219123d3c13SPavel Machek 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds /** 2221da177e4SLinus Torvalds * enter_state - Do common work of entering low-power state. 2231da177e4SLinus Torvalds * @state: pm_state structure for state we're entering. 2241da177e4SLinus Torvalds * 2251da177e4SLinus Torvalds * Make sure we're the only ones trying to enter a sleep state. Fail 2261da177e4SLinus Torvalds * if someone has beat us to it, since we don't want anything weird to 2271da177e4SLinus Torvalds * happen when we wake up. 2281da177e4SLinus Torvalds * Then, do the setup for suspend, enter the state, and cleaup (after 2291da177e4SLinus Torvalds * we've woken up). 2301da177e4SLinus Torvalds */ 2311da177e4SLinus Torvalds static int enter_state(suspend_state_t state) 2321da177e4SLinus Torvalds { 2331da177e4SLinus Torvalds int error; 2341da177e4SLinus Torvalds 235123d3c13SPavel Machek if (!valid_state(state)) 236eb9289ebSShaohua Li return -ENODEV; 237232b1432SRafael J. Wysocki 238a6d70980SStephen Hemminger if (!mutex_trylock(&pm_mutex)) 2391da177e4SLinus Torvalds return -EBUSY; 2401da177e4SLinus Torvalds 241232b1432SRafael J. Wysocki printk("Syncing filesystems ... "); 242232b1432SRafael J. Wysocki sys_sync(); 243232b1432SRafael J. Wysocki printk("done.\n"); 244232b1432SRafael J. Wysocki 24582428b62SDavid Brownell pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); 2466c961dfbSRafael J. Wysocki if ((error = suspend_prepare())) 2471da177e4SLinus Torvalds goto Unlock; 2481da177e4SLinus Torvalds 24982428b62SDavid Brownell pr_debug("PM: Entering %s sleep\n", pm_states[state]); 2506c961dfbSRafael J. Wysocki error = suspend_devices_and_enter(state); 2511da177e4SLinus Torvalds 25282428b62SDavid Brownell pr_debug("PM: Finishing wakeup.\n"); 2536c961dfbSRafael J. Wysocki suspend_finish(); 2541da177e4SLinus Torvalds Unlock: 255a6d70980SStephen Hemminger mutex_unlock(&pm_mutex); 2561da177e4SLinus Torvalds return error; 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds /** 2611da177e4SLinus Torvalds * pm_suspend - Externally visible function for suspending system. 262a3d25c27SRafael J. Wysocki * @state: Enumerated value of state to enter. 2631da177e4SLinus Torvalds * 2641da177e4SLinus Torvalds * Determine whether or not value is within range, get state 2651da177e4SLinus Torvalds * structure, and enter (above). 2661da177e4SLinus Torvalds */ 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds int pm_suspend(suspend_state_t state) 2691da177e4SLinus Torvalds { 270e2a5b420SAlexey Starikovskiy if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX) 2711da177e4SLinus Torvalds return enter_state(state); 2721da177e4SLinus Torvalds return -EINVAL; 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds 2754cf30348SRalf Baechle EXPORT_SYMBOL(pm_suspend); 2761da177e4SLinus Torvalds 277296699deSRafael J. Wysocki #endif /* CONFIG_SUSPEND */ 278296699deSRafael J. Wysocki 279*039a5dcdSGreg Kroah-Hartman struct kset *power_kset; 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds /** 2821da177e4SLinus Torvalds * state - control system power state. 2831da177e4SLinus Torvalds * 2841da177e4SLinus Torvalds * show() returns what states are supported, which is hard-coded to 2851da177e4SLinus Torvalds * 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and 2861da177e4SLinus Torvalds * 'disk' (Suspend-to-Disk). 2871da177e4SLinus Torvalds * 2881da177e4SLinus Torvalds * store() accepts one of those strings, translates it into the 2891da177e4SLinus Torvalds * proper enumerated value, and initiates a suspend transition. 2901da177e4SLinus Torvalds */ 2911da177e4SLinus Torvalds 292823bccfcSGreg Kroah-Hartman static ssize_t state_show(struct kset *kset, char *buf) 2931da177e4SLinus Torvalds { 2941da177e4SLinus Torvalds char *s = buf; 295296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 296296699deSRafael J. Wysocki int i; 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds for (i = 0; i < PM_SUSPEND_MAX; i++) { 299123d3c13SPavel Machek if (pm_states[i] && valid_state(i)) 3001da177e4SLinus Torvalds s += sprintf(s,"%s ", pm_states[i]); 3011da177e4SLinus Torvalds } 302296699deSRafael J. Wysocki #endif 303b0cb1a19SRafael J. Wysocki #ifdef CONFIG_HIBERNATION 304a3d25c27SRafael J. Wysocki s += sprintf(s, "%s\n", "disk"); 305a3d25c27SRafael J. Wysocki #else 306a3d25c27SRafael J. Wysocki if (s != buf) 307a3d25c27SRafael J. Wysocki /* convert the last space to a newline */ 308a3d25c27SRafael J. Wysocki *(s-1) = '\n'; 309a3d25c27SRafael J. Wysocki #endif 3101da177e4SLinus Torvalds return (s - buf); 3111da177e4SLinus Torvalds } 3121da177e4SLinus Torvalds 313823bccfcSGreg Kroah-Hartman static ssize_t state_store(struct kset *kset, const char *buf, size_t n) 3141da177e4SLinus Torvalds { 315296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 3161da177e4SLinus Torvalds suspend_state_t state = PM_SUSPEND_STANDBY; 3173b364b8dSAndreas Mohr const char * const *s; 318296699deSRafael J. Wysocki #endif 3191da177e4SLinus Torvalds char *p; 3201da177e4SLinus Torvalds int len; 321296699deSRafael J. Wysocki int error = -EINVAL; 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds p = memchr(buf, '\n', n); 3241da177e4SLinus Torvalds len = p ? p - buf : n; 3251da177e4SLinus Torvalds 326a3d25c27SRafael J. Wysocki /* First, check if we are requested to hibernate */ 3278d98a690SRafael J. Wysocki if (len == 4 && !strncmp(buf, "disk", len)) { 328a3d25c27SRafael J. Wysocki error = hibernate(); 329296699deSRafael J. Wysocki goto Exit; 330a3d25c27SRafael J. Wysocki } 331a3d25c27SRafael J. Wysocki 332296699deSRafael J. Wysocki #ifdef CONFIG_SUSPEND 3331da177e4SLinus Torvalds for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) { 3348d98a690SRafael J. Wysocki if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) 3351da177e4SLinus Torvalds break; 3361da177e4SLinus Torvalds } 33747bb7899Sdean gaudet if (state < PM_SUSPEND_MAX && *s) 3381da177e4SLinus Torvalds error = enter_state(state); 339296699deSRafael J. Wysocki #endif 340296699deSRafael J. Wysocki 341296699deSRafael J. Wysocki Exit: 3421da177e4SLinus Torvalds return error ? error : n; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds power_attr(state); 3461da177e4SLinus Torvalds 347c5c6ba4eSRafael J. Wysocki #ifdef CONFIG_PM_TRACE 348c5c6ba4eSRafael J. Wysocki int pm_trace_enabled; 349c5c6ba4eSRafael J. Wysocki 350823bccfcSGreg Kroah-Hartman static ssize_t pm_trace_show(struct kset *kset, char *buf) 351c5c6ba4eSRafael J. Wysocki { 352c5c6ba4eSRafael J. Wysocki return sprintf(buf, "%d\n", pm_trace_enabled); 353c5c6ba4eSRafael J. Wysocki } 354c5c6ba4eSRafael J. Wysocki 355c5c6ba4eSRafael J. Wysocki static ssize_t 356823bccfcSGreg Kroah-Hartman pm_trace_store(struct kset *kset, const char *buf, size_t n) 357c5c6ba4eSRafael J. Wysocki { 358c5c6ba4eSRafael J. Wysocki int val; 359c5c6ba4eSRafael J. Wysocki 360c5c6ba4eSRafael J. Wysocki if (sscanf(buf, "%d", &val) == 1) { 361c5c6ba4eSRafael J. Wysocki pm_trace_enabled = !!val; 362c5c6ba4eSRafael J. Wysocki return n; 363c5c6ba4eSRafael J. Wysocki } 364c5c6ba4eSRafael J. Wysocki return -EINVAL; 365c5c6ba4eSRafael J. Wysocki } 366c5c6ba4eSRafael J. Wysocki 367c5c6ba4eSRafael J. Wysocki power_attr(pm_trace); 368c5c6ba4eSRafael J. Wysocki 369c5c6ba4eSRafael J. Wysocki static struct attribute * g[] = { 370c5c6ba4eSRafael J. Wysocki &state_attr.attr, 371c5c6ba4eSRafael J. Wysocki &pm_trace_attr.attr, 372c5c6ba4eSRafael J. Wysocki NULL, 373c5c6ba4eSRafael J. Wysocki }; 374c5c6ba4eSRafael J. Wysocki #else 3751da177e4SLinus Torvalds static struct attribute * g[] = { 3761da177e4SLinus Torvalds &state_attr.attr, 3771da177e4SLinus Torvalds NULL, 3781da177e4SLinus Torvalds }; 379c5c6ba4eSRafael J. Wysocki #endif /* CONFIG_PM_TRACE */ 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds static struct attribute_group attr_group = { 3821da177e4SLinus Torvalds .attrs = g, 3831da177e4SLinus Torvalds }; 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds static int __init pm_init(void) 3871da177e4SLinus Torvalds { 388*039a5dcdSGreg Kroah-Hartman power_kset = kset_create_and_add("power", NULL, NULL); 389*039a5dcdSGreg Kroah-Hartman if (!power_kset) 390*039a5dcdSGreg Kroah-Hartman return -ENOMEM; 391*039a5dcdSGreg Kroah-Hartman return sysfs_create_group(&power_kset->kobj, &attr_group); 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds core_initcall(pm_init); 395