aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/device_pm.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-22 06:56:04 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-22 06:56:04 -0500
commite78adb7595a9d585c60a7497345cb6eaeaaacefb (patch)
treec4b8ec0cb80d0e850e074a47bd0ff277159fe7cc /drivers/acpi/device_pm.c
parent9c0f45e388fb9f9003ea22f98b84ffbab65ba554 (diff)
ACPI / PM: Always evaluate _PSn after setting power resources
The ACPI specitication (ACPI 5, Sections 7.2.8 - 7.2.11) requires that the _PSn (n = 0..3) method, if present, be executed after the power resources for the given device power state have been set appropriately. However, acpi_device_set_power() does that only if the new power state is going to be higher-power (lower-number) than the power state the device is in already. Otherwise, the ordering is reverse to protect against situations in which _PSn might access device registers unavailable after configuring the power resources for power state Dn (D3 meaning D3hot). Such situations are very unlikely to happen, though, and _PSn may actually be implemented with the assumption that power resources have been configured for power state Dn in advance, so change the code to follow the specification literally. This change was previously porposed in a different form by Lv Zheng. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/device_pm.c')
-rw-r--r--drivers/acpi/device_pm.c46
1 files changed, 17 insertions, 29 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index d7f3908c2e88..2ce07cee0434 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -242,50 +242,38 @@ int acpi_device_set_power(struct acpi_device *device, int state)
242 cut_power = true; 242 cut_power = true;
243 } 243 }
244 244
245 if (state < device->power.state && state != ACPI_STATE_D0
246 && device->power.state >= ACPI_STATE_D3_HOT) {
247 printk(KERN_WARNING PREFIX
248 "Cannot transition to non-D0 state from D3\n");
249 return -ENODEV;
250 }
251
245 /* 252 /*
246 * Transition Power 253 * Transition Power
247 * ---------------- 254 * ----------------
248 * On transitions to a high-powered state we first apply power (via 255 * In accordance with the ACPI specification first apply power (via
249 * power resources) then evalute _PSx. Conversly for transitions to 256 * power resources) and then evalute _PSx.
250 * a lower-powered state.
251 */ 257 */
252 if (state < device->power.state) { 258 if (device->power.flags.power_resources) {
253 if (device->power.state >= ACPI_STATE_D3_HOT && 259 result = acpi_power_transition(device, state);
254 state != ACPI_STATE_D0) {
255 printk(KERN_WARNING PREFIX
256 "Cannot transition to non-D0 state from D3\n");
257 return -ENODEV;
258 }
259 if (device->power.flags.power_resources) {
260 result = acpi_power_transition(device, state);
261 if (result)
262 goto end;
263 }
264 result = acpi_dev_pm_explicit_set(device, state);
265 if (result) 260 if (result)
266 goto end; 261 goto end;
267 } else {
268 result = acpi_dev_pm_explicit_set(device, state);
269 if (result)
270 goto end;
271
272 if (device->power.flags.power_resources) {
273 result = acpi_power_transition(device, state);
274 if (result)
275 goto end;
276 }
277 } 262 }
263 result = acpi_dev_pm_explicit_set(device, state);
264 if (result)
265 goto end;
278 266
279 if (cut_power) 267 if (cut_power)
280 result = acpi_power_transition(device, ACPI_STATE_D3_COLD); 268 result = acpi_power_transition(device, ACPI_STATE_D3_COLD);
281 269
282 end: 270 end:
283 if (result) 271 if (result) {
284 printk(KERN_WARNING PREFIX 272 printk(KERN_WARNING PREFIX
285 "Device [%s] failed to transition to %s\n", 273 "Device [%s] failed to transition to %s\n",
286 device->pnp.bus_id, 274 device->pnp.bus_id,
287 acpi_power_state_string(state)); 275 acpi_power_state_string(state));
288 else { 276 } else {
289 device->power.state = state; 277 device->power.state = state;
290 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 278 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
291 "Device [%s] transitioned to %s\n", 279 "Device [%s] transitioned to %s\n",