diff options
-rw-r--r-- | drivers/acpi/sleep/main.c | 12 | ||||
-rw-r--r-- | include/linux/suspend.h | 38 | ||||
-rw-r--r-- | kernel/power/disk.c | 27 |
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; |