aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-06-15 18:37:59 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-06-19 17:37:08 -0400
commitfa1675b56537651270e79967b7f1ee4202c83bf6 (patch)
tree0c294f009d636378d79fd8300bb5c936ffdb656f /drivers/acpi
parent4c164ae7d8a7ee1f39b773d97794535c2c193b12 (diff)
ACPI / PM: Rework and clean up acpi_dev_pm_get_state()
The acpi_dev_pm_get_state() function defined in device_pm.c is quite convoluted, which isn't really necessary, and it doesn't validate the values returned by the ACPI methods executed by it appropriately. To address these shortcomings modify it in the following way. (1) Make its return value only mean whether or not it succeeded and pass the device power states determined by it through pointers. (2) Drop the d_max_in argument, used by only one of its callers, from it, and move the code related to d_max_in into that caller, acpi_pm_device_sleep_state(). (3) Make it always check the return value of acpi_evaluate_integer() and handle failures as appropriate. Moreover, make it check if the values returned by the executed ACPI methods are not out of range. (4) Make it check if the values returned by the executed ACPI methods represent valid power states of the given device and handle situations in which that's not the case gracefully. Also update the kerneldoc comments of acpi_dev_pm_get_state() and acpi_pm_device_sleep_state() to reflect the code changes. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/device_pm.c158
1 files changed, 92 insertions, 66 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index afc808e93855..fd363b57a596 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -403,44 +403,37 @@ EXPORT_SYMBOL(acpi_bus_can_wakeup);
403 * @dev: Device whose preferred target power state to return. 403 * @dev: Device whose preferred target power state to return.
404 * @adev: ACPI device node corresponding to @dev. 404 * @adev: ACPI device node corresponding to @dev.
405 * @target_state: System state to match the resultant device state. 405 * @target_state: System state to match the resultant device state.
406 * @d_max_in: Deepest low-power state to take into consideration. 406 * @d_min_p: Location to store the highest power state available to the device.
407 * @d_min_p: Location to store the upper limit of the allowed states range. 407 * @d_max_p: Location to store the lowest power state available to the device.
408 * Return value: Preferred power state of the device on success, -ENODEV
409 * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure
410 * 408 *
411 * Find the lowest power (highest number) ACPI device power state that the 409 * Find the lowest power (highest number) and highest power (lowest number) ACPI
412 * device can be in while the system is in the state represented by 410 * device power states that the device can be in while the system is in the
413 * @target_state. If @d_min_p is set, the highest power (lowest number) device 411 * state represented by @target_state. Store the integer numbers representing
414 * power state that @dev can be in for the given system sleep state is stored 412 * those stats in the memory locations pointed to by @d_max_p and @d_min_p,
415 * at the location pointed to by it. 413 * respectively.
416 * 414 *
417 * Callers must ensure that @dev and @adev are valid pointers and that @adev 415 * Callers must ensure that @dev and @adev are valid pointers and that @adev
418 * actually corresponds to @dev before using this function. 416 * actually corresponds to @dev before using this function.
417 *
418 * Returns 0 on success or -ENODATA when one of the ACPI methods fails or
419 * returns a value that doesn't make sense. The memory locations pointed to by
420 * @d_max_p and @d_min_p are only modified on success.
419 */ 421 */
420static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev, 422static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
421 u32 target_state, int d_max_in, int *d_min_p) 423 u32 target_state, int *d_min_p, int *d_max_p)
422{ 424{
423 char acpi_method[] = "_SxD"; 425 char method[] = { '_', 'S', '0' + target_state, 'D', '\0' };
424 unsigned long long d_min, d_max; 426 acpi_handle handle = adev->handle;
427 unsigned long long ret;
428 int d_min, d_max;
425 bool wakeup = false; 429 bool wakeup = false;
430 acpi_status status;
426 431
427 if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3_COLD)
428 return -EINVAL;
429
430 if (d_max_in > ACPI_STATE_D3_HOT) {
431 enum pm_qos_flags_status stat;
432
433 stat = dev_pm_qos_flags(dev, PM_QOS_FLAG_NO_POWER_OFF);
434 if (stat == PM_QOS_FLAGS_ALL)
435 d_max_in = ACPI_STATE_D3_HOT;
436 }
437
438 acpi_method[2] = '0' + target_state;
439 /* 432 /*
440 * If the sleep state is S0, the lowest limit from ACPI is D3, 433 * If the system state is S0, the lowest power state the device can be
441 * but if the device has _S0W, we will use the value from _S0W 434 * in is D3cold, unless the device has _S0W and is supposed to signal
442 * as the lowest limit from ACPI. Finally, we will constrain 435 * wakeup, in which case the return value of _S0W has to be used as the
443 * the lowest limit with the specified one. 436 * lowest power state available to the device.
444 */ 437 */
445 d_min = ACPI_STATE_D0; 438 d_min = ACPI_STATE_D0;
446 d_max = ACPI_STATE_D3_COLD; 439 d_max = ACPI_STATE_D3_COLD;
@@ -449,12 +442,30 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
449 * If present, _SxD methods return the minimum D-state (highest power 442 * If present, _SxD methods return the minimum D-state (highest power
450 * state) we can use for the corresponding S-states. Otherwise, the 443 * state) we can use for the corresponding S-states. Otherwise, the
451 * minimum D-state is D0 (ACPI 3.x). 444 * minimum D-state is D0 (ACPI 3.x).
452 *
453 * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer
454 * provided -- that's our fault recovery, we ignore retval.
455 */ 445 */
456 if (target_state > ACPI_STATE_S0) { 446 if (target_state > ACPI_STATE_S0) {
457 acpi_evaluate_integer(adev->handle, acpi_method, NULL, &d_min); 447 /*
448 * We rely on acpi_evaluate_integer() not clobbering the integer
449 * provided if AE_NOT_FOUND is returned.
450 */
451 ret = d_min;
452 status = acpi_evaluate_integer(handle, method, NULL, &ret);
453 if ((ACPI_FAILURE(status) && status != AE_NOT_FOUND)
454 || ret > ACPI_STATE_D3_COLD)
455 return -ENODATA;
456
457 /*
458 * We need to handle legacy systems where D3hot and D3cold are
459 * the same and 3 is returned in both cases, so fall back to
460 * D3cold if D3hot is not a valid state.
461 */
462 if (!adev->power.states[ret].flags.valid) {
463 if (ret == ACPI_STATE_D3_HOT)
464 ret = ACPI_STATE_D3_COLD;
465 else
466 return -ENODATA;
467 }
468 d_min = ret;
458 wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid 469 wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid
459 && adev->wakeup.sleep_state >= target_state; 470 && adev->wakeup.sleep_state >= target_state;
460 } else if (dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) != 471 } else if (dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) !=
@@ -470,36 +481,29 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
470 * can wake the system. _S0W may be valid, too. 481 * can wake the system. _S0W may be valid, too.
471 */ 482 */
472 if (wakeup) { 483 if (wakeup) {
473 acpi_status status; 484 method[3] = 'W';
474 485 status = acpi_evaluate_integer(handle, method, NULL, &ret);
475 acpi_method[3] = 'W'; 486 if (status == AE_NOT_FOUND) {
476 status = acpi_evaluate_integer(adev->handle, acpi_method, NULL, 487 if (target_state > ACPI_STATE_S0)
477 &d_max);
478 if (ACPI_FAILURE(status)) {
479 if (target_state != ACPI_STATE_S0 ||
480 status != AE_NOT_FOUND)
481 d_max = d_min; 488 d_max = d_min;
482 } else if (d_max < d_min) { 489 } else if (ACPI_SUCCESS(status) && ret <= ACPI_STATE_D3_COLD) {
483 /* Warn the user of the broken DSDT */ 490 /* Fall back to D3cold if ret is not a valid state. */
484 printk(KERN_WARNING "ACPI: Wrong value from %s\n", 491 if (!adev->power.states[ret].flags.valid)
485 acpi_method); 492 ret = ACPI_STATE_D3_COLD;
486 /* Sanitize it */ 493
487 d_min = d_max; 494 d_max = ret > d_min ? ret : d_min;
495 } else {
496 return -ENODATA;
488 } 497 }
489 } 498 }
490 499
491 if (d_max_in < d_min)
492 return -EINVAL;
493 if (d_min_p) 500 if (d_min_p)
494 *d_min_p = d_min; 501 *d_min_p = d_min;
495 /* constrain d_max with specified lowest limit (max number) */ 502
496 if (d_max > d_max_in) { 503 if (d_max_p)
497 for (d_max = d_max_in; d_max > d_min; d_max--) { 504 *d_max_p = d_max;
498 if (adev->power.states[d_max].flags.valid) 505
499 break; 506 return 0;
500 }
501 }
502 return d_max;
503} 507}
504 508
505/** 509/**
@@ -508,7 +512,8 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
508 * @d_min_p: Location to store the upper limit of the allowed states range. 512 * @d_min_p: Location to store the upper limit of the allowed states range.
509 * @d_max_in: Deepest low-power state to take into consideration. 513 * @d_max_in: Deepest low-power state to take into consideration.
510 * Return value: Preferred power state of the device on success, -ENODEV 514 * Return value: Preferred power state of the device on success, -ENODEV
511 * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure 515 * if there's no 'struct acpi_device' for @dev, -EINVAL if @d_max_in is
516 * incorrect, or -ENODATA on ACPI method failure.
512 * 517 *
513 * The caller must ensure that @dev is valid before using this function. 518 * The caller must ensure that @dev is valid before using this function.
514 */ 519 */
@@ -516,14 +521,39 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in)
516{ 521{
517 acpi_handle handle = DEVICE_ACPI_HANDLE(dev); 522 acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
518 struct acpi_device *adev; 523 struct acpi_device *adev;
524 int ret, d_max;
525
526 if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3_COLD)
527 return -EINVAL;
528
529 if (d_max_in > ACPI_STATE_D3_HOT) {
530 enum pm_qos_flags_status stat;
531
532 stat = dev_pm_qos_flags(dev, PM_QOS_FLAG_NO_POWER_OFF);
533 if (stat == PM_QOS_FLAGS_ALL)
534 d_max_in = ACPI_STATE_D3_HOT;
535 }
519 536
520 if (!handle || acpi_bus_get_device(handle, &adev)) { 537 if (!handle || acpi_bus_get_device(handle, &adev)) {
521 dev_dbg(dev, "ACPI handle without context in %s!\n", __func__); 538 dev_dbg(dev, "ACPI handle without context in %s!\n", __func__);
522 return -ENODEV; 539 return -ENODEV;
523 } 540 }
524 541
525 return acpi_dev_pm_get_state(dev, adev, acpi_target_system_state(), 542 ret = acpi_dev_pm_get_state(dev, adev, acpi_target_system_state(),
526 d_max_in, d_min_p); 543 d_min_p, &d_max);
544 if (ret)
545 return ret;
546
547 if (d_max_in < *d_min_p)
548 return -EINVAL;
549
550 if (d_max > d_max_in) {
551 for (d_max = d_max_in; d_max > *d_min_p; d_max--) {
552 if (adev->power.states[d_max].flags.valid)
553 break;
554 }
555 }
556 return d_max;
527} 557}
528EXPORT_SYMBOL(acpi_pm_device_sleep_state); 558EXPORT_SYMBOL(acpi_pm_device_sleep_state);
529 559
@@ -674,17 +704,13 @@ struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
674static int acpi_dev_pm_low_power(struct device *dev, struct acpi_device *adev, 704static int acpi_dev_pm_low_power(struct device *dev, struct acpi_device *adev,
675 u32 system_state) 705 u32 system_state)
676{ 706{
677 int power_state; 707 int ret, state;
678 708
679 if (!acpi_device_power_manageable(adev)) 709 if (!acpi_device_power_manageable(adev))
680 return 0; 710 return 0;
681 711
682 power_state = acpi_dev_pm_get_state(dev, adev, system_state, 712 ret = acpi_dev_pm_get_state(dev, adev, system_state, NULL, &state);
683 ACPI_STATE_D3_COLD, NULL); 713 return ret ? ret : acpi_device_set_power(adev, state);
684 if (power_state < ACPI_STATE_D0 || power_state > ACPI_STATE_D3_COLD)
685 return -EIO;
686
687 return acpi_device_set_power(adev, power_state);
688} 714}
689 715
690/** 716/**