From e96c4b081df0991a57b244f68c3955a9ea00bd0a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 6 Jul 2010 18:28:35 -0400 Subject: ACPI / Sleep: Free NVS copy if suspending of devices fails If suspending of devices fails or system suspend is tested in the "devices" mode, the memory allocated for storing a copy of the ACPI NVS area will not be freed, because acpi_pm_finish() is not called in that case. Fix this by moving the suspend_nvs_free() call to acpi_pm_end(). Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/sleep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 5b7c52e4a00f..da68ed24f4c5 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -145,7 +145,6 @@ static void acpi_pm_finish(void) { u32 acpi_state = acpi_target_sleep_state; - suspend_nvs_free(); acpi_ec_unblock_transactions(); if (acpi_state == ACPI_STATE_S0) @@ -167,6 +166,7 @@ static void acpi_pm_finish(void) */ static void acpi_pm_end(void) { + suspend_nvs_free(); /* * This is necessary in case acpi_pm_finish() is not called during a * failing transition to a sleep state. -- cgit v1.2.3 From 25bed55753b8cf243406e8837990b55946c5278d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 2 Jul 2010 00:12:26 +0200 Subject: ACPI / Sleep: Rework enabling wakeup devices There is no reason why acpi_enable_wakeup_device() should be called with interrupts disabled, because it doesn't access hardware. Thus it is possible to move it next to acpi_enable_wakeup_device_prep() and make the ACPI suspend, hibernate and poweroff code more straightforward. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/sleep.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index da68ed24f4c5..8704ca78a8c4 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -70,10 +70,11 @@ static int acpi_sleep_prepare(u32 acpi_state) } ACPI_FLUSH_CPU_CACHE(); - acpi_enable_wakeup_device_prep(acpi_state); #endif printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n", acpi_state); + acpi_enable_wakeup_device_prep(acpi_state); + acpi_enable_wakeup_device(acpi_state); acpi_enter_sleep_state_prep(acpi_state); return 0; } @@ -238,7 +239,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) } local_irq_save(flags); - acpi_enable_wakeup_device(acpi_state); switch (acpi_state) { case ACPI_STATE_S1: barrier(); @@ -442,7 +442,6 @@ static int acpi_hibernation_enter(void) ACPI_FLUSH_CPU_CACHE(); local_irq_save(flags); - acpi_enable_wakeup_device(ACPI_STATE_S4); /* This shouldn't return. If it returns, we have a problem */ status = acpi_enter_sleep_state(ACPI_STATE_S4); /* Reprogram control registers and execute _BFS */ @@ -696,7 +695,6 @@ static void acpi_power_off(void) /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ printk(KERN_DEBUG "%s called\n", __func__); local_irq_disable(); - acpi_enable_wakeup_device(ACPI_STATE_S5); acpi_enter_sleep_state(ACPI_STATE_S5); } -- cgit v1.2.3 From 78f5f023167813130d2cf657d1b9eadc32f0e992 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 6 Jul 2010 22:09:38 -0400 Subject: ACPI / Wakeup: Simplify enabling of wakeup devices To simplify the enabling of wakeup devices during system suspend and hibernation, merge acpi_enable_wakeup_device_prep() with acpi_disable_wakeup_device() and remove unnecessary (and no longer valid) comments from the latter. Rename acpi_enable_wakeup_device() to acpi_enable_wakeup_devices() and acpi_disable_wakeup_device() to acpi_disable_wakeup_devices(), because these functions usually operate on multiple device objects. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/sleep.c | 5 ++--- drivers/acpi/sleep.h | 5 ++--- drivers/acpi/wakeup.c | 48 ++++++++++-------------------------------------- 3 files changed, 14 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 8704ca78a8c4..93441c95c53b 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -73,8 +73,7 @@ static int acpi_sleep_prepare(u32 acpi_state) #endif printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n", acpi_state); - acpi_enable_wakeup_device_prep(acpi_state); - acpi_enable_wakeup_device(acpi_state); + acpi_enable_wakeup_devices(acpi_state); acpi_enter_sleep_state_prep(acpi_state); return 0; } @@ -153,7 +152,7 @@ static void acpi_pm_finish(void) printk(KERN_INFO PREFIX "Waking up from system sleep state S%d\n", acpi_state); - acpi_disable_wakeup_device(acpi_state); + acpi_disable_wakeup_devices(acpi_state); acpi_leave_sleep_state(acpi_state); /* reset firmware waking vector */ diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h index 25b8bd149284..d8821805c3bc 100644 --- a/drivers/acpi/sleep.h +++ b/drivers/acpi/sleep.h @@ -2,9 +2,8 @@ extern u8 sleep_states[]; extern int acpi_suspend(u32 state); -extern void acpi_enable_wakeup_device_prep(u8 sleep_state); -extern void acpi_enable_wakeup_device(u8 sleep_state); -extern void acpi_disable_wakeup_device(u8 sleep_state); +extern void acpi_enable_wakeup_devices(u8 sleep_state); +extern void acpi_disable_wakeup_devices(u8 sleep_state); extern struct list_head acpi_wakeup_device_list; extern struct mutex acpi_device_lock; diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c index 388747a7ef4f..dc6d1d9112fb 100644 --- a/drivers/acpi/wakeup.c +++ b/drivers/acpi/wakeup.c @@ -21,45 +21,17 @@ ACPI_MODULE_NAME("wakeup_devices") /** - * acpi_enable_wakeup_device_prep - Prepare wake-up devices. + * acpi_enable_wakeup_devices - Enable wake-up device GPEs. * @sleep_state: ACPI system sleep state. * - * Enable all wake-up devices' power, unless the requested system sleep state is - * too deep. + * Enable wakeup device power of devices with the state.enable flag set and set + * the wakeup enable mask bits in the GPE registers that correspond to wakeup + * devices. */ -void acpi_enable_wakeup_device_prep(u8 sleep_state) +void acpi_enable_wakeup_devices(u8 sleep_state) { struct list_head *node, *next; - list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = container_of(node, - struct acpi_device, - wakeup_list); - - if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled - || (sleep_state > (u32) dev->wakeup.sleep_state)) - continue; - - acpi_enable_wakeup_device_power(dev, sleep_state); - } -} - -/** - * acpi_enable_wakeup_device - Enable wake-up device GPEs. - * @sleep_state: ACPI system sleep state. - * - * Enable all wake-up devices' GPEs, with the assumption that - * acpi_disable_all_gpes() was executed before, so we don't need to disable any - * GPEs here. - */ -void acpi_enable_wakeup_device(u8 sleep_state) -{ - struct list_head *node, *next; - - /* - * Caution: this routine must be invoked when interrupt is disabled - * Refer ACPI2.0: P212 - */ list_for_each_safe(node, next, &acpi_wakeup_device_list) { struct acpi_device *dev = container_of(node, struct acpi_device, wakeup_list); @@ -68,6 +40,9 @@ void acpi_enable_wakeup_device(u8 sleep_state) || sleep_state > (u32) dev->wakeup.sleep_state) continue; + if (dev->wakeup.state.enabled) + acpi_enable_wakeup_device_power(dev, sleep_state); + /* The wake-up power should have been enabled already. */ acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE); @@ -75,13 +50,10 @@ void acpi_enable_wakeup_device(u8 sleep_state) } /** - * acpi_disable_wakeup_device - Disable devices' wakeup capability. + * acpi_disable_wakeup_devices - Disable devices' wakeup capability. * @sleep_state: ACPI system sleep state. - * - * This function only affects devices with wakeup.state.enabled set, which means - * that it reverses the changes made by acpi_enable_wakeup_device_prep(). */ -void acpi_disable_wakeup_device(u8 sleep_state) +void acpi_disable_wakeup_devices(u8 sleep_state) { struct list_head *node, *next; -- cgit v1.2.3 From c5f7a1bb65bca03253c189e946b3ca79669f08af Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 2 Jul 2010 00:14:09 +0200 Subject: ACPI / Sleep: Consolidate suspend and hibernation routines Some hibernation and suspend routines can be merged, which reduces the complexity of code a bit. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/sleep.c | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 93441c95c53b..61c5bd03f733 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -104,6 +104,16 @@ static int acpi_pm_freeze(void) return 0; } +/** + * acpi_pre_suspend - Enable wakeup devices, "freeze" EC and save NVS. + */ +static int acpi_pm_pre_suspend(void) +{ + acpi_pm_freeze(); + suspend_nvs_save(); + return 0; +} + /** * __acpi_pm_prepare - Prepare the platform to enter the target state. * @@ -113,11 +123,9 @@ static int acpi_pm_freeze(void) static int __acpi_pm_prepare(void) { int error = acpi_sleep_prepare(acpi_target_sleep_state); - - suspend_nvs_save(); - if (error) acpi_target_sleep_state = ACPI_STATE_S0; + return error; } @@ -128,9 +136,8 @@ static int __acpi_pm_prepare(void) static int acpi_pm_prepare(void) { int error = __acpi_pm_prepare(); - if (!error) - acpi_pm_freeze(); + acpi_pm_pre_suspend(); return error; } @@ -322,9 +329,9 @@ static struct platform_suspend_ops acpi_suspend_ops = { static int acpi_suspend_begin_old(suspend_state_t pm_state) { int error = acpi_suspend_begin(pm_state); - if (!error) error = __acpi_pm_prepare(); + return error; } @@ -335,7 +342,7 @@ static int acpi_suspend_begin_old(suspend_state_t pm_state) static struct platform_suspend_ops acpi_suspend_ops_old = { .valid = acpi_suspend_state_valid, .begin = acpi_suspend_begin_old, - .prepare_late = acpi_pm_freeze, + .prepare_late = acpi_pm_pre_suspend, .enter = acpi_suspend_enter, .wake = acpi_suspend_finish, .end = acpi_pm_end, @@ -423,16 +430,6 @@ static int acpi_hibernation_begin(void) return error; } -static int acpi_hibernation_pre_snapshot(void) -{ - int error = acpi_pm_prepare(); - - if (!error) - suspend_nvs_save(); - - return error; -} - static int acpi_hibernation_enter(void) { acpi_status status = AE_OK; @@ -480,7 +477,7 @@ static void acpi_pm_thaw(void) static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_hibernation_pre_snapshot, + .pre_snapshot = acpi_pm_prepare, .finish = acpi_pm_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, @@ -516,13 +513,6 @@ static int acpi_hibernation_begin_old(void) return error; } -static int acpi_hibernation_pre_snapshot_old(void) -{ - acpi_pm_freeze(); - suspend_nvs_save(); - return 0; -} - /* * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has * been requested. @@ -530,7 +520,7 @@ static int acpi_hibernation_pre_snapshot_old(void) static struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .pre_snapshot = acpi_pm_pre_suspend, .prepare = acpi_pm_freeze, .finish = acpi_pm_finish, .enter = acpi_hibernation_enter, -- cgit v1.2.3 From 618d7fd0d4e51a45d25d9bc6097a0cb1e5a2f226 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 2 Jul 2010 00:14:57 +0200 Subject: ACPI / Sleep: Drop acpi_suspend_finish() The function acpi_suspend_finish() is not necessary any more, because acpi_pm_finish() can be used instead of it just fine. Remove it. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/sleep.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 61c5bd03f733..5529c7023956 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -290,11 +290,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) return ACPI_SUCCESS(status) ? 0 : -EFAULT; } -static void acpi_suspend_finish(void) -{ - acpi_pm_finish(); -} - static int acpi_suspend_state_valid(suspend_state_t pm_state) { u32 acpi_state; @@ -316,7 +311,7 @@ static struct platform_suspend_ops acpi_suspend_ops = { .begin = acpi_suspend_begin, .prepare_late = acpi_pm_prepare, .enter = acpi_suspend_enter, - .wake = acpi_suspend_finish, + .wake = acpi_pm_finish, .end = acpi_pm_end, }; @@ -344,7 +339,7 @@ static struct platform_suspend_ops acpi_suspend_ops_old = { .begin = acpi_suspend_begin_old, .prepare_late = acpi_pm_pre_suspend, .enter = acpi_suspend_enter, - .wake = acpi_suspend_finish, + .wake = acpi_pm_finish, .end = acpi_pm_end, .recover = acpi_pm_finish, }; -- cgit v1.2.3