aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShaohua Li <shaohua.li@intel.com>2008-07-24 00:28:41 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-24 13:47:24 -0400
commitbdfe6b7c681669148dae4db27eb24ee5408ba371 (patch)
tree644b84a7e4a329a635d9a9bc02102424cfb616e2
parent2f15fc4bdf91eb399da3f47a09c55831d9f22826 (diff)
pm: acpi hibernation: utilize hardware signature
ACPI defines a hardware signature. BIOS calculates the signature according to hardware configure and if hardware changes while hibernated, the signature will change. In that case, S4 resume should fail. Still, there may be systems on which this mechanism does not work correctly, so it is better to provide a workaround for them. For this reason, add a new switch to the acpi_sleep= command line argument allowing one to disable hardware signature checking. [shaohua.li@intel.com: build fix] Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Cc: Andi Kleen <andi@firstfloor.org> Cc: Len Brown <lenb@kernel.org> Acked-by: Pavel Machek <pavel@ucw.cz> Cc: <Valdis.Kletnieks@vt.edu> Cc: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--arch/x86/kernel/acpi/sleep.c4
-rw-r--r--drivers/acpi/sleep/main.c22
-rw-r--r--include/linux/acpi.h1
4 files changed, 30 insertions, 1 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 4d705713cabc..497a98dafdaa 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -148,10 +148,12 @@ and is between 256 and 4096 characters. It is defined in the file
148 default: 0 148 default: 0
149 149
150 acpi_sleep= [HW,ACPI] Sleep options 150 acpi_sleep= [HW,ACPI] Sleep options
151 Format: { s3_bios, s3_mode, s3_beep, old_ordering } 151 Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering }
152 See Documentation/power/video.txt for s3_bios and s3_mode. 152 See Documentation/power/video.txt for s3_bios and s3_mode.
153 s3_beep is for debugging; it makes the PC's speaker beep 153 s3_beep is for debugging; it makes the PC's speaker beep
154 as soon as the kernel's real-mode entry point is called. 154 as soon as the kernel's real-mode entry point is called.
155 s4_nohwsig prevents ACPI hardware signature from being
156 used during resume from hibernation.
155 old_ordering causes the ACPI 1.0 ordering of the _PTS 157 old_ordering causes the ACPI 1.0 ordering of the _PTS
156 control method, wrt putting devices into low power 158 control method, wrt putting devices into low power
157 states, to be enforced (the ACPI 2.0 ordering of _PTS is 159 states, to be enforced (the ACPI 2.0 ordering of _PTS is
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index a3ddad18aaa3..fa2161d5003b 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -150,6 +150,10 @@ static int __init acpi_sleep_setup(char *str)
150 acpi_realmode_flags |= 2; 150 acpi_realmode_flags |= 2;
151 if (strncmp(str, "s3_beep", 7) == 0) 151 if (strncmp(str, "s3_beep", 7) == 0)
152 acpi_realmode_flags |= 4; 152 acpi_realmode_flags |= 4;
153#ifdef CONFIG_HIBERNATION
154 if (strncmp(str, "s4_nohwsig", 10) == 0)
155 acpi_no_s4_hw_signature();
156#endif
153 if (strncmp(str, "old_ordering", 12) == 0) 157 if (strncmp(str, "old_ordering", 12) == 0)
154 acpi_old_suspend_ordering(); 158 acpi_old_suspend_ordering();
155 str = strchr(str, ','); 159 str = strchr(str, ',');
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 0489a7d1d42c..313507accf18 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -283,6 +283,15 @@ static struct platform_suspend_ops acpi_suspend_ops_old = {
283#endif /* CONFIG_SUSPEND */ 283#endif /* CONFIG_SUSPEND */
284 284
285#ifdef CONFIG_HIBERNATION 285#ifdef CONFIG_HIBERNATION
286static unsigned long s4_hardware_signature;
287static struct acpi_table_facs *facs;
288static bool nosigcheck;
289
290void __init acpi_no_s4_hw_signature(void)
291{
292 nosigcheck = true;
293}
294
286static int acpi_hibernation_begin(void) 295static int acpi_hibernation_begin(void)
287{ 296{
288 acpi_target_sleep_state = ACPI_STATE_S4; 297 acpi_target_sleep_state = ACPI_STATE_S4;
@@ -316,6 +325,12 @@ static void acpi_hibernation_leave(void)
316 acpi_enable(); 325 acpi_enable();
317 /* Reprogram control registers and execute _BFS */ 326 /* Reprogram control registers and execute _BFS */
318 acpi_leave_sleep_state_prep(ACPI_STATE_S4); 327 acpi_leave_sleep_state_prep(ACPI_STATE_S4);
328 /* Check the hardware signature */
329 if (facs && s4_hardware_signature != facs->hardware_signature) {
330 printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
331 "cannot resume!\n");
332 panic("ACPI S4 hardware signature mismatch");
333 }
319} 334}
320 335
321static void acpi_pm_enable_gpes(void) 336static void acpi_pm_enable_gpes(void)
@@ -544,6 +559,13 @@ int __init acpi_sleep_init(void)
544 &acpi_hibernation_ops_old : &acpi_hibernation_ops); 559 &acpi_hibernation_ops_old : &acpi_hibernation_ops);
545 sleep_states[ACPI_STATE_S4] = 1; 560 sleep_states[ACPI_STATE_S4] = 1;
546 printk(" S4"); 561 printk(" S4");
562 if (!nosigcheck) {
563 acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
564 (struct acpi_table_header **)&facs);
565 if (facs)
566 s4_hardware_signature =
567 facs->hardware_signature;
568 }
547 } 569 }
548#endif 570#endif
549 status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); 571 status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index a17177639376..702f79dad16a 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -236,6 +236,7 @@ int acpi_check_mem_region(resource_size_t start, resource_size_t n,
236 const char *name); 236 const char *name);
237 237
238#ifdef CONFIG_PM_SLEEP 238#ifdef CONFIG_PM_SLEEP
239void __init acpi_no_s4_hw_signature(void);
239void __init acpi_old_suspend_ordering(void); 240void __init acpi_old_suspend_ordering(void);
240#endif /* CONFIG_PM_SLEEP */ 241#endif /* CONFIG_PM_SLEEP */
241#else /* CONFIG_ACPI */ 242#else /* CONFIG_ACPI */