]> err.no Git - linux-2.6/blobdiff - kernel/power/disk.c
PM: ACPI and APM must not be enabled at the same time
[linux-2.6] / kernel / power / disk.c
index e50f4da18fd56ed64f8012039e224784f209a2cf..05b64790fe8391ed5189eee02144e5cf63f3fa2b 100644 (file)
@@ -278,21 +278,50 @@ int hibernation_platform_enter(void)
 {
        int error;
 
-       if (hibernation_ops) {
-               kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
-               /*
-                * We have cancelled the power transition by running
-                * hibernation_ops->finish() before saving the image, so we
-                * should let the firmware know that we're going to enter the
-                * sleep state after all
-                */
-               error = hibernation_ops->prepare();
-               sysdev_shutdown();
-               if (!error)
-                       error = hibernation_ops->enter();
-       } else {
-               error = -ENOSYS;
+       if (!hibernation_ops)
+               return -ENOSYS;
+
+       /*
+        * We have cancelled the power transition by running
+        * hibernation_ops->finish() before saving the image, so we should let
+        * the firmware know that we're going to enter the sleep state after all
+        */
+       error = hibernation_ops->start();
+       if (error)
+               return error;
+
+       suspend_console();
+       error = device_suspend(PMSG_SUSPEND);
+       if (error)
+               goto Resume_console;
+
+       error = hibernation_ops->prepare();
+       if (error)
+               goto Resume_devices;
+
+       error = disable_nonboot_cpus();
+       if (error)
+               goto Finish;
+
+       local_irq_disable();
+       error = device_power_down(PMSG_SUSPEND);
+       if (!error) {
+               hibernation_ops->enter();
+               /* We should never get here */
+               while (1);
        }
+       local_irq_enable();
+
+       /*
+        * We don't need to reenable the nonboot CPUs or resume consoles, since
+        * the system is going to be halted anyway.
+        */
+ Finish:
+       hibernation_ops->finish();
+ Resume_devices:
+       device_resume();
+ Resume_console:
+       resume_console();
        return error;
 }
 
@@ -309,14 +338,14 @@ static void power_down(void)
        case HIBERNATION_TEST:
        case HIBERNATION_TESTPROC:
                break;
-       case HIBERNATION_SHUTDOWN:
-               kernel_power_off();
-               break;
        case HIBERNATION_REBOOT:
                kernel_restart(NULL);
                break;
        case HIBERNATION_PLATFORM:
                hibernation_platform_enter();
+       case HIBERNATION_SHUTDOWN:
+               kernel_power_off();
+               break;
        }
        kernel_halt();
        /*
@@ -427,7 +456,17 @@ static int software_resume(void)
        int error;
        unsigned int flags;
 
-       mutex_lock(&pm_mutex);
+       /*
+        * name_to_dev_t() below takes a sysfs buffer mutex when sysfs
+        * is configured into the kernel. Since the regular hibernate
+        * trigger path is via sysfs which takes a buffer mutex before
+        * calling hibernate functions (which take pm_mutex) this can
+        * cause lockdep to complain about a possible ABBA deadlock
+        * which cannot happen since we're in the boot code here and
+        * sysfs can't be invoked yet. Therefore, we use a subclass
+        * here to avoid lockdep complaining.
+        */
+       mutex_lock_nested(&pm_mutex, SINGLE_DEPTH_NESTING);
        if (!swsusp_resume_device) {
                if (!strlen(resume_file)) {
                        mutex_unlock(&pm_mutex);