diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2007-12-08 02:04:21 +0100 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-02-01 18:30:54 -0500 |
commit | 72df68ca8e006a0107933c4fb13c741a0a48163f (patch) | |
tree | c6d0d36bffc54989fffcebc8ec1368a47cfa6d65 /kernel/power/disk.c | |
parent | 2ed43b63285c394cb5e1829c199cc94c7b8233b9 (diff) |
Hibernation: Move low level resume to disk.c
Move the low level restore code to kernel/power/disk.c , since the
corresponding low level hibernation code is already there.
Make restore fail if device_power_down(PMSG_PRETHAW) returns an
error.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'kernel/power/disk.c')
-rw-r--r-- | kernel/power/disk.c | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 0866b163c6b..2a4bada184e 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -275,6 +275,53 @@ int hibernation_snapshot(int platform_mode) } /** + * resume_target_kernel - prepare devices that need to be suspended with + * interrupts off, restore the contents of highmem that have not been + * restored yet from the image and run the low level code that will restore + * the remaining contents of memory and switch to the just restored target + * kernel. + */ + +static int resume_target_kernel(void) +{ + int error; + + local_irq_disable(); + error = device_power_down(PMSG_PRETHAW); + if (error) { + printk(KERN_ERR "Some devices failed to power down, " + "aborting resume\n"); + goto Enable_irqs; + } + /* We'll ignore saved state, but this gets preempt count (etc) right */ + save_processor_state(); + error = restore_highmem(); + if (!error) { + error = swsusp_arch_resume(); + /* + * The code below is only ever reached in case of a failure. + * Otherwise execution continues at place where + * swsusp_arch_suspend() was called + */ + BUG_ON(!error); + /* This call to restore_highmem() undos the previous one */ + restore_highmem(); + } + /* + * The only reason why swsusp_arch_resume() can fail is memory being + * very tight, so we have to free it as soon as we can to avoid + * subsequent failures + */ + swsusp_free(); + restore_processor_state(); + touch_softlockup_watchdog(); + device_power_up(); + Enable_irqs: + local_irq_enable(); + return error; +} + +/** * hibernation_restore - quiesce devices and restore the hibernation * snapshot image. If successful, control returns in hibernation_snaphot() * @platform_mode - if set, use the platform driver, if available, to @@ -297,7 +344,7 @@ int hibernation_restore(int platform_mode) if (!error) { error = disable_nonboot_cpus(); if (!error) - error = swsusp_resume(); + error = resume_target_kernel(); enable_nonboot_cpus(); } platform_restore_cleanup(platform_mode); |