Merge branch 'suspend' into release
[sfrench/cifs-2.6.git] / drivers / acpi / main.c
index d8242772de9285767354cac0f568705176761fa1..7e3c609cbef27194c13dbacc7c036956e0217b73 100644 (file)
@@ -101,6 +101,19 @@ void __init acpi_old_suspend_ordering(void)
  * cases.
  */
 static bool set_sci_en_on_resume;
+/*
+ * The ACPI specification wants us to save NVS memory regions during hibernation
+ * and to restore them during the subsequent resume.  However, it is not certain
+ * if this mechanism is going to work on all machines, so we allow the user to
+ * disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line
+ * option.
+ */
+static bool s4_no_nvs;
+
+void __init acpi_s4_no_nvs(void)
+{
+       s4_no_nvs = true;
+}
 
 /**
  *     acpi_pm_disable_gpes - Disable the GPEs.
@@ -394,9 +407,25 @@ void __init acpi_no_s4_hw_signature(void)
 
 static int acpi_hibernation_begin(void)
 {
-       acpi_target_sleep_state = ACPI_STATE_S4;
-       acpi_sleep_tts_switch(acpi_target_sleep_state);
-       return 0;
+       int error;
+
+       error = s4_no_nvs ? 0 : hibernate_nvs_alloc();
+       if (!error) {
+               acpi_target_sleep_state = ACPI_STATE_S4;
+               acpi_sleep_tts_switch(acpi_target_sleep_state);
+       }
+
+       return error;
+}
+
+static int acpi_hibernation_pre_snapshot(void)
+{
+       int error = acpi_pm_prepare();
+
+       if (!error)
+               hibernate_nvs_save();
+
+       return error;
 }
 
 static int acpi_hibernation_enter(void)
@@ -417,6 +446,12 @@ static int acpi_hibernation_enter(void)
        return ACPI_SUCCESS(status) ? 0 : -EFAULT;
 }
 
+static void acpi_hibernation_finish(void)
+{
+       hibernate_nvs_free();
+       acpi_pm_finish();
+}
+
 static void acpi_hibernation_leave(void)
 {
        /*
@@ -432,6 +467,8 @@ static void acpi_hibernation_leave(void)
                        "cannot resume!\n");
                panic("ACPI S4 hardware signature mismatch");
        }
+       /* Restore the NVS memory area */
+       hibernate_nvs_restore();
 }
 
 static void acpi_pm_enable_gpes(void)
@@ -442,8 +479,8 @@ static void acpi_pm_enable_gpes(void)
 static struct platform_hibernation_ops acpi_hibernation_ops = {
        .begin = acpi_hibernation_begin,
        .end = acpi_pm_end,
-       .pre_snapshot = acpi_pm_prepare,
-       .finish = acpi_pm_finish,
+       .pre_snapshot = acpi_hibernation_pre_snapshot,
+       .finish = acpi_hibernation_finish,
        .prepare = acpi_pm_prepare,
        .enter = acpi_hibernation_enter,
        .leave = acpi_hibernation_leave,
@@ -469,8 +506,22 @@ static int acpi_hibernation_begin_old(void)
 
        error = acpi_sleep_prepare(ACPI_STATE_S4);
 
+       if (!error) {
+               if (!s4_no_nvs)
+                       error = hibernate_nvs_alloc();
+               if (!error)
+                       acpi_target_sleep_state = ACPI_STATE_S4;
+       }
+       return error;
+}
+
+static int acpi_hibernation_pre_snapshot_old(void)
+{
+       int error = acpi_pm_disable_gpes();
+
        if (!error)
-               acpi_target_sleep_state = ACPI_STATE_S4;
+               hibernate_nvs_save();
+
        return error;
 }
 
@@ -481,8 +532,8 @@ static int acpi_hibernation_begin_old(void)
 static struct platform_hibernation_ops acpi_hibernation_ops_old = {
        .begin = acpi_hibernation_begin_old,
        .end = acpi_pm_end,
-       .pre_snapshot = acpi_pm_disable_gpes,
-       .finish = acpi_pm_finish,
+       .pre_snapshot = acpi_hibernation_pre_snapshot_old,
+       .finish = acpi_hibernation_finish,
        .prepare = acpi_pm_disable_gpes,
        .enter = acpi_hibernation_enter,
        .leave = acpi_hibernation_leave,