diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-02-23 17:15:21 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-02-23 17:15:21 -0500 |
commit | b5d667eb392ed901fc7ae76869c7a130559e193c (patch) | |
tree | 25824b7ac66bd8c3586499e4b38aabae2e0665e5 /drivers/acpi/internal.h | |
parent | 511d5c4212948fe55035b8fed61ac0e125af5a05 (diff) |
ACPI / PM: Take unusual configurations of power resources into account
Commit d2e5f0c (ACPI / PCI: Rework the setup and cleanup of device
wakeup) moved the initial disabling of system wakeup for PCI devices
into a place where it can actually work and that exposed a hidden old
issue with crap^Wunusual system designs where the same power
resources are used for both wakeup power and device power control at
run time.
Namely, say there is one power resource such that the ACPI power
state D0 of a PCI device depends on that power resource (i.e. the
device is in D0 when that power resource is "on") and it is used
as a wakeup power resource for the same device. Then, calling
acpi_pci_sleep_wake(pci_dev, false) for the device in question will
cause the reference counter of that power resource to drop to 0,
which in turn will cause it to be turned off. As a result, the
device will go into D3cold at that point, although it should have
stayed in D0.
As it turns out, that happens to USB controllers on some laptops
and USB becomes unusable on those machines as a result, which is
a major regression from v3.8.
To fix this problem, (1) increment the reference counters of wakup
power resources during their initialization if they are "on"
initially, (2) prevent acpi_disable_wakeup_device_power() from
decrementing the reference counters of wakeup power resources that
were not enabled for wakeup power previously, and (3) prevent
acpi_enable_wakeup_device_power() from incrementing the reference
counters of wakeup power resources that already are enabled for
wakeup power.
In addition to that, if it is impossible to determine the initial
states of wakeup power resources, avoid enabling wakeup for devices
whose wakeup power depends on those power resources.
Reported-by: Dave Jones <davej@redhat.com>
Reported-by: Fabio Baltieri <fabio.baltieri@linaro.org>
Tested-by: Fabio Baltieri <fabio.baltieri@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/internal.h')
-rw-r--r-- | drivers/acpi/internal.h | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index c5a61cd6c1a5..6306d2ecb428 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
@@ -56,7 +56,7 @@ int acpi_extract_power_resources(union acpi_object *package, unsigned int start, | |||
56 | struct list_head *list); | 56 | struct list_head *list); |
57 | int acpi_add_power_resource(acpi_handle handle); | 57 | int acpi_add_power_resource(acpi_handle handle); |
58 | void acpi_power_add_remove_device(struct acpi_device *adev, bool add); | 58 | void acpi_power_add_remove_device(struct acpi_device *adev, bool add); |
59 | int acpi_power_min_system_level(struct list_head *list); | 59 | int acpi_power_wakeup_list_init(struct list_head *list, int *system_level); |
60 | int acpi_device_sleep_wake(struct acpi_device *dev, | 60 | int acpi_device_sleep_wake(struct acpi_device *dev, |
61 | int enable, int sleep_state, int dev_state); | 61 | int enable, int sleep_state, int dev_state); |
62 | int acpi_power_get_inferred_state(struct acpi_device *device, int *state); | 62 | int acpi_power_get_inferred_state(struct acpi_device *device, int *state); |