aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-07-04 07:22:11 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-21 21:21:29 -0400
commit2757f8d630ae099abc7d51b7b09de76a33876bf4 (patch)
treee0374f785b33d44f7a8890bcedeb2400ca4a6a07 /drivers/acpi
parent22a5fdfc36cd18abfd421699e9076307fa54dae4 (diff)
ACPI / PM: Fix corner case in acpi_bus_update_power()
commit 91bdad0b6237c25a7bf8fd4604d0cc64a2005a23 upstream. The role of acpi_bus_update_power() is to update the given ACPI device object's power.state field to reflect the current physical state of the device (as inferred from the configuration of power resources and _PSC, if available). For this purpose it calls acpi_device_set_power() that should update the power resources' reference counters and set power.state as appropriate. However, that doesn't work if the "new" state is D1, D2 or D3hot and the the current value of power.state means D3cold, because in that case acpi_device_set_power() will refuse to transition the device from D3cold to non-D0. To address this problem, make acpi_bus_update_power() call acpi_power_transition() directly to update the power resources' reference counters and only use acpi_device_set_power() to put the device into D0 if the current physical state of it cannot be determined. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/device_pm.c23
1 files changed, 18 insertions, 5 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 31c217a42839..553527c2532b 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -324,14 +324,27 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p)
324 if (result) 324 if (result)
325 return result; 325 return result;
326 326
327 if (state == ACPI_STATE_UNKNOWN) 327 if (state == ACPI_STATE_UNKNOWN) {
328 state = ACPI_STATE_D0; 328 state = ACPI_STATE_D0;
329 329 result = acpi_device_set_power(device, state);
330 result = acpi_device_set_power(device, state); 330 if (result)
331 if (!result && state_p) 331 return result;
332 } else {
333 if (device->power.flags.power_resources) {
334 /*
335 * We don't need to really switch the state, bu we need
336 * to update the power resources' reference counters.
337 */
338 result = acpi_power_transition(device, state);
339 if (result)
340 return result;
341 }
342 device->power.state = state;
343 }
344 if (state_p)
332 *state_p = state; 345 *state_p = state;
333 346
334 return result; 347 return 0;
335} 348}
336EXPORT_SYMBOL_GPL(acpi_bus_update_power); 349EXPORT_SYMBOL_GPL(acpi_bus_update_power);
337 350