Skip to content

Commit

Permalink
ACPI / PM: Make __acpi_bus_get_power() cover D3cold correctly
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Rafael J. Wysocki committed May 29, 2012
1 parent 63a1a76 commit 38c92ff
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 23 deletions.
51 changes: 29 additions & 22 deletions drivers/acpi/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)));

Expand Down
2 changes: 1 addition & 1 deletion drivers/acpi/power.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 38c92ff

Please sign in to comment.