diff options
| author | Patrick Mochel <mochel@digitalimplant.org> | 2004-07-17 00:09:36 -0700 |
|---|---|---|
| committer | Patrick Mochel <mochel@digitalimplant.org> | 2004-07-17 00:09:36 -0700 |
| commit | e2676af65065dbf62e1a8e59016ed8536d0fee4a (patch) | |
| tree | 99cb5224b77462233c54147714c66332977f8483 /kernel/power | |
| parent | 29221b810c59c94da43493103377068da6328263 (diff) | |
[Power Mgmt] Merge swsusp entry points with the PM core.
- Add {enable,disable}_nonboot_cpus() to prepare() and finish() in
kernel/power/disk.c
- Move swsusp __setup options there. Remove resume_status variable in favor
of simpler 'noresume' variable, and check it in pm_resume().
- Remove software_resume() from swsusp; rename pm_resume() to software_resume().
The latter is considerably cleaner, and leverages the core code.
- Move software_suspend() to kernel/power/main.c and shrink it down a
wrapper that takes pm_sem and calls pm_suspend_disk(), which does the
same as the old software_suspend() did.
This keeps the same entry points (via ACPI sleep and the reboot() syscall),
but actually allows those to use the low-level power states of the system
rather than always shutting off the system.
- Remove now-unused functions from swsusp.
Diffstat (limited to 'kernel/power')
| -rw-r--r-- | kernel/power/disk.c | 49 | ||||
| -rw-r--r-- | kernel/power/main.c | 15 | ||||
| -rw-r--r-- | kernel/power/swsusp.c | 200 |
3 files changed, 52 insertions, 212 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 6d4119cf40cc..ab49261f078f 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -30,6 +30,9 @@ extern int swsusp_resume(void); extern int swsusp_free(void); +static int noresume = 0; +char resume_file[256] = CONFIG_PM_STD_PARTITION; + /** * power_down - Shut machine down for hibernate. * @mode: Suspend-to-disk mode @@ -99,6 +102,7 @@ static void finish(void) { device_resume(); platform_finish(); + enable_nonboot_cpus(); thaw_processes(); pm_restore_console(); } @@ -126,6 +130,7 @@ static int prepare(void) /* Free memory before shutting down devices. */ free_some_memory(); + disable_nonboot_cpus(); if ((error = device_suspend(PM_SUSPEND_DISK))) goto Finish; @@ -133,6 +138,7 @@ static int prepare(void) Finish: platform_finish(); Thaw: + enable_nonboot_cpus(); thaw_processes(); pm_restore_console(); return error; @@ -188,7 +194,7 @@ int pm_suspend_disk(void) /** - * pm_resume - Resume from a saved image. + * software_resume - Resume from a saved image. * * Called as a late_initcall (so all devices are discovered and * initialized), we call pmdisk to see if we have a saved image or not. @@ -199,10 +205,18 @@ int pm_suspend_disk(void) * */ -static int pm_resume(void) +static int software_resume(void) { int error; + if (noresume) { + /** + * FIXME: If noresume is specified, we need to find the partition + * and reset it back to normal swap space. + */ + return 0; + } + pr_debug("PM: Reading pmdisk image.\n"); if ((error = swsusp_read())) @@ -216,16 +230,6 @@ static int pm_resume(void) barrier(); mb(); - /* FIXME: The following (comment and mdelay()) are from swsusp. - * Are they really necessary? - * - * We do not want some readahead with DMA to corrupt our memory, right? - * Do it with disabled interrupts for best effect. That way, if some - * driver scheduled DMA, we have good chance for DMA to finish ;-). - */ - pr_debug("PM: Waiting for DMAs to settle down.\n"); - mdelay(1000); - pr_debug("PM: Restoring saved image.\n"); swsusp_resume(); pr_debug("PM: Restore failed, recovering.n"); @@ -237,7 +241,7 @@ static int pm_resume(void) return 0; } -late_initcall(pm_resume); +late_initcall(software_resume); static char * pm_disk_modes[] = { @@ -336,3 +340,22 @@ static int __init pm_disk_init(void) } core_initcall(pm_disk_init); + + +static int __init resume_setup(char *str) +{ + if (noresume) + return 1; + + strncpy( resume_file, str, 255 ); + return 1; +} + +static int __init noresume_setup(char *str) +{ + noresume = 1; + return 1; +} + +__setup("noresume", noresume_setup); +__setup("resume=", resume_setup); diff --git a/kernel/power/main.c b/kernel/power/main.c index d582906fecc6..3e37ade640f6 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -169,6 +169,21 @@ static int enter_state(u32 state) return error; } +/* + * This is main interface to the outside world. It needs to be + * called from process context. + */ +int software_suspend(void) +{ + int error; + + if (down_trylock(&pm_sem)) + return -EBUSY; + error = pm_suspend_disk(); + up(&pm_sem); + return error; +} + /** * pm_suspend - Externally visible function for suspending system. diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 74805928f5d8..e478c7e37bc6 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -71,11 +71,6 @@ #include "power.h" -unsigned char software_suspend_enabled = 0; - -#define NORESUME 1 -#define RESUME_SPECIFIED 2 - /* References to section boundaries */ extern char __nosave_begin, __nosave_end; @@ -85,8 +80,7 @@ extern int is_head_of_free_region(struct page *); int pagedir_order_check; int nr_copy_pages_check; -static int resume_status; -static char resume_file[256] = CONFIG_PM_STD_PARTITION; +extern char resume_file[]; static dev_t resume_device; /* Local variables that should not be affected by save */ unsigned int nr_copy_pages __nosavedata = 0; @@ -664,30 +658,6 @@ void swsusp_free(void) free_pages(p, pagedir_order); } -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"); -} - static void calc_order(void) { @@ -878,48 +848,6 @@ int swsusp_write(void) } -static void suspend_power_down(void) -{ - extern int C_A_D; - C_A_D = 0; - printk(KERN_EMERG "%s%s Trying to power down.\n", name_suspend, TEST_SWSUSP ? "Disable TEST_SWSUSP. NOT ": ""); -#ifdef CONFIG_VT - PRINTK(KERN_EMERG "shift_state: %04x\n", shift_state); - mdelay(1000); - if (TEST_SWSUSP ^ (!!(shift_state & (1 << KG_CTRL)))) - machine_restart(NULL); - else -#endif - { - device_suspend(3); - device_shutdown(); - machine_power_off(); - } - - printk(KERN_EMERG "%sProbably not capable for powerdown. System halted.\n", name_suspend); - machine_halt(); - while (1); - /* NOTREACHED */ -} - - -static void suspend_finish(void) -{ - free_pages((unsigned long) pagedir_nosave, pagedir_order); - -#ifdef CONFIG_HIGHMEM - printk( "Restoring highmem\n" ); - restore_highmem(); -#endif - device_resume(); - -#ifdef SUSPEND_CONSOLE - acquire_console_sem(); - update_screen(fg_console); - release_console_sem(); -#endif -} - extern asmlinkage int swsusp_arch_suspend(void); extern asmlinkage int swsusp_arch_resume(void); @@ -971,59 +899,6 @@ int swsusp_resume(void) -static int in_suspend __nosavedata = 0; - -/* - * This is main interface to the outside world. It needs to be - * called from process context. - */ -int software_suspend(void) -{ - int res; - if (!software_suspend_enabled) - return -EAGAIN; - - software_suspend_enabled = 0; - might_sleep(); - - if (arch_prepare_suspend()) { - printk("%sArchitecture failed to prepare\n", name_suspend); - return -EPERM; - } - 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(); - disable_nonboot_cpus(); - /* Save state of all device drivers, and stop them. */ - printk("Suspending devices... "); - if ((res = device_suspend(3))==0) { - in_suspend = 1; - - res = swsusp_save(); - - if (!res && in_suspend) { - swsusp_write(); - suspend_power_down(); - } - in_suspend = 0; - suspend_finish(); - } - thaw_processes(); - enable_nonboot_cpus(); - } else - res = -EBUSY; - software_suspend_enabled = 1; - MDELAY(1000); - pm_restore_console(); - return res; -} - /* More restore stuff */ #define does_collide(addr) does_collide_order(pagedir_nosave, addr, 0) @@ -1370,76 +1245,3 @@ int __init swsusp_read(void) pr_debug("pmdisk: Error %d resuming\n", error); return error; } - -/** - * software_resume - Resume from a saved image. - * - * Called as a late_initcall (so all devices are discovered and - * initialized), we call swsusp to see if we have a saved image or not. - * If so, we quiesce devices, then restore the saved image. We will - * return above (in pm_suspend_disk() ) if everything goes well. - * Otherwise, we fail gracefully and return to the normally - * scheduled program. - * - */ -static int __init software_resume(void) -{ - if (num_online_cpus() > 1) { - printk(KERN_WARNING "Software Suspend has malfunctioning SMP support. Disabled :(\n"); - return -EINVAL; - } - /* We enable the possibility of machine suspend */ - software_suspend_enabled = 1; - if (!resume_status) - return 0; - - printk( "%s", name_resume ); - if (resume_status == NORESUME) { - /* - * FIXME: If noresume is specified, we need to handle by finding - * the right partition and resettting the signature. - */ - return 0; - } - MDELAY(1000); - - if (pm_prepare_console()) - printk("swsusp: Can't allocate a console... proceeding\n"); - - if (swsusp_read()) - goto read_failure; - /* FIXME: Should we stop processes here, just to be safer? */ - disable_nonboot_cpus(); - device_suspend(3); - swsusp_resume(); - panic("This never returns"); - -read_failure: - pm_restore_console(); - return 0; -} - -late_initcall(software_resume); - -static int __init resume_setup(char *str) -{ - if (resume_status == NORESUME) - return 1; - - strncpy( resume_file, str, 255 ); - resume_status = RESUME_SPECIFIED; - - return 1; -} - -static int __init noresume_setup(char *str) -{ - resume_status = NORESUME; - return 1; -} - -__setup("noresume", noresume_setup); -__setup("resume=", resume_setup); - -EXPORT_SYMBOL(software_suspend); -EXPORT_SYMBOL(software_suspend_enabled); |
