From 3d695839a135a9b3f24b0d7cfd9c4fde2eadd2c5 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Mon, 28 Jun 2010 20:55:01 -0400 Subject: [PATCH 1/8] ACPI: handle systems which asynchoronously enable ACPI mode Folklore suggested that such systems existed in the pre-history of ACPI. However, we removed the SCI_EN polling loop from acpi_hw_set_mode() in b430acbd7c4b919886fa7fd92eeb7a695f1940d3 because it delayed resume by 3 seconds on boxes that refused to set SCI_EN. Matthew removed the call to acpi_enable() from the suspend resume path. James found a modern system that still needs to be polled upon boot. So here we restore the workaround, except that we put it in acpi_enable() rather than the low level acpi_hw_set_mode(). https://bugzilla.kernel.org/show_bug.cgi?id=16271 Signed-off-by: Len Brown --- drivers/acpi/acpica/evxfevnt.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index d97b8dce1668..18b3f1468b7d 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -70,6 +70,7 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, acpi_status acpi_enable(void) { acpi_status status; + int retry; ACPI_FUNCTION_TRACE(acpi_enable); @@ -98,16 +99,18 @@ acpi_status acpi_enable(void) /* Sanity check that transition succeeded */ - if (acpi_hw_get_mode() != ACPI_SYS_MODE_ACPI) { - ACPI_ERROR((AE_INFO, - "Hardware did not enter ACPI mode")); - return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE); + for (retry = 0; retry < 30000; ++retry) { + if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) { + if (retry != 0) + ACPI_WARNING((AE_INFO, + "Platform took > %d00 usec to enter ACPI mode", retry)); + return_ACPI_STATUS(AE_OK); + } + acpi_os_stall(100); /* 100 usec */ } - ACPI_DEBUG_PRINT((ACPI_DB_INIT, - "Transition to ACPI mode successful\n")); - - return_ACPI_STATUS(AE_OK); + ACPI_ERROR((AE_INFO, "Hardware did not enter ACPI mode")); + return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE); } ACPI_EXPORT_SYMBOL(acpi_enable) From 153e500f516329f439856f52ccbf61d1fd1a946a Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 7 Jul 2010 09:11:57 +0800 Subject: [PATCH 2/8] ACPI battery: don't invoke power_supply_changed twice when battery is hot-added When battery is hot-added, we should not invoke power_supply_changed in acpi_battery_notify, because it has been invoked in acpi_battery_update, and battery->bat.changed_work is queued in keventd already. https://bugzilla.kernel.org/show_bug.cgi?id=16244 Signed-off-by: Zhang Rui Acked-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/battery.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 3026e3fa83ef..dc58402b0a17 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -868,9 +868,15 @@ static void acpi_battery_remove_fs(struct acpi_device *device) static void acpi_battery_notify(struct acpi_device *device, u32 event) { struct acpi_battery *battery = acpi_driver_data(device); +#ifdef CONFIG_ACPI_SYSFS_POWER + struct device *old; +#endif if (!battery) return; +#ifdef CONFIG_ACPI_SYSFS_POWER + old = battery->bat.dev; +#endif acpi_battery_update(battery); acpi_bus_generate_proc_event(device, event, acpi_battery_present(battery)); @@ -879,7 +885,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) acpi_battery_present(battery)); #ifdef CONFIG_ACPI_SYSFS_POWER /* acpi_battery_update could remove power_supply object */ - if (battery->bat.dev) + if (old && battery->bat.dev) power_supply_changed(&battery->bat); #endif } From 096486eece7ef38cf1ee46b704482c75c4010fb1 Mon Sep 17 00:00:00 2001 From: "Nik A. Melchior" Date: Mon, 21 Jun 2010 12:47:05 +0800 Subject: [PATCH 3/8] ACPI video: fix string mismatch for Sony SR290 laptop Fix string mismatch for Sony SR290 laptop. https://bugzilla.kernel.org/show_bug.cgi?id=12904#c45 Signed-off-by: Nik A. Melchior Signed-off-by: Len Brown --- drivers/acpi/blacklist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 01381be05e96..2bb28b9d91c4 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -214,7 +214,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { .ident = "Sony VGN-SR290J", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "Sony VGN-SR290J"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR290J"), }, }, { From 856b185dd23da39e562983fbf28860f54e661b41 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Thu, 17 Jun 2010 09:08:54 -0600 Subject: [PATCH 4/8] ACPI: processor: fix processor_physically_present on UP The commit 5d554a7bb06 (ACPI: processor: add internal processor_physically_present()) is broken on uniprocessor (UP) configurations, as acpi_get_cpuid() will always return -1. We use the value of num_possible_cpus() to tell us whether we got an invalid cpuid from acpi_get_cpuid() in the SMP case, or if instead, we are UP, in which case num_possible_cpus() is #defined as 1. We use num_possible_cpus() instead of num_online_cpus() to protect ourselves against the scenario of CPU hotplug, and we've taken down all the CPUs except one. Thanks to Jan Pogadl for initial report and analysis and Chen Gong for review. https://bugzilla.kernel.org/show_bug.cgi?id=16357 Reported-by: Jan Pogadl : Reviewed-by: Chen Gong Signed-off-by: Alex Chiang Signed-off-by: Len Brown --- drivers/acpi/processor_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 51284351418f..e9699aaed109 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -223,7 +223,7 @@ static bool processor_physically_present(acpi_handle handle) type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; cpuid = acpi_get_cpuid(handle, type, acpi_id); - if (cpuid == -1) + if ((cpuid == -1) && (num_possible_cpus() > 1)) return false; return true; From 6c9c0fd062a6540dbee233151679b5f03ce433d9 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Tue, 20 Jul 2010 15:18:35 -0700 Subject: [PATCH 5/8] ACPI: fix unused function warning CONFIG_ACPI_PROCFS=n: drivers/acpi/processor_idle.c:83: warning: 'us_to_pm_timer_ticks' defined but not used. Signed-off-by: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index b1b385692f46..d0035946b6b9 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -80,10 +80,13 @@ module_param(nocst, uint, 0000); static unsigned int latency_factor __read_mostly = 2; module_param(latency_factor, uint, 0644); +#ifdef CONFIG_ACPI_PROCFS static u64 us_to_pm_timer_ticks(s64 t) { return div64_u64(t * PM_TIMER_FREQUENCY, 1000000); } +#endif + /* * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3. * For now disable this. Probably a bug somewhere else. From 718be4aaf3613cf7c2d097f925abc3d3553c0605 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 22 Jul 2010 16:54:27 -0400 Subject: [PATCH 6/8] ACPI: skip checking BM_STS if the BIOS doesn't ask for it It turns out that there is a bit in the _CST for Intel FFH C3 that tells the OS if we should be checking BM_STS or not. Linux has been unconditionally checking BM_STS. If the chip-set is configured to enable BM_STS, it can retard or completely prevent entry into deep C-states -- as illustrated by turbostat: http://userweb.kernel.org/~lenb/acpi/utils/pmtools/turbostat/ ref: Intel Processor Vendor-Specific ACPI Interface Specification table 4 "_CST FFH GAS Field Encoding" Bit 1: Set to 1 if OSPM should use Bus Master avoidance for this C-state https://bugzilla.kernel.org/show_bug.cgi?id=15886 Signed-off-by: Len Brown --- arch/x86/kernel/acpi/cstate.c | 9 +++++++++ drivers/acpi/processor_idle.c | 2 +- include/acpi/processor.h | 3 ++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c index 2e837f5080fe..fb7a5f052e2b 100644 --- a/arch/x86/kernel/acpi/cstate.c +++ b/arch/x86/kernel/acpi/cstate.c @@ -145,6 +145,15 @@ int acpi_processor_ffh_cstate_probe(unsigned int cpu, percpu_entry->states[cx->index].eax = cx->address; percpu_entry->states[cx->index].ecx = MWAIT_ECX_INTERRUPT_BREAK; } + + /* + * For _CST FFH on Intel, if GAS.access_size bit 1 is cleared, + * then we should skip checking BM_STS for this C-state. + * ref: "Intel Processor Vendor-Specific ACPI Interface Specification" + */ + if ((c->x86_vendor == X86_VENDOR_INTEL) && !(reg->access_size & 0x2)) + cx->bm_sts_skip = 1; + return retval; } EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index b1b385692f46..b351342f1faf 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -947,7 +947,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, if (acpi_idle_suspend) return(acpi_idle_enter_c1(dev, state)); - if (acpi_idle_bm_check()) { + if (!cx->bm_sts_skip && acpi_idle_bm_check()) { if (dev->safe_state) { dev->last_state = dev->safe_state; return dev->safe_state->enter(dev, dev->safe_state); diff --git a/include/acpi/processor.h b/include/acpi/processor.h index da565a48240e..a68ca8a11a53 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -48,7 +48,7 @@ struct acpi_power_register { u8 space_id; u8 bit_width; u8 bit_offset; - u8 reserved; + u8 access_size; u64 address; } __attribute__ ((packed)); @@ -63,6 +63,7 @@ struct acpi_processor_cx { u32 power; u32 usage; u64 time; + u8 bm_sts_skip; char desc[ACPI_CX_DESC_LEN]; }; From d3e7e99f2faf9f44ec0a3379f735b41c9173dfa1 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 22 Jul 2010 17:23:10 -0400 Subject: [PATCH 7/8] ACPI: create "processor.bm_check_disable" boot param processor.bm_check_disable=1" prevents Linux from checking BM_STS before entering C3-type cpu power states. This may be useful for a system running acpi_idle where the BIOS exports FADT C-states, _CST IO C-states, or _CST FFH C-states with the BM_STS bit set; while configuring the chipset to set BM_STS more frequently than perhaps is optimal. Note that such systems may have been developed using a tickful OS that would quickly clear BM_STS, rather than a tickless OS that may go for some time between checking and clearing BM_STS. Note also that an alternative for newer systems is to use the intel_idle driver, which always ignores BM_STS, relying Linux device drivers to register constraints explicitly via PM_QOS. https://bugzilla.kernel.org/show_bug.cgi?id=15886 Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index b351342f1faf..1d4104855296 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -76,6 +76,8 @@ static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER; module_param(max_cstate, uint, 0000); static unsigned int nocst __read_mostly; module_param(nocst, uint, 0000); +static int bm_check_disable __read_mostly; +module_param(bm_check_disable, uint, 0000); static unsigned int latency_factor __read_mostly = 2; module_param(latency_factor, uint, 0644); @@ -763,6 +765,9 @@ static int acpi_idle_bm_check(void) { u32 bm_status = 0; + if (bm_check_disable) + return 0; + acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status); if (bm_status) acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, 1); From 72ad5d77fb981963edae15eee8196c80238f5ed0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 23 Jul 2010 22:59:09 +0200 Subject: [PATCH 8/8] ACPI / Sleep: Allow the NVS saving to be skipped during suspend to RAM Commit 2a6b69765ad794389f2fc3e14a0afa1a995221c2 (ACPI: Store NVS state even when entering suspend to RAM) caused the ACPI suspend code save the NVS area during suspend and restore it during resume unconditionally, although it is known that some systems need to use acpi_sleep=s4_nonvs for hibernation to work. To allow the affected systems to avoid saving and restoring the NVS area during suspend to RAM and resume, introduce kernel command line option acpi_sleep=nonvs and make acpi_sleep=s4_nonvs work as its alias temporarily (add acpi_sleep=s4_nonvs to the feature removal file). Addresses https://bugzilla.kernel.org/show_bug.cgi?id=16396 . Signed-off-by: Rafael J. Wysocki Reported-and-tested-by: tomas m Signed-off-by: Len Brown --- Documentation/feature-removal-schedule.txt | 7 +++++ Documentation/kernel-parameters.txt | 4 +-- arch/x86/kernel/acpi/sleep.c | 9 ++++-- drivers/acpi/sleep.c | 35 +++++++++++----------- include/linux/acpi.h | 2 +- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index c268783bc4e7..1571c0c83dba 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -647,3 +647,10 @@ Who: Stefan Richter ---------------------------- +What: The acpi_sleep=s4_nonvs command line option +When: 2.6.37 +Files: arch/x86/kernel/acpi/sleep.c +Why: superseded by acpi_sleep=nonvs +Who: Rafael J. Wysocki + +---------------------------- diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 4ddb58df081e..2b2407d9a6d0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -254,8 +254,8 @@ and is between 256 and 4096 characters. It is defined in the file control method, with respect to putting devices into low power states, to be enforced (the ACPI 2.0 ordering of _PTS is used by default). - s4_nonvs prevents the kernel from saving/restoring the - ACPI NVS memory during hibernation. + nonvs prevents the kernel from saving/restoring the + ACPI NVS memory during suspend/hibernation and resume. sci_force_enable causes the kernel to set SCI_EN directly on resume from S1/S3 (which is against the ACPI spec, but some broken systems don't work without it). diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 82e508677b91..fcc3c61fdecc 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -157,9 +157,14 @@ static int __init acpi_sleep_setup(char *str) #ifdef CONFIG_HIBERNATION if (strncmp(str, "s4_nohwsig", 10) == 0) acpi_no_s4_hw_signature(); - if (strncmp(str, "s4_nonvs", 8) == 0) - acpi_s4_no_nvs(); + if (strncmp(str, "s4_nonvs", 8) == 0) { + pr_warning("ACPI: acpi_sleep=s4_nonvs is deprecated, " + "please use acpi_sleep=nonvs instead"); + acpi_nvs_nosave(); + } #endif + if (strncmp(str, "nonvs", 5) == 0) + acpi_nvs_nosave(); if (strncmp(str, "old_ordering", 12) == 0) acpi_old_suspend_ordering(); str = strchr(str, ','); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 5b7c52e4a00f..2862c781b372 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -81,6 +81,20 @@ static int acpi_sleep_prepare(u32 acpi_state) #ifdef CONFIG_ACPI_SLEEP static u32 acpi_target_sleep_state = ACPI_STATE_S0; +/* + * The ACPI specification wants us to save NVS memory regions during hibernation + * and to restore them during the subsequent resume. Windows does that also for + * suspend to RAM. However, it is known that this mechanism does not work on + * all machines, so we allow the user to disable it with the help of the + * 'acpi_sleep=nonvs' kernel command line option. + */ +static bool nvs_nosave; + +void __init acpi_nvs_nosave(void) +{ + nvs_nosave = true; +} + /* * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the * user to request that behavior by using the 'acpi_old_suspend_ordering' @@ -197,8 +211,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state) u32 acpi_state = acpi_suspend_states[pm_state]; int error = 0; - error = suspend_nvs_alloc(); - + error = nvs_nosave ? 0 : suspend_nvs_alloc(); if (error) return error; @@ -388,20 +401,6 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { #endif /* CONFIG_SUSPEND */ #ifdef CONFIG_HIBERNATION -/* - * 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; -} - static unsigned long s4_hardware_signature; static struct acpi_table_facs *facs; static bool nosigcheck; @@ -415,7 +414,7 @@ static int acpi_hibernation_begin(void) { int error; - error = s4_no_nvs ? 0 : suspend_nvs_alloc(); + error = nvs_nosave ? 0 : suspend_nvs_alloc(); if (!error) { acpi_target_sleep_state = ACPI_STATE_S4; acpi_sleep_tts_switch(acpi_target_sleep_state); @@ -510,7 +509,7 @@ static int acpi_hibernation_begin_old(void) error = acpi_sleep_prepare(ACPI_STATE_S4); if (!error) { - if (!s4_no_nvs) + if (!nvs_nosave) error = suspend_nvs_alloc(); if (!error) acpi_target_sleep_state = ACPI_STATE_S4; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 224a38c960d4..ccf94dc5acdf 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -253,7 +253,7 @@ int acpi_resources_are_enforced(void); #ifdef CONFIG_PM_SLEEP void __init acpi_no_s4_hw_signature(void); void __init acpi_old_suspend_ordering(void); -void __init acpi_s4_no_nvs(void); +void __init acpi_nvs_nosave(void); #endif /* CONFIG_PM_SLEEP */ struct acpi_osc_context {