From e60cc7a6f02598fc23c68a656fe9c263d6531ca0 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 13 Mar 2009 12:08:26 -0600 Subject: ACPI: move private declarations to internal.h A number of things that shouldn't be exposed outside the ACPI core were declared in include/acpi/acpi_drivers.h, where anybody can see them. This patch moves those declarations to a new "internal.h" inside drivers/acpi. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/sleep.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/acpi/sleep.c') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 519266654f0..0f86cf74216 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -21,6 +21,8 @@ #include #include + +#include "internal.h" #include "sleep.h" u8 sleep_states[ACPI_S_STATE_COUNT]; -- cgit v1.2.3-70-g09d2 From 50ffba1bd3120b069617455545bc27bcf3cf7579 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 23 Feb 2009 15:02:07 +0800 Subject: ACPICA: Rename ACPI bit register access functions Rename acpi_get_register and acpi_set_register to clarify the purpose of these functions. New names are acpi_read_bit_register and acpi_write_bit_register. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/evevent.c | 12 ++++++------ drivers/acpi/acpica/evmisc.c | 4 ++-- drivers/acpi/acpica/evxfevnt.c | 24 ++++++++++++------------ drivers/acpi/acpica/hwacpi.c | 2 +- drivers/acpi/acpica/hwsleep.c | 15 ++++++++------- drivers/acpi/acpica/hwxface.c | 16 ++++++++-------- drivers/acpi/processor_idle.c | 10 +++++----- drivers/acpi/sleep.c | 2 +- include/acpi/acpixf.h | 4 ++-- 9 files changed, 45 insertions(+), 44 deletions(-) (limited to 'drivers/acpi/sleep.c') diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index 803edd9e3f6..246f8775ec1 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -204,8 +204,8 @@ static acpi_status acpi_ev_fixed_event_initialize(void) if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) { status = - acpi_set_register(acpi_gbl_fixed_event_info[i]. - enable_register_id, 0); + acpi_write_bit_register(acpi_gbl_fixed_event_info + [i].enable_register_id, 0); if (ACPI_FAILURE(status)) { return (status); } @@ -288,16 +288,16 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event) /* Clear the status bit */ - (void)acpi_set_register(acpi_gbl_fixed_event_info[event]. - status_register_id, 1); + (void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. + status_register_id, 1); /* * Make sure we've got a handler. If not, report an error. The event is * disabled to prevent further interrupts. */ if (NULL == acpi_gbl_fixed_event_handlers[event].handler) { - (void)acpi_set_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, 0); + (void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. + enable_register_id, 0); ACPI_ERROR((AE_INFO, "No installed handler for fixed event [%08X]", diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index 5f893057bcc..0e9e12b2f2b 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -534,8 +534,8 @@ acpi_status acpi_ev_release_global_lock(void) */ if (pending) { status = - acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE, - 1); + acpi_write_bit_register + (ACPI_BITREG_GLOBAL_LOCK_RELEASE, 1); } ACPI_DEBUG_PRINT((ACPI_DB_EXEC, diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 35485e4b60a..484c9793ca0 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -172,8 +172,8 @@ acpi_status acpi_enable_event(u32 event, u32 flags) * register bit) */ status = - acpi_set_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, 1); + acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. + enable_register_id, 1); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -181,8 +181,8 @@ acpi_status acpi_enable_event(u32 event, u32 flags) /* Make sure that the hardware responded */ status = - acpi_get_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, &value); + acpi_read_bit_register(acpi_gbl_fixed_event_info[event]. + enable_register_id, &value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -354,15 +354,15 @@ acpi_status acpi_disable_event(u32 event, u32 flags) * register bit) */ status = - acpi_set_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, 0); + acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. + enable_register_id, 0); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } status = - acpi_get_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, &value); + acpi_read_bit_register(acpi_gbl_fixed_event_info[event]. + enable_register_id, &value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -407,8 +407,8 @@ acpi_status acpi_clear_event(u32 event) * register bit) */ status = - acpi_set_register(acpi_gbl_fixed_event_info[event]. - status_register_id, 1); + acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. + status_register_id, 1); return_ACPI_STATUS(status); } @@ -495,7 +495,7 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) /* Get the status of the requested fixed event */ status = - acpi_get_register(acpi_gbl_fixed_event_info[event]. + acpi_read_bit_register(acpi_gbl_fixed_event_info[event]. enable_register_id, &value); if (ACPI_FAILURE(status)) return_ACPI_STATUS(status); @@ -503,7 +503,7 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) *event_status = value; status = - acpi_get_register(acpi_gbl_fixed_event_info[event]. + acpi_read_bit_register(acpi_gbl_fixed_event_info[event]. status_register_id, &value); if (ACPI_FAILURE(status)) return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index a9d4fea4167..8902db8c670 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -172,7 +172,7 @@ u32 acpi_hw_get_mode(void) return_UINT32(ACPI_SYS_MODE_ACPI); } - status = acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value); + status = acpi_read_bit_register(ACPI_BITREG_SCI_ENABLE, &value); if (ACPI_FAILURE(status)) { return_UINT32(ACPI_SYS_MODE_LEGACY); } diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 677ccb6bcee..78d62b8a5c3 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -250,7 +250,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) /* Clear wake status */ - status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1); + status = acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, 1); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -365,7 +365,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) /* Wait until we enter sleep state */ do { - status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, + status = acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -399,7 +399,7 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void) ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios); - status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1); + status = acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, 1); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -431,7 +431,8 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void) do { acpi_os_stall(1000); - status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value); + status = + acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -592,18 +593,18 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) * it to determine whether the system is rebooting or resuming. Clear * it for compatibility. */ - acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1); + acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, 1); acpi_gbl_system_awake_and_running = TRUE; /* Enable power button */ (void) - acpi_set_register(acpi_gbl_fixed_event_info + acpi_write_bit_register(acpi_gbl_fixed_event_info [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1); (void) - acpi_set_register(acpi_gbl_fixed_event_info + acpi_write_bit_register(acpi_gbl_fixed_event_info [ACPI_EVENT_POWER_BUTTON].status_register_id, 1); arg.integer.value = ACPI_SST_WORKING; diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index c8100199634..529251c7f91 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -242,7 +242,7 @@ ACPI_EXPORT_SYMBOL(acpi_write) /******************************************************************************* * - * FUNCTION: acpi_get_register + * FUNCTION: acpi_read_bit_register * * PARAMETERS: register_id - ID of ACPI Bit Register to access * return_value - Value that was read from the register, @@ -264,13 +264,13 @@ ACPI_EXPORT_SYMBOL(acpi_write) * it make much sense to actually read this field.) * ******************************************************************************/ -acpi_status acpi_get_register(u32 register_id, u32 *return_value) +acpi_status acpi_read_bit_register(u32 register_id, u32 *return_value) { u32 register_value = 0; struct acpi_bit_register_info *bit_reg_info; acpi_status status; - ACPI_FUNCTION_TRACE(acpi_get_register); + ACPI_FUNCTION_TRACE(acpi_read_bit_register); /* Get the info structure corresponding to the requested ACPI Register */ @@ -302,11 +302,11 @@ acpi_status acpi_get_register(u32 register_id, u32 *return_value) return_ACPI_STATUS(status); } -ACPI_EXPORT_SYMBOL(acpi_get_register) +ACPI_EXPORT_SYMBOL(acpi_read_bit_register) /******************************************************************************* * - * FUNCTION: acpi_set_register + * FUNCTION: acpi_write_bit_register * * PARAMETERS: register_id - ID of ACPI Bit Register to access * Value - Value to write to the register, in bit @@ -322,14 +322,14 @@ ACPI_EXPORT_SYMBOL(acpi_get_register) * PM2 Control. * ******************************************************************************/ -acpi_status acpi_set_register(u32 register_id, u32 value) +acpi_status acpi_write_bit_register(u32 register_id, u32 value) { u32 register_value = 0; struct acpi_bit_register_info *bit_reg_info; acpi_status status; acpi_cpu_flags lock_flags; - ACPI_FUNCTION_TRACE_U32(acpi_set_register, register_id); + ACPI_FUNCTION_TRACE_U32(acpi_write_bit_register, register_id); /* Get the info structure corresponding to the requested ACPI Register */ @@ -459,7 +459,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value) return_ACPI_STATUS(status); } -ACPI_EXPORT_SYMBOL(acpi_set_register) +ACPI_EXPORT_SYMBOL(acpi_write_bit_register) /******************************************************************************* * diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 6946047d009..5c69e85c1e4 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -630,7 +630,7 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, * In either case, the proper way to * handle BM_RLD is to set it and leave it set. */ - acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1); + acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 1); return; } @@ -800,9 +800,9 @@ static int acpi_idle_bm_check(void) { u32 bm_status = 0; - acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status); + acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status); if (bm_status) - acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1); + acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, 1); /* * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect * the true state of bus mastering activity; forcing us to @@ -1028,7 +1028,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, c3_cpu_count++; /* Disable bus master arbitration when all CPUs are in C3 */ if (c3_cpu_count == num_online_cpus()) - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); + acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1); spin_unlock(&c3_lock); } else if (!pr->flags.bm_check) { ACPI_FLUSH_CPU_CACHE(); @@ -1041,7 +1041,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, /* Re-enable bus master arbitration */ if (pr->flags.bm_check && pr->flags.bm_control) { spin_lock(&c3_lock); - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); + acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0); c3_cpu_count--; spin_unlock(&c3_lock); } diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 00456fccfa3..837ac7d5801 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -248,7 +248,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) /* If ACPI is not enabled by the BIOS, we need to enable it here. */ if (set_sci_en_on_resume) - acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1); + acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1); else acpi_enable(); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 325d4b073ac..a5525a5518a 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -345,9 +345,9 @@ acpi_resource_to_address64(struct acpi_resource *resource, */ acpi_status acpi_reset(void); -acpi_status acpi_get_register(u32 register_id, u32 * return_value); +acpi_status acpi_read_bit_register(u32 register_id, u32 *return_value); -acpi_status acpi_set_register(u32 register_id, u32 value); +acpi_status acpi_write_bit_register(u32 register_id, u32 value); acpi_status acpi_set_firmware_waking_vector(u32 physical_address); -- cgit v1.2.3-70-g09d2 From 2a9ef8e1a856be8e526bb9b10fb98c5012f6e3f8 Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Wed, 18 Mar 2009 16:36:25 +0800 Subject: ACPI: suspend: Add the Pansonic CF51 box to the dmi check table The Pansonic CF51-2L requires "acpi_sleep=old_ordering", so invoke it automatically via DMI. http://bugzilla.kernel.org/show_bug.cgi?id=12561 Signed-off-by: Zhao Yakui Signed-off-by: Len Brown --- drivers/acpi/sleep.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/acpi/sleep.c') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 00456fccfa3..31ff2a9a03d 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -394,6 +394,15 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"), }, }, + { + .callback = init_old_suspend_ordering, + .ident = "Panasonic CF51-2L", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, + "Matsushita Electric Industrial Co.,Ltd."), + DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"), + }, + }, {}, }; #endif /* CONFIG_SUSPEND */ -- cgit v1.2.3-70-g09d2 From 96f15efcea94545987715f453a8c2b8ea592d000 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 17 Apr 2009 23:32:20 -0400 Subject: ACPI: Disable _GTS and _BFS support by default Executing BIOS code paths not exercised by Windows tends to get Linux into trouble. However, if a system does benefit from _GTS or _BFS, acpi.gts=1 an acpi.bfs=1 are now available to enable them. http://bugzilla.kernel.org/show_bug.cgi?id=13041 Signed-off-by: Len Brown --- drivers/acpi/acpica/hwsleep.c | 43 ++++++++++++++++++++++++++----------------- drivers/acpi/sleep.c | 27 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 17 deletions(-) (limited to 'drivers/acpi/sleep.c') diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index baa5fc05e12..db307a356f0 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -211,6 +211,12 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) +static unsigned int gts, bfs; +module_param(gts, uint, 0644); +module_param(bfs, uint, 0644); +MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend."); +MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".); + /******************************************************************************* * * FUNCTION: acpi_enter_sleep_state @@ -278,16 +284,18 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) return_ACPI_STATUS(status); } - /* Execute the _GTS method */ + if (gts) { + /* Execute the _GTS method */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = sleep_state; + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = sleep_state; - status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL); - if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { - return_ACPI_STATUS(status); + status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + return_ACPI_STATUS(status); + } } /* Get current value of PM1A control */ @@ -513,18 +521,19 @@ acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) } } - /* Execute the _BFS method */ + if (bfs) { + /* Execute the _BFS method */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = sleep_state; + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = sleep_state; - status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL); - if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { - ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS")); + status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS")); + } } - return_ACPI_STATUS(status); } diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 779e4e500df..9042875ac94 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -713,6 +713,32 @@ static void acpi_power_off(void) acpi_enter_sleep_state(ACPI_STATE_S5); } +/* + * ACPI 2.0 created the optional _GTS and _BFS, + * but industry adoption has been neither rapid nor broad. + * + * Linux gets into trouble when it executes poorly validated + * paths through the BIOS, so disable _GTS and _BFS by default, + * but do speak up and offer the option to enable them. + */ +void __init acpi_gts_bfs_check(void) +{ + acpi_handle dummy; + + if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_NAME__GTS, &dummy))) + { + printk(KERN_NOTICE PREFIX "BIOS offers _GTS\n"); + printk(KERN_NOTICE PREFIX "If \"acpi.gts=1\" improves suspend, " + "please notify linux-acpi@vger.kernel.org\n"); + } + if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_NAME__BFS, &dummy))) + { + printk(KERN_NOTICE PREFIX "BIOS offers _BFS\n"); + printk(KERN_NOTICE PREFIX "If \"acpi.bfs=1\" improves resume, " + "please notify linux-acpi@vger.kernel.org\n"); + } +} + int __init acpi_sleep_init(void) { acpi_status status; @@ -771,5 +797,6 @@ int __init acpi_sleep_init(void) * object can also be evaluated when the system enters S5. */ register_reboot_notifier(&tts_notifier); + acpi_gts_bfs_check(); return 0; } -- cgit v1.2.3-70-g09d2 From 6a7c7eaf71b636f197d73b381a2ab729ebdcfb2e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 19 Apr 2009 20:08:42 +0200 Subject: PM/Suspend: Introduce two new platform callbacks to avoid breakage Commit 900af0d973856d6feb6fc088c2d0d3fde57707d3 (PM: Change suspend code ordering) changed the ordering of suspend code in such a way that the platform .prepare() callback is now executed after the device drivers' late suspend callbacks have run. Unfortunately, this turns out to break ARM platforms that need to talk via I2C to power control devices during the .prepare() callback. For this reason introduce two new platform suspend callbacks, .prepare_late() and .wake(), that will be called just prior to disabling non-boot CPUs and right after bringing them back on line, respectively, and use them instead of .prepare() and .finish() for ACPI suspend. Make the PM core execute the .prepare() and .finish() platform suspend callbacks where they were executed previously (that is, right after calling the regular suspend methods provided by device drivers and right before executing their regular resume methods, respectively). It is not necessary to make analogous changes to the hibernation code and data structures at the moment, because they are only used by ACPI platforms. Signed-off-by: Rafael J. Wysocki Reported-by: Russell King Acked-by: Len Brown --- drivers/acpi/sleep.c | 8 ++++---- include/linux/suspend.h | 36 ++++++++++++++++++++++++++---------- kernel/power/main.c | 24 +++++++++++++++++------- 3 files changed, 47 insertions(+), 21 deletions(-) (limited to 'drivers/acpi/sleep.c') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 779e4e500df..d060e6fd7fd 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -300,9 +300,9 @@ static int acpi_suspend_state_valid(suspend_state_t pm_state) static struct platform_suspend_ops acpi_suspend_ops = { .valid = acpi_suspend_state_valid, .begin = acpi_suspend_begin, - .prepare = acpi_pm_prepare, + .prepare_late = acpi_pm_prepare, .enter = acpi_suspend_enter, - .finish = acpi_pm_finish, + .wake = acpi_pm_finish, .end = acpi_pm_end, }; @@ -328,9 +328,9 @@ 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 = acpi_pm_disable_gpes, + .prepare_late = acpi_pm_disable_gpes, .enter = acpi_suspend_enter, - .finish = acpi_pm_finish, + .wake = acpi_pm_finish, .end = acpi_pm_end, .recover = acpi_pm_finish, }; diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 3e3a4364cbf..795032edfc4 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -58,10 +58,17 @@ typedef int __bitwise suspend_state_t; * by @begin(). * @prepare() is called right after devices have been suspended (ie. the * appropriate .suspend() method has been executed for each device) and - * before the nonboot CPUs are disabled (it is executed with IRQs enabled). - * This callback is optional. It returns 0 on success or a negative - * error code otherwise, in which case the system cannot enter the desired - * sleep state (@enter() and @finish() will not be called in that case). + * before device drivers' late suspend callbacks are executed. It returns + * 0 on success or a negative error code otherwise, in which case the + * system cannot enter the desired sleep state (@prepare_late(), @enter(), + * @wake(), and @finish() will not be called in that case). + * + * @prepare_late: Finish preparing the platform for entering the system sleep + * state indicated by @begin(). + * @prepare_late is called before disabling nonboot CPUs and after + * device drivers' late suspend callbacks have been executed. It returns + * 0 on success or a negative error code otherwise, in which case the + * system cannot enter the desired sleep state (@enter() and @wake()). * * @enter: Enter the system sleep state indicated by @begin() or represented by * the argument if @begin() is not implemented. @@ -69,19 +76,26 @@ typedef int __bitwise suspend_state_t; * error code otherwise, in which case the system cannot enter the desired * sleep state. * - * @finish: Called when the system has just left a sleep state, right after - * the nonboot CPUs have been enabled and before devices are resumed (it is - * executed with IRQs enabled). + * @wake: Called when the system has just left a sleep state, right after + * the nonboot CPUs have been enabled and before device drivers' early + * resume callbacks are executed. + * This callback is optional, but should be implemented by the platforms + * that implement @prepare_late(). If implemented, it is always called + * after @enter(), even if @enter() fails. + * + * @finish: Finish wake-up of the platform. + * @finish is called right prior to calling device drivers' regular suspend + * callbacks. * This callback is optional, but should be implemented by the platforms * that implement @prepare(). If implemented, it is always called after - * @enter() (even if @enter() fails). + * @enter() and @wake(), if implemented, even if any of them fails. * * @end: Called by the PM core right after resuming devices, to indicate to * the platform that the system has returned to the working state or * the transition to the sleep state has been aborted. * This callback is optional, but should be implemented by the platforms - * that implement @begin(), but platforms implementing @begin() should - * also provide a @end() which cleans up transitions aborted before + * that implement @begin(). Accordingly, platforms implementing @begin() + * should also provide a @end() which cleans up transitions aborted before * @enter(). * * @recover: Recover the platform from a suspend failure. @@ -93,7 +107,9 @@ struct platform_suspend_ops { int (*valid)(suspend_state_t state); int (*begin)(suspend_state_t state); int (*prepare)(void); + int (*prepare_late)(void); int (*enter)(suspend_state_t state); + void (*wake)(void); void (*finish)(void); void (*end)(void); void (*recover)(void); diff --git a/kernel/power/main.c b/kernel/power/main.c index f172f41858b..f99ed6a75ea 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -291,20 +291,26 @@ static int suspend_enter(suspend_state_t state) device_pm_lock(); + if (suspend_ops->prepare) { + error = suspend_ops->prepare(); + if (error) + goto Done; + } + error = device_power_down(PMSG_SUSPEND); if (error) { printk(KERN_ERR "PM: Some devices failed to power down\n"); - goto Done; + goto Platfrom_finish; } - if (suspend_ops->prepare) { - error = suspend_ops->prepare(); + if (suspend_ops->prepare_late) { + error = suspend_ops->prepare_late(); if (error) goto Power_up_devices; } if (suspend_test(TEST_PLATFORM)) - goto Platfrom_finish; + goto Platform_wake; error = disable_nonboot_cpus(); if (error || suspend_test(TEST_CPUS)) @@ -326,13 +332,17 @@ static int suspend_enter(suspend_state_t state) Enable_cpus: enable_nonboot_cpus(); - Platfrom_finish: - if (suspend_ops->finish) - suspend_ops->finish(); + Platform_wake: + if (suspend_ops->wake) + suspend_ops->wake(); Power_up_devices: device_power_up(PMSG_RESUME); + Platfrom_finish: + if (suspend_ops->finish) + suspend_ops->finish(); + Done: device_pm_unlock(); -- cgit v1.2.3-70-g09d2