aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/sleep/main.c12
-rw-r--r--include/linux/suspend.h38
-rw-r--r--kernel/power/disk.c27
3 files changed, 64 insertions, 13 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index c58dd0bb550..f20b0ab9ef5 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -230,6 +230,12 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
#endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATION
+static int acpi_hibernation_start(void)
+{
+ acpi_target_sleep_state = ACPI_STATE_S4;
+ return 0;
+}
+
static int acpi_hibernation_prepare(void)
{
return acpi_sleep_prepare(ACPI_STATE_S4);
@@ -258,6 +264,8 @@ static void acpi_hibernation_finish(void)
/* reset firmware waking vector */
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+
+ acpi_target_sleep_state = ACPI_STATE_S0;
}
static int acpi_hibernation_pre_restore(void)
@@ -275,9 +283,11 @@ static void acpi_hibernation_restore_cleanup(void)
}
static struct hibernation_ops acpi_hibernation_ops = {
+ .start = acpi_hibernation_start,
+ .pre_snapshot = acpi_hibernation_prepare,
+ .finish = acpi_hibernation_finish,
.prepare = acpi_hibernation_prepare,
.enter = acpi_hibernation_enter,
- .finish = acpi_hibernation_finish,
.pre_restore = acpi_hibernation_pre_restore,
.restore_cleanup = acpi_hibernation_restore_cleanup,
};
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index dee416c5477..0044483dd47 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -134,16 +134,42 @@ extern void mark_free_pages(struct zone *zone);
*
* All three methods must be assigned.
*
- * @prepare: prepare system for hibernation
- * @enter: shut down system after state has been saved to disk
- * @finish: finish/clean up after state has been reloaded
- * @pre_restore: prepare system for the restoration from a hibernation image
- * @restore_cleanup: clean up after a failing image restoration
+ * @start: Tell the platform driver that we're starting hibernation.
+ * Called right after shrinking memory and before freezing devices.
+ *
+ * @pre_snapshot: Prepare the platform for creating the hibernation image.
+ * Called right after devices have been frozen and before the nonboot
+ * CPUs are disabled (runs with IRQs on).
+ *
+ * @finish: Restore the previous state of the platform after the hibernation
+ * image has been created *or* put the platform into the normal operation
+ * mode after the hibernation (the same method is executed in both cases).
+ * Called right after the nonboot CPUs have been enabled and before
+ * thawing devices (runs with IRQs on).
+ *
+ * @prepare: Prepare the platform for entering the low power state.
+ * Called right after the hibernation image has been saved and before
+ * devices are prepared for entering the low power state.
+ *
+ * @enter: Put the system into the low power state after the hibernation image
+ * has been saved to disk.
+ * Called after the nonboot CPUs have been disabled and all of the low
+ * level devices have been shut down (runs with IRQs off).
+ *
+ * @pre_restore: Prepare system for the restoration from a hibernation image.
+ * Called right after devices have been frozen and before the nonboot
+ * CPUs are disabled (runs with IRQs on).
+ *
+ * @restore_cleanup: Clean up after a failing image restoration.
+ * Called right after the nonboot CPUs have been enabled and before
+ * thawing devices (runs with IRQs on).
*/
struct hibernation_ops {
+ int (*start)(void);
+ int (*pre_snapshot)(void);
+ void (*finish)(void);
int (*prepare)(void);
int (*enter)(void);
- void (*finish)(void);
int (*pre_restore)(void);
void (*restore_cleanup)(void);
};
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index eb72255b5c8..d17bb14bce7 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -54,8 +54,9 @@ static struct hibernation_ops *hibernation_ops;
void hibernation_set_ops(struct hibernation_ops *ops)
{
- if (ops && !(ops->prepare && ops->enter && ops->finish
- && ops->pre_restore && ops->restore_cleanup)) {
+ if (ops && !(ops->start && ops->pre_snapshot && ops->finish
+ && ops->prepare && ops->enter && ops->pre_restore
+ && ops->restore_cleanup)) {
WARN_ON(1);
return;
}
@@ -69,16 +70,26 @@ void hibernation_set_ops(struct hibernation_ops *ops)
mutex_unlock(&pm_mutex);
}
+/**
+ * platform_start - tell the platform driver that we're starting
+ * hibernation
+ */
+
+static int platform_start(int platform_mode)
+{
+ return (platform_mode && hibernation_ops) ?
+ hibernation_ops->start() : 0;
+}
/**
- * platform_prepare - prepare the machine for hibernation using the
+ * platform_pre_snapshot - prepare the machine for hibernation using the
* platform driver if so configured and return an error code if it fails
*/
-static int platform_prepare(int platform_mode)
+static int platform_pre_snapshot(int platform_mode)
{
return (platform_mode && hibernation_ops) ?
- hibernation_ops->prepare() : 0;
+ hibernation_ops->pre_snapshot() : 0;
}
/**
@@ -135,12 +146,16 @@ int hibernation_snapshot(int platform_mode)
if (error)
return error;
+ error = platform_start(platform_mode);
+ if (error)
+ return error;
+
suspend_console();
error = device_suspend(PMSG_FREEZE);
if (error)
goto Resume_console;
- error = platform_prepare(platform_mode);
+ error = platform_pre_snapshot(platform_mode);
if (error)
goto Resume_devices;