diff options
| -rw-r--r-- | include/linux/suspend.h | 24 | ||||
| -rw-r--r-- | kernel/power/main.c | 28 | ||||
| -rw-r--r-- | kernel/power/power.h | 7 | ||||
| -rw-r--r-- | kernel/power/swsusp.c | 171 | ||||
| -rw-r--r-- | kernel/sys.c | 7 |
5 files changed, 59 insertions, 178 deletions
diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 28788d8a65ff..da171766c8c8 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -8,8 +8,7 @@ #include <linux/notifier.h> #include <linux/config.h> #include <linux/init.h> - -extern unsigned char software_suspend_enabled; +#include <linux/pm.h> #ifdef CONFIG_SOFTWARE_SUSPEND /* page backup entry */ @@ -46,12 +45,6 @@ extern int shrink_mem(void); /* mm/page_alloc.c */ extern void drain_local_pages(void); -/* kernel/suspend.c */ -extern int software_suspend(void); - -extern int register_suspend_notifier(struct notifier_block *); -extern int unregister_suspend_notifier(struct notifier_block *); - extern unsigned int nr_copy_pages __nosavedata; extern suspend_pagedir_t *pagedir_nosave __nosavedata; @@ -72,32 +65,17 @@ static inline int software_suspend(void) { return -EPERM; } -#define register_suspend_notifier(a) do { } while(0) -#define unregister_suspend_notifier(a) do { } while(0) #endif /* CONFIG_SOFTWARE_SUSPEND */ #ifdef CONFIG_PM extern void refrigerator(unsigned long); -extern int freeze_processes(void); -extern void thaw_processes(void); - -extern int pm_prepare_console(void); -extern void pm_restore_console(void); #else static inline void refrigerator(unsigned long flag) { } -static inline int freeze_processes(void) -{ - return 0; -} -static inline void thaw_processes(void) -{ - -} #endif /* CONFIG_PM */ #endif /* _LINUX_SWSUSP_H */ diff --git a/kernel/power/main.c b/kernel/power/main.c index 063e98c6bceb..42bf7233a3a7 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -15,6 +15,8 @@ #include <linux/errno.h> #include <linux/init.h> #include <linux/pm.h> +#include <linux/fs.h> + #include "power.h" @@ -30,6 +32,8 @@ static int have_swsusp = 1; static int have_swsusp = 0; #endif +extern long sys_sync(void); + /** * pm_set_ops - Set the global power method table. @@ -129,6 +133,25 @@ static int in_suspend __nosavedata = 0; /** + * free_some_memory - Try to free as much memory as possible + * + * ... but do not OOM-kill anyone + * + * Notice: all userland should be stopped at this point, or + * livelock is possible. + */ + +static void free_some_memory(void) +{ + printk("Freeing memory: "); + while (shrink_all_memory(10000)) + printk("."); + printk("|\n"); + blk_run_queues(); +} + + +/** * pm_suspend_disk - The granpappy of power management. * * If we're going through the firmware, then get it over with quickly. @@ -197,6 +220,7 @@ static int suspend_prepare(u32 state) pm_prepare_console(); + sys_sync(); if (freeze_processes()) { error = -EAGAIN; goto Thaw; @@ -207,6 +231,10 @@ static int suspend_prepare(u32 state) goto Thaw; } + /* Free memory before shutting down devices. */ + if (state == PM_SUSPEND_DISK) + free_some_memory(); + if ((error = device_pm_suspend(state))) goto Finish; diff --git a/kernel/power/power.h b/kernel/power/power.h index ae7bcbc37845..e98de640155d 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -37,3 +37,10 @@ static inline int swsusp_free(void) return 0; } #endif + + +extern int freeze_processes(void); +extern void thaw_processes(void); + +extern int pm_prepare_console(void); +extern void pm_restore_console(void); diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index d1b2a46de5fa..5c70937437d4 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -65,8 +65,6 @@ #include "power.h" -extern long sys_sync(void); - unsigned char software_suspend_enabled = 1; #define __ADDRESS(x) ((unsigned long) phys_to_virt(x)) @@ -439,29 +437,6 @@ static suspend_pagedir_t *create_suspend_pagedir(int nr_copy_pages) return pagedir; } -static int prepare_suspend_processes(void) -{ - sys_sync(); /* Syncing needs pdflushd, so do it before stopping processes */ - if (freeze_processes()) { - printk( KERN_ERR "Suspend failed: Not all processes stopped!\n" ); - thaw_processes(); - return 1; - } - return 0; -} - -/* - * Try to free as much memory as possible, but do not OOM-kill anyone - * - * Notice: all userland should be stopped at this point, or livelock is possible. - */ -static void free_some_memory(void) -{ - printk("Freeing memory: "); - while (shrink_all_memory(10000)) - printk("."); - printk("|\n"); -} /* Make disk drivers accept operations, again */ static void drivers_unsuspend(void) @@ -470,28 +445,6 @@ static void drivers_unsuspend(void) device_resume(RESUME_ENABLE); } -/* Called from process context */ -static int drivers_suspend(void) -{ - if (device_suspend(4, SUSPEND_NOTIFY)) - return -EIO; - if (device_suspend(4, SUSPEND_SAVE_STATE)) { - device_resume(RESUME_RESTORE_STATE); - return -EIO; - } - if (!pm_suspend_state) { - if(pm_send_all(PM_SUSPEND,(void *)3)) { - printk(KERN_WARNING "Problem while sending suspend event\n"); - return -EIO; - } - pm_suspend_state=1; - } else - printk(KERN_WARNING "PM suspend state already raised\n"); - device_suspend(4, SUSPEND_DISABLE); - - return 0; -} - #define RESUME_PHASE1 1 /* Called from interrupts disabled */ #define RESUME_PHASE2 2 /* Called with interrupts enabled */ #define RESUME_ALL_PHASES (RESUME_PHASE1 | RESUME_PHASE2) @@ -694,72 +647,6 @@ void do_magic_suspend_2(void) mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME); } -static int do_software_suspend(void) -{ - arch_prepare_suspend(); - if (pm_prepare_console()) - printk( "%sCan't allocate a console... proceeding\n", name_suspend); - if (!prepare_suspend_processes()) { - - /* At this point, all user processes and "dangerous" - kernel threads are stopped. Free some memory, as we - need half of memory free. */ - - free_some_memory(); - - /* No need to invalidate any vfsmnt list -- - * they will be valid after resume, anyway. - */ - blk_run_queues(); - - /* Save state of all device drivers, and stop them. */ - if (drivers_suspend()==0) - /* If stopping device drivers worked, we proceed basically into - * suspend_save_image. - * - * do_magic(0) returns after system is resumed. - * - * do_magic() copies all "used" memory to "free" memory, then - * unsuspends all device drivers, and writes memory to disk - * using normal kernel mechanism. - */ - do_magic(0); - thaw_processes(); - } - software_suspend_enabled = 1; - MDELAY(1000); - pm_restore_console(); - return 0; -} - - -/** - * software_suspend - initiate suspend-to-swap transition. - * - * This is main interface to the outside world. It needs to be - * called from process context. - */ - -int software_suspend(void) -{ - if(!software_suspend_enabled) - return -EINVAL; - - if (num_online_cpus() > 1) { - printk(KERN_WARNING "swsusp does not support SMP.\n"); - return -EPERM; - } - -#if defined (CONFIG_HIGHMEM) || defined (COFNIG_DISCONTIGMEM) - printk("swsusp is not supported with high- or discontig-mem.\n"); - return -EPERM; -#endif - - software_suspend_enabled = 0; - might_sleep(); - return do_software_suspend(); -} - /* More restore stuff */ /* FIXME: Why not memcpy(to, from, 1<<pagedir_order*PAGE_SIZE)? */ @@ -1031,54 +918,34 @@ static int read_suspend_image(const char * specialfile) } /** - * software_resume - Check and load saved image from swap. - * - * Defined as a late_initcall, so it gets called after all devices - * have been probed and initialized, but before we've mounted anything. - */ - -static int software_resume(void) -{ - if (!strlen(resume_file)) - return 0; - - if (pm_prepare_console()) - printk("swsusp: Can't allocate a console... proceeding\n"); - - printk("swsusp: %s\n", name_resume ); - - MDELAY(1000); - - printk("swsusp: resuming from %s\n", resume_file); - if (read_suspend_image(resume_file)) - goto read_failure; - do_magic(1); - printk("swsusp: Resume failed. Continuing.\n"); - -read_failure: - pm_restore_console(); - return -EFAULT; -} - -late_initcall(software_resume); - - -/** * swsusp_save - Snapshot memory */ int swsusp_save(void) { +#if defined (CONFIG_HIGHMEM) || defined (COFNIG_DISCONTIGMEM) + printk("swsusp is not supported with high- or discontig-mem.\n"); return -EPERM; +#endif + return 0; } /** * swsusp_write - Write saved memory image to swap. + * + * do_magic(0) returns after system is resumed. + * + * do_magic() copies all "used" memory to "free" memory, then + * unsuspends all device drivers, and writes memory to disk + * using normal kernel mechanism. */ int swsusp_write(void) { + arch_prepare_suspend(); + do_magic(0); + MDELAY(1000); return 0; } @@ -1089,7 +956,11 @@ int swsusp_write(void) int swsusp_read(void) { - return -ENOENT; + if (!strlen(resume_file)) + return -ENOENT; + printk("swsusp: %s\n", name_resume ); + MDELAY(1000); + return read_suspend_image(resume_file); } @@ -1099,6 +970,7 @@ int swsusp_read(void) int swsusp_restore(void) { + do_magic(1); return 0; } @@ -1114,7 +986,8 @@ int swsusp_free(void) static int __init resume_setup(char *str) { - strncpy( resume_file, str, 255 ); + if (strlen(str)) + strncpy(resume_file, str, 255); return 1; } @@ -1127,5 +1000,3 @@ static int __init noresume_setup(char *str) __setup("noresume", noresume_setup); __setup("resume=", resume_setup); -EXPORT_SYMBOL(software_suspend); -EXPORT_SYMBOL(software_suspend_enabled); diff --git a/kernel/sys.c b/kernel/sys.c index 3497a1565a61..27c19703a1ea 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -456,11 +456,8 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user #ifdef CONFIG_SOFTWARE_SUSPEND case LINUX_REBOOT_CMD_SW_SUSPEND: - if (!software_suspend_enabled) { - unlock_kernel(); - return -EAGAIN; - } - software_suspend(); + if (!pm_suspend(PM_SUSPEND_DISK)) + break; do_exit(0); break; #endif |
