Commit e2676af6 authored by Patrick Mochel's avatar Patrick Mochel

[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. 
parent 29221b81
...@@ -41,7 +41,6 @@ static inline int software_suspend(void) ...@@ -41,7 +41,6 @@ static inline int software_suspend(void)
printk("Warning: fake suspend called\n"); printk("Warning: fake suspend called\n");
return -EPERM; return -EPERM;
} }
#define software_resume() do { } while(0)
#endif /* CONFIG_SOFTWARE_SUSPEND */ #endif /* CONFIG_SOFTWARE_SUSPEND */
......
...@@ -30,6 +30,9 @@ extern int swsusp_resume(void); ...@@ -30,6 +30,9 @@ extern int swsusp_resume(void);
extern int swsusp_free(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. * power_down - Shut machine down for hibernate.
* @mode: Suspend-to-disk mode * @mode: Suspend-to-disk mode
...@@ -99,6 +102,7 @@ static void finish(void) ...@@ -99,6 +102,7 @@ static void finish(void)
{ {
device_resume(); device_resume();
platform_finish(); platform_finish();
enable_nonboot_cpus();
thaw_processes(); thaw_processes();
pm_restore_console(); pm_restore_console();
} }
...@@ -126,6 +130,7 @@ static int prepare(void) ...@@ -126,6 +130,7 @@ static int prepare(void)
/* Free memory before shutting down devices. */ /* Free memory before shutting down devices. */
free_some_memory(); free_some_memory();
disable_nonboot_cpus();
if ((error = device_suspend(PM_SUSPEND_DISK))) if ((error = device_suspend(PM_SUSPEND_DISK)))
goto Finish; goto Finish;
...@@ -133,6 +138,7 @@ static int prepare(void) ...@@ -133,6 +138,7 @@ static int prepare(void)
Finish: Finish:
platform_finish(); platform_finish();
Thaw: Thaw:
enable_nonboot_cpus();
thaw_processes(); thaw_processes();
pm_restore_console(); pm_restore_console();
return error; return error;
...@@ -188,7 +194,7 @@ int pm_suspend_disk(void) ...@@ -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 * 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. * initialized), we call pmdisk to see if we have a saved image or not.
...@@ -199,10 +205,18 @@ int pm_suspend_disk(void) ...@@ -199,10 +205,18 @@ int pm_suspend_disk(void)
* *
*/ */
static int pm_resume(void) static int software_resume(void)
{ {
int error; 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"); pr_debug("PM: Reading pmdisk image.\n");
if ((error = swsusp_read())) if ((error = swsusp_read()))
...@@ -216,16 +230,6 @@ static int pm_resume(void) ...@@ -216,16 +230,6 @@ static int pm_resume(void)
barrier(); barrier();
mb(); 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"); pr_debug("PM: Restoring saved image.\n");
swsusp_resume(); swsusp_resume();
pr_debug("PM: Restore failed, recovering.n"); pr_debug("PM: Restore failed, recovering.n");
...@@ -237,7 +241,7 @@ static int pm_resume(void) ...@@ -237,7 +241,7 @@ static int pm_resume(void)
return 0; return 0;
} }
late_initcall(pm_resume); late_initcall(software_resume);
static char * pm_disk_modes[] = { static char * pm_disk_modes[] = {
...@@ -336,3 +340,22 @@ static int __init pm_disk_init(void) ...@@ -336,3 +340,22 @@ static int __init pm_disk_init(void)
} }
core_initcall(pm_disk_init); 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);
...@@ -169,6 +169,21 @@ static int enter_state(u32 state) ...@@ -169,6 +169,21 @@ static int enter_state(u32 state)
return error; 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. * pm_suspend - Externally visible function for suspending system.
......
...@@ -71,11 +71,6 @@ ...@@ -71,11 +71,6 @@
#include "power.h" #include "power.h"
unsigned char software_suspend_enabled = 0;
#define NORESUME 1
#define RESUME_SPECIFIED 2
/* References to section boundaries */ /* References to section boundaries */
extern char __nosave_begin, __nosave_end; extern char __nosave_begin, __nosave_end;
...@@ -85,8 +80,7 @@ extern int is_head_of_free_region(struct page *); ...@@ -85,8 +80,7 @@ extern int is_head_of_free_region(struct page *);
int pagedir_order_check; int pagedir_order_check;
int nr_copy_pages_check; int nr_copy_pages_check;
static int resume_status; extern char resume_file[];
static char resume_file[256] = CONFIG_PM_STD_PARTITION;
static dev_t resume_device; static dev_t resume_device;
/* Local variables that should not be affected by save */ /* Local variables that should not be affected by save */
unsigned int nr_copy_pages __nosavedata = 0; unsigned int nr_copy_pages __nosavedata = 0;
...@@ -664,30 +658,6 @@ void swsusp_free(void) ...@@ -664,30 +658,6 @@ void swsusp_free(void)
free_pages(p, pagedir_order); 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) static void calc_order(void)
{ {
...@@ -878,48 +848,6 @@ int swsusp_write(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_suspend(void);
extern asmlinkage int swsusp_arch_resume(void); extern asmlinkage int swsusp_arch_resume(void);
...@@ -971,59 +899,6 @@ int swsusp_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 */ /* More restore stuff */
#define does_collide(addr) does_collide_order(pagedir_nosave, addr, 0) #define does_collide(addr) does_collide_order(pagedir_nosave, addr, 0)
...@@ -1370,76 +1245,3 @@ int __init swsusp_read(void) ...@@ -1370,76 +1245,3 @@ int __init swsusp_read(void)
pr_debug("pmdisk: Error %d resuming\n", error); pr_debug("pmdisk: Error %d resuming\n", error);
return 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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment