ACPI / PM: Take order attribute of wakeup power resources into account
ACPI power resources have an order attribute that should be taken
into account when turning them on and off, but it is not used now.
Modify the power resources management code to preserve the
spec-compliant ordering of wakeup power resources.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 22a3d00..242feca 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -469,7 +469,7 @@
*/
int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
{
- int i, err = 0;
+ int err = 0;
if (!dev || !dev->wakeup.flags.valid)
return -EINVAL;
@@ -479,24 +479,17 @@
if (dev->wakeup.prepare_count++)
goto out;
- /* Open power resource */
- for (i = 0; i < dev->wakeup.resources.count; i++) {
- int ret = acpi_power_on(dev->wakeup.resources.handles[i]);
- if (ret) {
- printk(KERN_ERR PREFIX "Transition power state\n");
- dev->wakeup.flags.valid = 0;
- err = -ENODEV;
- goto err_out;
- }
+ err = acpi_power_on_list(&dev->wakeup.resources);
+ if (err) {
+ dev_err(&dev->dev, "Cannot turn wakeup power resources on\n");
+ dev->wakeup.flags.valid = 0;
+ } else {
+ /*
+ * Passing 3 as the third argument below means the device may be
+ * put into arbitrary power state afterward.
+ */
+ err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
}
-
- /*
- * Passing 3 as the third argument below means the device may be placed
- * in arbitrary power state afterwards.
- */
- err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
-
- err_out:
if (err)
dev->wakeup.prepare_count = 0;
@@ -513,7 +506,7 @@
*/
int acpi_disable_wakeup_device_power(struct acpi_device *dev)
{
- int i, err = 0;
+ int err = 0;
if (!dev || !dev->wakeup.flags.valid)
return -EINVAL;
@@ -534,15 +527,10 @@
if (err)
goto out;
- /* Close power resource */
- for (i = 0; i < dev->wakeup.resources.count; i++) {
- int ret = acpi_power_off(dev->wakeup.resources.handles[i]);
- if (ret) {
- printk(KERN_ERR PREFIX "Transition power state\n");
- dev->wakeup.flags.valid = 0;
- err = -ENODEV;
- goto out;
- }
+ err = acpi_power_off_list(&dev->wakeup.resources);
+ if (err) {
+ dev_err(&dev->dev, "Cannot turn wakeup power resources off\n");
+ dev->wakeup.flags.valid = 0;
}
out:
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index d557868..e4ac46a 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -479,6 +479,9 @@
{
int i;
+ if (device->wakeup.flags.valid)
+ acpi_power_resources_list_free(&device->wakeup.resources);
+
if (!device->flags.power_manageable)
return;
@@ -902,6 +905,8 @@
if (!wakeup)
return AE_BAD_PARAMETER;
+ INIT_LIST_HEAD(&wakeup->resources);
+
/* _PRW */
status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer);
if (ACPI_FAILURE(status)) {
@@ -948,19 +953,17 @@
}
wakeup->sleep_state = element->integer.value;
- if ((package->package.count - 2) > ACPI_MAX_HANDLES) {
- status = AE_NO_MEMORY;
- goto out;
- }
- wakeup->resources.count = package->package.count - 2;
- for (i = 0; i < wakeup->resources.count; i++) {
- element = &(package->package.elements[i + 2]);
+ for (i = 2; i < package->package.count; i++) {
+ acpi_handle rhandle;
+
+ element = &(package->package.elements[i]);
if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
status = AE_BAD_DATA;
goto out;
}
-
- wakeup->resources.handles[i] = element->reference.handle;
+ rhandle = element->reference.handle;
+ acpi_add_power_resource(rhandle);
+ acpi_power_resources_list_add(rhandle, &wakeup->resources);
}
acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number);
@@ -1018,6 +1021,7 @@
status = acpi_bus_extract_wakeup_device_power_package(device->handle,
&device->wakeup);
if (ACPI_FAILURE(status)) {
+ acpi_power_resources_list_free(&device->wakeup.resources);
ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
return;
}
@@ -1491,9 +1495,11 @@
acpi_handle temp;
status = acpi_get_handle(handle, "_PRW", &temp);
- if (ACPI_SUCCESS(status))
+ if (ACPI_SUCCESS(status)) {
acpi_bus_extract_wakeup_device_power_package(handle,
&wakeup);
+ acpi_power_resources_list_free(&wakeup.resources);
+ }
return AE_CTRL_DEPTH;
}
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 32dc679..a272c31 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -242,7 +242,7 @@
acpi_handle gpe_device;
u64 gpe_number;
u64 sleep_state;
- struct acpi_handle_list resources;
+ struct list_head resources;
struct acpi_device_wakeup_flags flags;
int prepare_count;
};