diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2010-10-14 17:24:13 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2010-10-15 16:25:15 -0400 |
commit | 761afb869f649ea23e2dea7bfe9b550d3a1b7631 (patch) | |
tree | 816a6eb04802b1befedaf07f9c1359dd4dc7a9f6 /drivers/acpi | |
parent | cd07202cc8262e1669edff0d97715f3dd9260917 (diff) |
ACPI / PM: Fix problems with acpi_pm_device_sleep_state()
There is a number of problems with acpi_pm_device_sleep_state() now.
First, if _S0W is not defined, it prevents devices from being put
into D3 by PCI runtime PM, which shouldn't happen. Second, it
shouldn't use adev->wakeup.state.enabled, because if it's set, it
only means that either the device is permanently enabled to wake up
the system, or that it has been enabled to do that through
/proc/acpi/wakeup. Finally, it should be compiled if CONFIG_PM_SLEEP
is not set, so that PCI runtime PM works correctly in that case.
Fix these problems.
Reported-by: Matthew Garrett <mjg59@srcf.ucam.org>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/sleep.c | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 4754ff6e70e6..e807f4196f89 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -27,6 +27,8 @@ | |||
27 | 27 | ||
28 | u8 sleep_states[ACPI_S_STATE_COUNT]; | 28 | u8 sleep_states[ACPI_S_STATE_COUNT]; |
29 | 29 | ||
30 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; | ||
31 | |||
30 | static void acpi_sleep_tts_switch(u32 acpi_state) | 32 | static void acpi_sleep_tts_switch(u32 acpi_state) |
31 | { | 33 | { |
32 | union acpi_object in_arg = { ACPI_TYPE_INTEGER }; | 34 | union acpi_object in_arg = { ACPI_TYPE_INTEGER }; |
@@ -79,8 +81,6 @@ static int acpi_sleep_prepare(u32 acpi_state) | |||
79 | } | 81 | } |
80 | 82 | ||
81 | #ifdef CONFIG_ACPI_SLEEP | 83 | #ifdef CONFIG_ACPI_SLEEP |
82 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; | ||
83 | |||
84 | /* | 84 | /* |
85 | * The ACPI specification wants us to save NVS memory regions during hibernation | 85 | * The ACPI specification wants us to save NVS memory regions during hibernation |
86 | * and to restore them during the subsequent resume. Windows does that also for | 86 | * and to restore them during the subsequent resume. Windows does that also for |
@@ -562,7 +562,7 @@ int acpi_suspend(u32 acpi_state) | |||
562 | return -EINVAL; | 562 | return -EINVAL; |
563 | } | 563 | } |
564 | 564 | ||
565 | #ifdef CONFIG_PM_SLEEP | 565 | #ifdef CONFIG_PM_OPS |
566 | /** | 566 | /** |
567 | * acpi_pm_device_sleep_state - return preferred power state of ACPI device | 567 | * acpi_pm_device_sleep_state - return preferred power state of ACPI device |
568 | * in the system sleep state given by %acpi_target_sleep_state | 568 | * in the system sleep state given by %acpi_target_sleep_state |
@@ -624,7 +624,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) | |||
624 | * can wake the system. _S0W may be valid, too. | 624 | * can wake the system. _S0W may be valid, too. |
625 | */ | 625 | */ |
626 | if (acpi_target_sleep_state == ACPI_STATE_S0 || | 626 | if (acpi_target_sleep_state == ACPI_STATE_S0 || |
627 | (device_may_wakeup(dev) && adev->wakeup.state.enabled && | 627 | (device_may_wakeup(dev) && |
628 | adev->wakeup.sleep_state <= acpi_target_sleep_state)) { | 628 | adev->wakeup.sleep_state <= acpi_target_sleep_state)) { |
629 | acpi_status status; | 629 | acpi_status status; |
630 | 630 | ||
@@ -632,7 +632,9 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) | |||
632 | status = acpi_evaluate_integer(handle, acpi_method, NULL, | 632 | status = acpi_evaluate_integer(handle, acpi_method, NULL, |
633 | &d_max); | 633 | &d_max); |
634 | if (ACPI_FAILURE(status)) { | 634 | if (ACPI_FAILURE(status)) { |
635 | d_max = d_min; | 635 | if (acpi_target_sleep_state != ACPI_STATE_S0 || |
636 | status != AE_NOT_FOUND) | ||
637 | d_max = d_min; | ||
636 | } else if (d_max < d_min) { | 638 | } else if (d_max < d_min) { |
637 | /* Warn the user of the broken DSDT */ | 639 | /* Warn the user of the broken DSDT */ |
638 | printk(KERN_WARNING "ACPI: Wrong value from %s\n", | 640 | printk(KERN_WARNING "ACPI: Wrong value from %s\n", |
@@ -646,7 +648,9 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) | |||
646 | *d_min_p = d_min; | 648 | *d_min_p = d_min; |
647 | return d_max; | 649 | return d_max; |
648 | } | 650 | } |
651 | #endif /* CONFIG_PM_OPS */ | ||
649 | 652 | ||
653 | #ifdef CONFIG_PM_SLEEP | ||
650 | /** | 654 | /** |
651 | * acpi_pm_device_sleep_wake - enable or disable the system wake-up | 655 | * acpi_pm_device_sleep_wake - enable or disable the system wake-up |
652 | * capability of given device | 656 | * capability of given device |
@@ -677,7 +681,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) | |||
677 | 681 | ||
678 | return error; | 682 | return error; |
679 | } | 683 | } |
680 | #endif | 684 | #endif /* CONFIG_PM_SLEEP */ |
681 | 685 | ||
682 | static void acpi_power_off_prepare(void) | 686 | static void acpi_power_off_prepare(void) |
683 | { | 687 | { |