aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2008-10-22 23:28:46 -0400
committerLen Brown <len.brown@intel.com>2008-10-22 23:28:46 -0400
commitacd41d36e5a813501da92156f325ce15ddcd58ff (patch)
treedaaca230153261b13e6d1989a977352e2c29a3d4 /drivers/acpi
parent4dff4e7f6cbcd2722b02dbb394ba87c4e05f8841 (diff)
parent4fb507b6b764195bb7821cf2baa988f6eb677d30 (diff)
Merge branch 'suspend' into test
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/hardware/hwsleep.c44
-rw-r--r--drivers/acpi/sleep/main.c59
2 files changed, 76 insertions, 27 deletions
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index dba3cfbe8cba..25dccdf179b9 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -78,19 +78,17 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
78 return_ACPI_STATUS(status); 78 return_ACPI_STATUS(status);
79 } 79 }
80 80
81 /* Set the vector */ 81 /*
82 * According to the ACPI specification 2.0c and later, the 64-bit
83 * waking vector should be cleared and the 32-bit waking vector should
84 * be used, unless we want the wake-up code to be called by the BIOS in
85 * Protected Mode. Some systems (for example HP dv5-1004nr) are known
86 * to fail to resume if the 64-bit vector is used.
87 */
88 if (facs->version >= 1)
89 facs->xfirmware_waking_vector = 0;
82 90
83 if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) { 91 facs->firmware_waking_vector = (u32)physical_address;
84 /*
85 * ACPI 1.0 FACS or short table or optional X_ field is zero
86 */
87 facs->firmware_waking_vector = (u32) physical_address;
88 } else {
89 /*
90 * ACPI 2.0 FACS with valid X_ field
91 */
92 facs->xfirmware_waking_vector = physical_address;
93 }
94 92
95 return_ACPI_STATUS(AE_OK); 93 return_ACPI_STATUS(AE_OK);
96} 94}
@@ -134,20 +132,7 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
134 } 132 }
135 133
136 /* Get the vector */ 134 /* Get the vector */
137 135 *physical_address = (acpi_physical_address)facs->firmware_waking_vector;
138 if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
139 /*
140 * ACPI 1.0 FACS or short table or optional X_ field is zero
141 */
142 *physical_address =
143 (acpi_physical_address) facs->firmware_waking_vector;
144 } else {
145 /*
146 * ACPI 2.0 FACS with valid X_ field
147 */
148 *physical_address =
149 (acpi_physical_address) facs->xfirmware_waking_vector;
150 }
151 136
152 return_ACPI_STATUS(AE_OK); 137 return_ACPI_STATUS(AE_OK);
153} 138}
@@ -627,6 +612,13 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
627 } 612 }
628 /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */ 613 /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
629 614
615 /*
616 * Some BIOSes assume that WAK_STS will be cleared on resume and use
617 * it to determine whether the system is rebooting or resuming. Clear
618 * it for compatibility.
619 */
620 acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
621
630 acpi_gbl_system_awake_and_running = TRUE; 622 acpi_gbl_system_awake_and_running = TRUE;
631 623
632 /* Enable power button */ 624 /* Enable power button */
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 4c21480b5820..cc344d4252c9 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -15,6 +15,7 @@
15#include <linux/dmi.h> 15#include <linux/dmi.h>
16#include <linux/device.h> 16#include <linux/device.h>
17#include <linux/suspend.h> 17#include <linux/suspend.h>
18#include <linux/reboot.h>
18 19
19#include <asm/io.h> 20#include <asm/io.h>
20 21
@@ -25,6 +26,36 @@
25u8 sleep_states[ACPI_S_STATE_COUNT]; 26u8 sleep_states[ACPI_S_STATE_COUNT];
26static u32 acpi_target_sleep_state = ACPI_STATE_S0; 27static u32 acpi_target_sleep_state = ACPI_STATE_S0;
27 28
29static void acpi_sleep_tts_switch(u32 acpi_state)
30{
31 union acpi_object in_arg = { ACPI_TYPE_INTEGER };
32 struct acpi_object_list arg_list = { 1, &in_arg };
33 acpi_status status = AE_OK;
34
35 in_arg.integer.value = acpi_state;
36 status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL);
37 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
38 /*
39 * OS can't evaluate the _TTS object correctly. Some warning
40 * message will be printed. But it won't break anything.
41 */
42 printk(KERN_NOTICE "Failure in evaluating _TTS object\n");
43 }
44}
45
46static int tts_notify_reboot(struct notifier_block *this,
47 unsigned long code, void *x)
48{
49 acpi_sleep_tts_switch(ACPI_STATE_S5);
50 return NOTIFY_DONE;
51}
52
53static struct notifier_block tts_notifier = {
54 .notifier_call = tts_notify_reboot,
55 .next = NULL,
56 .priority = 0,
57};
58
28static int acpi_sleep_prepare(u32 acpi_state) 59static int acpi_sleep_prepare(u32 acpi_state)
29{ 60{
30#ifdef CONFIG_ACPI_SLEEP 61#ifdef CONFIG_ACPI_SLEEP
@@ -130,6 +161,7 @@ static void acpi_pm_end(void)
130 * failing transition to a sleep state. 161 * failing transition to a sleep state.
131 */ 162 */
132 acpi_target_sleep_state = ACPI_STATE_S0; 163 acpi_target_sleep_state = ACPI_STATE_S0;
164 acpi_sleep_tts_switch(acpi_target_sleep_state);
133} 165}
134#endif /* CONFIG_ACPI_SLEEP */ 166#endif /* CONFIG_ACPI_SLEEP */
135 167
@@ -154,6 +186,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
154 186
155 if (sleep_states[acpi_state]) { 187 if (sleep_states[acpi_state]) {
156 acpi_target_sleep_state = acpi_state; 188 acpi_target_sleep_state = acpi_state;
189 acpi_sleep_tts_switch(acpi_target_sleep_state);
157 } else { 190 } else {
158 printk(KERN_ERR "ACPI does not support this state: %d\n", 191 printk(KERN_ERR "ACPI does not support this state: %d\n",
159 pm_state); 192 pm_state);
@@ -199,6 +232,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
199 break; 232 break;
200 } 233 }
201 234
235 /* If ACPI is not enabled by the BIOS, we need to enable it here. */
236 acpi_enable();
202 /* Reprogram control registers and execute _BFS */ 237 /* Reprogram control registers and execute _BFS */
203 acpi_leave_sleep_state_prep(acpi_state); 238 acpi_leave_sleep_state_prep(acpi_state);
204 239
@@ -295,6 +330,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
295 DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"), 330 DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"),
296 }, 331 },
297 }, 332 },
333 {
334 .callback = init_old_suspend_ordering,
335 .ident = "HP xw4600 Workstation",
336 .matches = {
337 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
338 DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"),
339 },
340 },
298 {}, 341 {},
299}; 342};
300#endif /* CONFIG_SUSPEND */ 343#endif /* CONFIG_SUSPEND */
@@ -312,6 +355,7 @@ void __init acpi_no_s4_hw_signature(void)
312static int acpi_hibernation_begin(void) 355static int acpi_hibernation_begin(void)
313{ 356{
314 acpi_target_sleep_state = ACPI_STATE_S4; 357 acpi_target_sleep_state = ACPI_STATE_S4;
358 acpi_sleep_tts_switch(acpi_target_sleep_state);
315 return 0; 359 return 0;
316} 360}
317 361
@@ -375,7 +419,15 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {
375 */ 419 */
376static int acpi_hibernation_begin_old(void) 420static int acpi_hibernation_begin_old(void)
377{ 421{
378 int error = acpi_sleep_prepare(ACPI_STATE_S4); 422 int error;
423 /*
424 * The _TTS object should always be evaluated before the _PTS object.
425 * When the old_suspended_ordering is true, the _PTS object is
426 * evaluated in the acpi_sleep_prepare.
427 */
428 acpi_sleep_tts_switch(ACPI_STATE_S4);
429
430 error = acpi_sleep_prepare(ACPI_STATE_S4);
379 431
380 if (!error) 432 if (!error)
381 acpi_target_sleep_state = ACPI_STATE_S4; 433 acpi_target_sleep_state = ACPI_STATE_S4;
@@ -595,5 +647,10 @@ int __init acpi_sleep_init(void)
595 pm_power_off = acpi_power_off; 647 pm_power_off = acpi_power_off;
596 } 648 }
597 printk(")\n"); 649 printk(")\n");
650 /*
651 * Register the tts_notifier to reboot notifier list so that the _TTS
652 * object can also be evaluated when the system enters S5.
653 */
654 register_reboot_notifier(&tts_notifier);
598 return 0; 655 return 0;
599} 656}