]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - kernel/power/disk.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial
[net-next-2.6.git] / kernel / power / disk.c
index 9d1c1a0de35048831e40bfd662eb12775e8046ec..5f21ab2bbcdf0cf5c85985f8612f923ad6ad3d03 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/console.h>
 #include <linux/cpu.h>
 #include <linux/freezer.h>
+#include <asm/suspend.h>
 
 #include "power.h"
 
@@ -214,7 +215,7 @@ static int create_image(int platform_mode)
                return error;
 
        device_pm_lock();
-       local_irq_disable();
+
        /* At this point, device_suspend() has been called, but *not*
         * device_power_down(). We *must* call device_power_down() now.
         * Otherwise, drivers for some devices (e.g. interrupt controllers)
@@ -225,13 +226,25 @@ static int create_image(int platform_mode)
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
                        "aborting hibernation\n");
-               goto Enable_irqs;
+               goto Unlock;
        }
+
+       error = platform_pre_snapshot(platform_mode);
+       if (error || hibernation_test(TEST_PLATFORM))
+               goto Platform_finish;
+
+       error = disable_nonboot_cpus();
+       if (error || hibernation_test(TEST_CPUS)
+           || hibernation_testmode(HIBERNATION_TEST))
+               goto Enable_cpus;
+
+       local_irq_disable();
+
        sysdev_suspend(PMSG_FREEZE);
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
                        "aborting hibernation\n");
-               goto Power_up_devices;
+               goto Enable_irqs;
        }
 
        if (hibernation_test(TEST_CORE))
@@ -247,17 +260,28 @@ static int create_image(int platform_mode)
        restore_processor_state();
        if (!in_suspend)
                platform_leave(platform_mode);
+
  Power_up:
        sysdev_resume();
        /* NOTE:  device_power_up() is just a resume() for devices
         * that suspended with irqs off ... no overall powerup.
         */
- Power_up_devices:
-       device_power_up(in_suspend ?
-               (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
+
  Enable_irqs:
        local_irq_enable();
+
+ Enable_cpus:
+       enable_nonboot_cpus();
+
+ Platform_finish:
+       platform_finish(platform_mode);
+
+       device_power_up(in_suspend ?
+               (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
+
+ Unlock:
        device_pm_unlock();
+
        return error;
 }
 
@@ -291,25 +315,9 @@ int hibernation_snapshot(int platform_mode)
        if (hibernation_test(TEST_DEVICES))
                goto Recover_platform;
 
-       error = platform_pre_snapshot(platform_mode);
-       if (error || hibernation_test(TEST_PLATFORM))
-               goto Finish;
-
-       error = disable_nonboot_cpus();
-       if (!error) {
-               if (hibernation_test(TEST_CPUS))
-                       goto Enable_cpus;
-
-               if (hibernation_testmode(HIBERNATION_TEST))
-                       goto Enable_cpus;
+       error = create_image(platform_mode);
+       /* Control returns here after successful restore */
 
-               error = create_image(platform_mode);
-               /* Control returns here after successful restore */
-       }
- Enable_cpus:
-       enable_nonboot_cpus();
- Finish:
-       platform_finish(platform_mode);
  Resume_devices:
        device_resume(in_suspend ?
                (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
@@ -331,19 +339,33 @@ int hibernation_snapshot(int platform_mode)
  *     kernel.
  */
 
-static int resume_target_kernel(void)
+static int resume_target_kernel(bool platform_mode)
 {
        int error;
 
        device_pm_lock();
-       local_irq_disable();
+
        error = device_power_down(PMSG_QUIESCE);
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
                        "aborting resume\n");
-               goto Enable_irqs;
+               goto Unlock;
        }
-       sysdev_suspend(PMSG_QUIESCE);
+
+       error = platform_pre_restore(platform_mode);
+       if (error)
+               goto Cleanup;
+
+       error = disable_nonboot_cpus();
+       if (error)
+               goto Enable_cpus;
+
+       local_irq_disable();
+
+       error = sysdev_suspend(PMSG_QUIESCE);
+       if (error)
+               goto Enable_irqs;
+
        /* We'll ignore saved state, but this gets preempt count (etc) right */
        save_processor_state();
        error = restore_highmem();
@@ -366,11 +388,23 @@ static int resume_target_kernel(void)
        swsusp_free();
        restore_processor_state();
        touch_softlockup_watchdog();
+
        sysdev_resume();
-       device_power_up(PMSG_RECOVER);
+
  Enable_irqs:
        local_irq_enable();
+
+ Enable_cpus:
+       enable_nonboot_cpus();
+
+ Cleanup:
+       platform_restore_cleanup(platform_mode);
+
+       device_power_up(PMSG_RECOVER);
+
+ Unlock:
        device_pm_unlock();
+
        return error;
 }
 
@@ -390,19 +424,10 @@ int hibernation_restore(int platform_mode)
        pm_prepare_console();
        suspend_console();
        error = device_suspend(PMSG_QUIESCE);
-       if (error)
-               goto Finish;
-
-       error = platform_pre_restore(platform_mode);
        if (!error) {
-               error = disable_nonboot_cpus();
-               if (!error)
-                       error = resume_target_kernel();
-               enable_nonboot_cpus();
+               error = resume_target_kernel(platform_mode);
+               device_resume(PMSG_RECOVER);
        }
-       platform_restore_cleanup(platform_mode);
-       device_resume(PMSG_RECOVER);
- Finish:
        resume_console();
        pm_restore_console();
        return error;
@@ -438,38 +463,46 @@ int hibernation_platform_enter(void)
                goto Resume_devices;
        }
 
+       device_pm_lock();
+
+       error = device_power_down(PMSG_HIBERNATE);
+       if (error)
+               goto Unlock;
+
        error = hibernation_ops->prepare();
        if (error)
-               goto Resume_devices;
+               goto Platofrm_finish;
 
        error = disable_nonboot_cpus();
        if (error)
-               goto Finish;
+               goto Platofrm_finish;
 
-       device_pm_lock();
        local_irq_disable();
-       error = device_power_down(PMSG_HIBERNATE);
-       if (!error) {
-               sysdev_suspend(PMSG_HIBERNATE);
-               hibernation_ops->enter();
-               /* We should never get here */
-               while (1);
-       }
-       local_irq_enable();
-       device_pm_unlock();
+       sysdev_suspend(PMSG_HIBERNATE);
+       hibernation_ops->enter();
+       /* We should never get here */
+       while (1);
 
        /*
         * We don't need to reenable the nonboot CPUs or resume consoles, since
         * the system is going to be halted anyway.
         */
Finish:
Platofrm_finish:
        hibernation_ops->finish();
+
+       device_power_up(PMSG_RESTORE);
+
+ Unlock:
+       device_pm_unlock();
+
  Resume_devices:
        entering_platform_hibernation = false;
        device_resume(PMSG_RESTORE);
        resume_console();
+
  Close:
        hibernation_ops->end();
+
        return error;
 }