ACPI / PM: Make __acpi_bus_get_power() cover D3cold correctly
After recent changes of the ACPI device power states definitions, if power resources are not used for the device's power management, the state returned by __acpi_bus_get_power() cannot exceed D3hot, because the return values of _PSC are 0 through 3. However, if the _PR3 method is not present for the device and _PS3 returns 3, we have to assume that the device is in D3cold, so the value returned by __acpi_bus_get_power() in that case should be 4. Similarly, acpi_power_get_inferred_state() should take the power resources for the D3hot state into account in general, so that it can return 3 if those resources are "on" or 4 (D3cold) otherwise. Fix the the above two issues and make sure that if both _PSC and _PR3 are present for the device, the power resources listed by _PR3 will be used to determine if the number 3 returned by _PSC is meant to represent D3cold or D3hot. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
This commit is contained in:
Родитель
63a1a765df
Коммит
38c92fff98
|
@ -202,37 +202,44 @@ static const char *state_string(int state)
|
|||
|
||||
static int __acpi_bus_get_power(struct acpi_device *device, int *state)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = 0;
|
||||
unsigned long long psc = 0;
|
||||
int result = ACPI_STATE_UNKNOWN;
|
||||
|
||||
if (!device || !state)
|
||||
return -EINVAL;
|
||||
|
||||
*state = ACPI_STATE_UNKNOWN;
|
||||
|
||||
if (device->flags.power_manageable) {
|
||||
/*
|
||||
* Get the device's power state either directly (via _PSC) or
|
||||
* indirectly (via power resources).
|
||||
*/
|
||||
if (device->power.flags.power_resources) {
|
||||
result = acpi_power_get_inferred_state(device, state);
|
||||
if (result)
|
||||
return result;
|
||||
} else if (device->power.flags.explicit_get) {
|
||||
status = acpi_evaluate_integer(device->handle, "_PSC",
|
||||
NULL, &psc);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
*state = (int)psc;
|
||||
}
|
||||
} else {
|
||||
if (!device->flags.power_manageable) {
|
||||
/* TBD: Non-recursive algorithm for walking up hierarchy. */
|
||||
*state = device->parent ?
|
||||
device->parent->power.state : ACPI_STATE_D0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the device's power state either directly (via _PSC) or
|
||||
* indirectly (via power resources).
|
||||
*/
|
||||
if (device->power.flags.explicit_get) {
|
||||
unsigned long long psc;
|
||||
acpi_status status = acpi_evaluate_integer(device->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;
|
||||
}
|
||||
*state = result;
|
||||
|
||||
out:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
|
||||
device->pnp.bus_id, state_string(*state)));
|
||||
|
||||
|
|
|
@ -631,7 +631,7 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
|
|||
* We know a device's inferred power state when all the resources
|
||||
* required for a given D-state are 'on'.
|
||||
*/
|
||||
for (i = ACPI_STATE_D0; i < ACPI_STATE_D3_HOT; i++) {
|
||||
for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
|
||||
list = &device->power.states[i].resources;
|
||||
if (list->count < 1)
|
||||
continue;
|
||||
|
|
Загрузка…
Ссылка в новой задаче