Commit d5eefa82 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

ACPI / PM: Turn power resources on and off in the right order during resume

According to Section 7.2 of ACPI 6.0, power resources should
always be enabled and disabled in order given by the "resourceorder"
field of the corresponding Power Resource objects: "Power Resource
levels are enabled from low values to high values and are disabled
from high values to low values."

However, this is not what happens during system resume, because
in that case the enabling/disabling is carried out in the power
resource registration order which may not reflect the ordering
required by the platform.

For this reason, make the ordering of the global list of all
power resources in the system (used by the system resume code)
reflect the one given by the "resourceorder" attributes of the
Power Resource objects in the ACPI namespace and modify
acpi_resume_power_resources() to walk the list in the reverse
order when turning off the power resources that had been off
before the system was suspended.
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 20dacb71
...@@ -760,6 +760,25 @@ static void acpi_power_sysfs_remove(struct acpi_device *device) ...@@ -760,6 +760,25 @@ static void acpi_power_sysfs_remove(struct acpi_device *device)
device_remove_file(&device->dev, &dev_attr_resource_in_use); device_remove_file(&device->dev, &dev_attr_resource_in_use);
} }
static void acpi_power_add_resource_to_list(struct acpi_power_resource *resource)
{
mutex_lock(&power_resource_list_lock);
if (!list_empty(&acpi_power_resource_list)) {
struct acpi_power_resource *r;
list_for_each_entry(r, &acpi_power_resource_list, list_node)
if (r->order > resource->order) {
list_add_tail(&resource->list_node, &r->list_node);
goto out;
}
}
list_add_tail(&resource->list_node, &acpi_power_resource_list);
out:
mutex_unlock(&power_resource_list_lock);
}
int acpi_add_power_resource(acpi_handle handle) int acpi_add_power_resource(acpi_handle handle)
{ {
struct acpi_power_resource *resource; struct acpi_power_resource *resource;
...@@ -810,9 +829,7 @@ int acpi_add_power_resource(acpi_handle handle) ...@@ -810,9 +829,7 @@ int acpi_add_power_resource(acpi_handle handle)
if (!device_create_file(&device->dev, &dev_attr_resource_in_use)) if (!device_create_file(&device->dev, &dev_attr_resource_in_use))
device->remove = acpi_power_sysfs_remove; device->remove = acpi_power_sysfs_remove;
mutex_lock(&power_resource_list_lock); acpi_power_add_resource_to_list(resource);
list_add(&resource->list_node, &acpi_power_resource_list);
mutex_unlock(&power_resource_list_lock);
acpi_device_add_finalize(device); acpi_device_add_finalize(device);
return 0; return 0;
...@@ -843,7 +860,22 @@ void acpi_resume_power_resources(void) ...@@ -843,7 +860,22 @@ void acpi_resume_power_resources(void)
&& resource->ref_count) { && resource->ref_count) {
dev_info(&resource->device.dev, "Turning ON\n"); dev_info(&resource->device.dev, "Turning ON\n");
__acpi_power_on(resource); __acpi_power_on(resource);
} else if (state == ACPI_POWER_RESOURCE_STATE_ON }
mutex_unlock(&resource->resource_lock);
}
list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) {
int result, state;
mutex_lock(&resource->resource_lock);
result = acpi_power_get_state(resource->device.handle, &state);
if (result) {
mutex_unlock(&resource->resource_lock);
continue;
}
if (state == ACPI_POWER_RESOURCE_STATE_ON
&& !resource->ref_count) { && !resource->ref_count) {
dev_info(&resource->device.dev, "Turning OFF\n"); dev_info(&resource->device.dev, "Turning OFF\n");
__acpi_power_off(resource); __acpi_power_off(resource);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment