Commit 761afb86 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Len Brown

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: default avatarMatthew Garrett <mjg59@srcf.ucam.org>
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent cd07202c
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
u8 sleep_states[ACPI_S_STATE_COUNT]; u8 sleep_states[ACPI_S_STATE_COUNT];
static u32 acpi_target_sleep_state = ACPI_STATE_S0;
static void acpi_sleep_tts_switch(u32 acpi_state) static void acpi_sleep_tts_switch(u32 acpi_state)
{ {
union acpi_object in_arg = { ACPI_TYPE_INTEGER }; union acpi_object in_arg = { ACPI_TYPE_INTEGER };
...@@ -79,8 +81,6 @@ static int acpi_sleep_prepare(u32 acpi_state) ...@@ -79,8 +81,6 @@ static int acpi_sleep_prepare(u32 acpi_state)
} }
#ifdef CONFIG_ACPI_SLEEP #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 * 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 * and to restore them during the subsequent resume. Windows does that also for
...@@ -562,7 +562,7 @@ int acpi_suspend(u32 acpi_state) ...@@ -562,7 +562,7 @@ int acpi_suspend(u32 acpi_state)
return -EINVAL; return -EINVAL;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_OPS
/** /**
* acpi_pm_device_sleep_state - return preferred power state of ACPI device * acpi_pm_device_sleep_state - return preferred power state of ACPI device
* in the system sleep state given by %acpi_target_sleep_state * 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,7 +624,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
* can wake the system. _S0W may be valid, too. * can wake the system. _S0W may be valid, too.
*/ */
if (acpi_target_sleep_state == ACPI_STATE_S0 || if (acpi_target_sleep_state == ACPI_STATE_S0 ||
(device_may_wakeup(dev) && adev->wakeup.state.enabled && (device_may_wakeup(dev) &&
adev->wakeup.sleep_state <= acpi_target_sleep_state)) { adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
acpi_status status; acpi_status status;
...@@ -632,7 +632,9 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) ...@@ -632,7 +632,9 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
status = acpi_evaluate_integer(handle, acpi_method, NULL, status = acpi_evaluate_integer(handle, acpi_method, NULL,
&d_max); &d_max);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
d_max = d_min; if (acpi_target_sleep_state != ACPI_STATE_S0 ||
status != AE_NOT_FOUND)
d_max = d_min;
} else if (d_max < d_min) { } else if (d_max < d_min) {
/* Warn the user of the broken DSDT */ /* Warn the user of the broken DSDT */
printk(KERN_WARNING "ACPI: Wrong value from %s\n", 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,7 +648,9 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
*d_min_p = d_min; *d_min_p = d_min;
return d_max; return d_max;
} }
#endif /* CONFIG_PM_OPS */
#ifdef CONFIG_PM_SLEEP
/** /**
* acpi_pm_device_sleep_wake - enable or disable the system wake-up * acpi_pm_device_sleep_wake - enable or disable the system wake-up
* capability of given device * capability of given device
...@@ -677,7 +681,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) ...@@ -677,7 +681,7 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
return error; return error;
} }
#endif #endif /* CONFIG_PM_SLEEP */
static void acpi_power_off_prepare(void) static void acpi_power_off_prepare(void)
{ {
......
...@@ -389,21 +389,25 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); ...@@ -389,21 +389,25 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state); int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state);
int acpi_disable_wakeup_device_power(struct acpi_device *dev); int acpi_disable_wakeup_device_power(struct acpi_device *dev);
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_OPS
int acpi_pm_device_sleep_state(struct device *, int *); int acpi_pm_device_sleep_state(struct device *, int *);
int acpi_pm_device_sleep_wake(struct device *, bool); #else
#else /* !CONFIG_PM_SLEEP */
static inline int acpi_pm_device_sleep_state(struct device *d, int *p) static inline int acpi_pm_device_sleep_state(struct device *d, int *p)
{ {
if (p) if (p)
*p = ACPI_STATE_D0; *p = ACPI_STATE_D0;
return ACPI_STATE_D3; return ACPI_STATE_D3;
} }
#endif
#ifdef CONFIG_PM_SLEEP
int acpi_pm_device_sleep_wake(struct device *, bool);
#else
static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable) static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
{ {
return -ENODEV; return -ENODEV;
} }
#endif /* !CONFIG_PM_SLEEP */ #endif
#endif /* CONFIG_ACPI */ #endif /* CONFIG_ACPI */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment