diff options
| author | Len Brown <len.brown@intel.com> | 2008-10-22 23:28:46 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2008-10-22 23:28:46 -0400 |
| commit | acd41d36e5a813501da92156f325ce15ddcd58ff (patch) | |
| tree | daaca230153261b13e6d1989a977352e2c29a3d4 /drivers/acpi | |
| parent | 4dff4e7f6cbcd2722b02dbb394ba87c4e05f8841 (diff) | |
| parent | 4fb507b6b764195bb7821cf2baa988f6eb677d30 (diff) | |
Merge branch 'suspend' into test
Diffstat (limited to 'drivers/acpi')
| -rw-r--r-- | drivers/acpi/hardware/hwsleep.c | 44 | ||||
| -rw-r--r-- | drivers/acpi/sleep/main.c | 59 |
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 @@ | |||
| 25 | u8 sleep_states[ACPI_S_STATE_COUNT]; | 26 | u8 sleep_states[ACPI_S_STATE_COUNT]; |
| 26 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; | 27 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; |
| 27 | 28 | ||
| 29 | static 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 | |||
| 46 | static 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 | |||
| 53 | static struct notifier_block tts_notifier = { | ||
| 54 | .notifier_call = tts_notify_reboot, | ||
| 55 | .next = NULL, | ||
| 56 | .priority = 0, | ||
| 57 | }; | ||
| 58 | |||
| 28 | static int acpi_sleep_prepare(u32 acpi_state) | 59 | static 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) | |||
| 312 | static int acpi_hibernation_begin(void) | 355 | static 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 | */ |
| 376 | static int acpi_hibernation_begin_old(void) | 420 | static 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 | } |
