From 72df68ca8e006a0107933c4fb13c741a0a48163f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 8 Dec 2007 02:04:21 +0100 Subject: 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 Acked-by: Pavel Machek Signed-off-by: Len Brown --- kernel/power/disk.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'kernel/power/disk.c') diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 0866b163c6bb..2a4bada184ed 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -274,6 +274,53 @@ int hibernation_snapshot(int platform_mode) return error; } +/** + * 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() @@ -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); -- cgit v1.2.2