Skip to content

Commit

Permalink
ACPI / PM: Take order attribute of wakeup power resources into account
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Rafael J. Wysocki committed Jan 17, 2013
1 parent 0b22452 commit 993cbe5
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 39 deletions.
44 changes: 16 additions & 28 deletions drivers/acpi/power.c
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev,
*/
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;
Expand All @@ -479,24 +479,17 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
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;

Expand All @@ -513,7 +506,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
*/
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;
Expand All @@ -534,15 +527,10 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
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:
Expand Down
26 changes: 16 additions & 10 deletions drivers/acpi/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,9 @@ static void acpi_free_power_resources_lists(struct acpi_device *device)
{
int i;

if (device->wakeup.flags.valid)
acpi_power_resources_list_free(&device->wakeup.resources);

if (!device->flags.power_manageable)
return;

Expand Down Expand Up @@ -902,6 +905,8 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
if (!wakeup)
return AE_BAD_PARAMETER;

INIT_LIST_HEAD(&wakeup->resources);

/* _PRW */
status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer);
if (ACPI_FAILURE(status)) {
Expand Down Expand Up @@ -948,19 +953,17 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
}
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);
Expand Down Expand Up @@ -1018,6 +1021,7 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
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;
}
Expand Down Expand Up @@ -1491,9 +1495,11 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
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;
}

Expand Down
2 changes: 1 addition & 1 deletion include/acpi/acpi_bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ struct acpi_device_wakeup {
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;
};
Expand Down

0 comments on commit 993cbe5

Please sign in to comment.