aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-05-20 07:58:00 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-05-29 15:20:24 -0400
commit38c92fff988d518fe80dc23d0d44d66bd7e47ddd (patch)
treec18cc469f47bf0e79f3617c59175978e60f31878
parent63a1a765dffb1e59d82c7948638e56d5f4f2e3a1 (diff)
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>
-rw-r--r--drivers/acpi/bus.c51
-rw-r--r--drivers/acpi/power.c2
2 files changed, 30 insertions, 23 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a41be56c1cc0..adceafda9c17 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -202,37 +202,44 @@ static const char *state_string(int state)
202 202
203static int __acpi_bus_get_power(struct acpi_device *device, int *state) 203static int __acpi_bus_get_power(struct acpi_device *device, int *state)
204{ 204{
205 int result = 0; 205 int result = ACPI_STATE_UNKNOWN;
206 acpi_status status = 0;
207 unsigned long long psc = 0;
208 206
209 if (!device || !state) 207 if (!device || !state)
210 return -EINVAL; 208 return -EINVAL;
211 209
212 *state = ACPI_STATE_UNKNOWN; 210 if (!device->flags.power_manageable) {
213
214 if (device->flags.power_manageable) {
215 /*
216 * Get the device's power state either directly (via _PSC) or
217 * indirectly (via power resources).
218 */
219 if (device->power.flags.power_resources) {
220 result = acpi_power_get_inferred_state(device, state);
221 if (result)
222 return result;
223 } else if (device->power.flags.explicit_get) {
224 status = acpi_evaluate_integer(device->handle, "_PSC",
225 NULL, &psc);
226 if (ACPI_FAILURE(status))
227 return -ENODEV;
228 *state = (int)psc;
229 }
230 } else {
231 /* TBD: Non-recursive algorithm for walking up hierarchy. */ 211 /* TBD: Non-recursive algorithm for walking up hierarchy. */
232 *state = device->parent ? 212 *state = device->parent ?
233 device->parent->power.state : ACPI_STATE_D0; 213 device->parent->power.state : ACPI_STATE_D0;
214 goto out;
215 }
216
217 /*
218 * Get the device's power state either directly (via _PSC) or
219 * indirectly (via power resources).
220 */
221 if (device->power.flags.explicit_get) {
222 unsigned long long psc;
223 acpi_status status = acpi_evaluate_integer(device->handle,
224 "_PSC", NULL, &psc);
225 if (ACPI_FAILURE(status))
226 return -ENODEV;
227
228 result = psc;
229 }
230 /* The test below covers ACPI_STATE_UNKNOWN too. */
231 if (result <= ACPI_STATE_D2) {
232 ; /* Do nothing. */
233 } else if (device->power.flags.power_resources) {
234 int error = acpi_power_get_inferred_state(device, &result);
235 if (error)
236 return error;
237 } else if (result == ACPI_STATE_D3_HOT) {
238 result = ACPI_STATE_D3;
234 } 239 }
240 *state = result;
235 241
242 out:
236 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n", 243 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
237 device->pnp.bus_id, state_string(*state))); 244 device->pnp.bus_id, state_string(*state)));
238 245
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 0500f719f63e..dd6d6a3c6780 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -631,7 +631,7 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
631 * We know a device's inferred power state when all the resources 631 * We know a device's inferred power state when all the resources
632 * required for a given D-state are 'on'. 632 * required for a given D-state are 'on'.
633 */ 633 */
634 for (i = ACPI_STATE_D0; i < ACPI_STATE_D3_HOT; i++) { 634 for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
635 list = &device->power.states[i].resources; 635 list = &device->power.states[i].resources;
636 if (list->count < 1) 636 if (list->count < 1)
637 continue; 637 continue;