diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-04-08 12:31:48 +0200 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-04-08 12:31:48 +0200 |
commit | 077f893bd942b23d8e27c90f8f60018ce21010a0 (patch) | |
tree | df5511c5249cbc2b08edd5546cc32848061a7aac | |
parent | 6912897d7574d780994ac9a531f76c5df1669aeb (diff) | |
parent | 75eb2d13acca49c3c4f1c96fb04d6c9fd6013e78 (diff) |
Merge branch 'acpi-pm' into linux-next
* acpi-pm:
ACPI / PM: Fix potential problem in acpi_device_get_power()
-rw-r--r-- | drivers/acpi/device_pm.c | 39 |
1 files changed, 24 insertions, 15 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index dd314ef9bff1..96de787e6104 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -145,27 +145,36 @@ int acpi_device_get_power(struct acpi_device *device, int *state) } /* - * Get the device's power state either directly (via _PSC) or - * indirectly (via power resources). + * Get the device's power state from power resources settings and _PSC, + * if available. */ + if (device->power.flags.power_resources) { + int error = acpi_power_get_inferred_state(device, &result); + if (error) + return error; + } if (device->power.flags.explicit_get) { + acpi_handle handle = device->handle; unsigned long long psc; - acpi_status status = acpi_evaluate_integer(device->handle, - "_PSC", NULL, &psc); + acpi_status status; + + status = acpi_evaluate_integer(handle, "_PSC", NULL, &psc); if (ACPI_FAILURE(status)) return -ENODEV; - result = psc; - } - /* The test below covers ACPI_STATE_UNKNOWN too. */ - if (result <= ACPI_STATE_D2) { - ; /* Do nothing. */ - } else if (device->power.flags.power_resources) { - int error = acpi_power_get_inferred_state(device, &result); - if (error) - return error; - } else if (result == ACPI_STATE_D3_HOT) { - result = ACPI_STATE_D3; + /* + * The power resources settings may indicate a power state + * shallower than the actual power state of the device. + * + * Moreover, on systems predating ACPI 4.0, if the device + * doesn't depend on any power resources and _PSC returns 3, + * that means "power off". We need to maintain compatibility + * with those systems. + */ + if (psc > result && psc < ACPI_STATE_D3_COLD) + result = psc; + else if (result == ACPI_STATE_UNKNOWN) + result = psc > ACPI_STATE_D2 ? ACPI_STATE_D3_COLD : psc; } /* |