From f2a93dbd71db549d43e7bf9283918a83a5f5071d Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 19 Aug 2003 07:53:13 -0700 Subject: [PATCH] [power] Adapt swsusp to new PM core. Clean up heavily. - Split suspend/resume code into the four functions called from the PM core. - Remove now-duplicated code. - Make sure PM core frees memory and sync's disks before we shut down devices. - Remove software_suspend(), in favor of pm_suspend(). - Remove unused definitions from suspend.h --- include/linux/suspend.h | 24 +----- kernel/power/main.c | 28 +++++++ kernel/power/power.h | 7 ++ kernel/power/swsusp.c | 171 +++++----------------------------------- kernel/sys.c | 7 +- 5 files changed, 59 insertions(+), 178 deletions(-) diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 28788d8a65ff0..da171766c8c81 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -8,8 +8,7 @@ #include #include #include - -extern unsigned char software_suspend_enabled; +#include #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,31 +65,16 @@ 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 */ diff --git a/kernel/power/main.c b/kernel/power/main.c index 063e98c6bceb2..42bf7233a3a7a 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -15,6 +15,8 @@ #include #include #include +#include + #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. @@ -128,6 +132,25 @@ static int power_down(u32 mode) 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. * @@ -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 ae7bcbc378459..e98de640155d9 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 d1b2a46de5fa0..5c70937437d4d 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<