summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/suspend.h24
-rw-r--r--kernel/power/main.c28
-rw-r--r--kernel/power/power.h7
-rw-r--r--kernel/power/swsusp.c171
-rw-r--r--kernel/sys.c7
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