diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/sleep.c | 21 | ||||
-rw-r--r-- | drivers/pci/pci-acpi.c | 8 |
2 files changed, 24 insertions, 5 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index fdcdbb652915..69134653909c 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -19,6 +19,7 @@ #include <linux/acpi.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/pm_qos.h> #include <asm/io.h> @@ -711,6 +712,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) struct acpi_device *adev; char acpi_method[] = "_SxD"; unsigned long long d_min, d_max; + bool wakeup = false; if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3) return -EINVAL; @@ -718,6 +720,13 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) printk(KERN_DEBUG "ACPI handle has no context!\n"); return -ENODEV; } + if (d_max_in > ACPI_STATE_D3_HOT) { + enum pm_qos_flags_status stat; + + stat = dev_pm_qos_flags(dev, PM_QOS_FLAG_NO_POWER_OFF); + if (stat == PM_QOS_FLAGS_ALL) + d_max_in = ACPI_STATE_D3_HOT; + } acpi_method[2] = '0' + acpi_target_sleep_state; /* @@ -737,8 +746,14 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer * provided -- that's our fault recovery, we ignore retval. */ - if (acpi_target_sleep_state > ACPI_STATE_S0) + if (acpi_target_sleep_state > ACPI_STATE_S0) { acpi_evaluate_integer(handle, acpi_method, NULL, &d_min); + wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid + && adev->wakeup.sleep_state >= acpi_target_sleep_state; + } else if (dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) != + PM_QOS_FLAGS_NONE) { + wakeup = adev->wakeup.flags.valid; + } /* * If _PRW says we can wake up the system from the target sleep state, @@ -747,9 +762,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) * (ACPI 3.x), it should return the maximum (lowest power) D-state that * can wake the system. _S0W may be valid, too. */ - if (acpi_target_sleep_state == ACPI_STATE_S0 || - (device_may_wakeup(dev) && adev->wakeup.flags.valid && - adev->wakeup.sleep_state >= acpi_target_sleep_state)) { + if (wakeup) { acpi_status status; acpi_method[3] = 'W'; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c5792d622dc4..63d6618a4804 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -17,6 +17,7 @@ #include <linux/pci-acpi.h> #include <linux/pm_runtime.h> +#include <linux/pm_qos.h> #include "pci.h" static DEFINE_MUTEX(pci_acpi_pm_notify_mtx); @@ -257,11 +258,16 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) return -ENODEV; switch (state) { + case PCI_D3cold: + if (dev_pm_qos_flags(&dev->dev, PM_QOS_FLAG_NO_POWER_OFF) == + PM_QOS_FLAGS_ALL) { + error = -EBUSY; + break; + } case PCI_D0: case PCI_D1: case PCI_D2: case PCI_D3hot: - case PCI_D3cold: error = acpi_bus_set_power(handle, state_conv[state]); } |