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

ACPI: Take power resource initialization errors into account

Some ACPI power resource initialization errors, like memory
allocation errors, are not taken into account appropriately in some
cases, which may lead to a device having an incomplete list of power
resources that one of its power states depends on, for one example.

Rework the power resource initialization and namespace scanning code
so that power resource initialization errors are treated more
seriously.
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent ef85bdbe
...@@ -51,10 +51,9 @@ void acpi_free_ids(struct acpi_device *device); ...@@ -51,10 +51,9 @@ void acpi_free_ids(struct acpi_device *device);
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
int acpi_power_init(void); int acpi_power_init(void);
void acpi_power_resources_list_free(struct list_head *list); void acpi_power_resources_list_free(struct list_head *list);
acpi_status acpi_extract_power_resources(union acpi_object *package, int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
unsigned int start, struct list_head *list);
struct list_head *list); int acpi_add_power_resource(acpi_handle handle);
void acpi_add_power_resource(acpi_handle handle);
void acpi_power_add_remove_device(struct acpi_device *adev, bool add); void acpi_power_add_remove_device(struct acpi_device *adev, bool add);
int acpi_device_sleep_wake(struct acpi_device *dev, int acpi_device_sleep_wake(struct acpi_device *dev,
int enable, int sleep_state, int dev_state); int enable, int sleep_state, int dev_state);
......
...@@ -97,18 +97,18 @@ static struct acpi_power_resource *acpi_power_get_context(acpi_handle handle) ...@@ -97,18 +97,18 @@ static struct acpi_power_resource *acpi_power_get_context(acpi_handle handle)
return container_of(device, struct acpi_power_resource, device); return container_of(device, struct acpi_power_resource, device);
} }
static void acpi_power_resources_list_add(acpi_handle handle, static int acpi_power_resources_list_add(acpi_handle handle,
struct list_head *list) struct list_head *list)
{ {
struct acpi_power_resource *resource = acpi_power_get_context(handle); struct acpi_power_resource *resource = acpi_power_get_context(handle);
struct acpi_power_resource_entry *entry; struct acpi_power_resource_entry *entry;
if (!resource || !list) if (!resource || !list)
return; return -EINVAL;
entry = kzalloc(sizeof(*entry), GFP_KERNEL); entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) if (!entry)
return; return -ENOMEM;
entry->resource = resource; entry->resource = resource;
if (!list_empty(list)) { if (!list_empty(list)) {
...@@ -117,10 +117,11 @@ static void acpi_power_resources_list_add(acpi_handle handle, ...@@ -117,10 +117,11 @@ static void acpi_power_resources_list_add(acpi_handle handle,
list_for_each_entry(e, list, node) list_for_each_entry(e, list, node)
if (e->resource->order > resource->order) { if (e->resource->order > resource->order) {
list_add_tail(&entry->node, &e->node); list_add_tail(&entry->node, &e->node);
return; return 0;
} }
} }
list_add_tail(&entry->node, list); list_add_tail(&entry->node, list);
return 0;
} }
void acpi_power_resources_list_free(struct list_head *list) void acpi_power_resources_list_free(struct list_head *list)
...@@ -133,33 +134,37 @@ void acpi_power_resources_list_free(struct list_head *list) ...@@ -133,33 +134,37 @@ void acpi_power_resources_list_free(struct list_head *list)
} }
} }
acpi_status acpi_extract_power_resources(union acpi_object *package, int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
unsigned int start, struct list_head *list)
struct list_head *list)
{ {
acpi_status status = AE_OK;
unsigned int i; unsigned int i;
int err = 0;
for (i = start; i < package->package.count; i++) { for (i = start; i < package->package.count; i++) {
union acpi_object *element = &package->package.elements[i]; union acpi_object *element = &package->package.elements[i];
acpi_handle rhandle; acpi_handle rhandle;
if (element->type != ACPI_TYPE_LOCAL_REFERENCE) { if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
status = AE_BAD_DATA; err = -ENODATA;
break; break;
} }
rhandle = element->reference.handle; rhandle = element->reference.handle;
if (!rhandle) { if (!rhandle) {
status = AE_NULL_ENTRY; err = -ENODEV;
break; break;
} }
acpi_add_power_resource(rhandle); err = acpi_add_power_resource(rhandle);
acpi_power_resources_list_add(rhandle, list); if (err)
break;
err = acpi_power_resources_list_add(rhandle, list);
if (err)
break;
} }
if (ACPI_FAILURE(status)) if (err)
acpi_power_resources_list_free(list); acpi_power_resources_list_free(list);
return status; return err;
} }
static int acpi_power_get_state(acpi_handle handle, int *state) static int acpi_power_get_state(acpi_handle handle, int *state)
...@@ -662,7 +667,7 @@ static void acpi_release_power_resource(struct device *dev) ...@@ -662,7 +667,7 @@ static void acpi_release_power_resource(struct device *dev)
kfree(resource); kfree(resource);
} }
void 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;
struct acpi_device *device = NULL; struct acpi_device *device = NULL;
...@@ -673,11 +678,11 @@ void acpi_add_power_resource(acpi_handle handle) ...@@ -673,11 +678,11 @@ void acpi_add_power_resource(acpi_handle handle)
acpi_bus_get_device(handle, &device); acpi_bus_get_device(handle, &device);
if (device) if (device)
return; return 0;
resource = kzalloc(sizeof(*resource), GFP_KERNEL); resource = kzalloc(sizeof(*resource), GFP_KERNEL);
if (!resource) if (!resource)
return; return -ENOMEM;
device = &resource->device; device = &resource->device;
acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER, acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER,
...@@ -712,10 +717,11 @@ void acpi_add_power_resource(acpi_handle handle) ...@@ -712,10 +717,11 @@ void acpi_add_power_resource(acpi_handle handle)
mutex_lock(&power_resource_list_lock); mutex_lock(&power_resource_list_lock);
list_add(&resource->list_node, &acpi_power_resource_list); list_add(&resource->list_node, &acpi_power_resource_list);
mutex_unlock(&power_resource_list_lock); mutex_unlock(&power_resource_list_lock);
return; return 0;
err: err:
acpi_release_power_resource(&device->dev); acpi_release_power_resource(&device->dev);
return result;
} }
#ifdef CONFIG_ACPI_SLEEP #ifdef CONFIG_ACPI_SLEEP
......
...@@ -892,17 +892,17 @@ void acpi_bus_data_handler(acpi_handle handle, void *context) ...@@ -892,17 +892,17 @@ void acpi_bus_data_handler(acpi_handle handle, void *context)
return; return;
} }
static acpi_status static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, struct acpi_device_wakeup *wakeup)
struct acpi_device_wakeup *wakeup)
{ {
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package = NULL; union acpi_object *package = NULL;
union acpi_object *element = NULL; union acpi_object *element = NULL;
acpi_status status; acpi_status status;
int err = -ENODATA;
if (!wakeup) if (!wakeup)
return AE_BAD_PARAMETER; return -EINVAL;
INIT_LIST_HEAD(&wakeup->resources); INIT_LIST_HEAD(&wakeup->resources);
...@@ -910,29 +910,25 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, ...@@ -910,29 +910,25 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer); status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
return status; return err;
} }
package = (union acpi_object *)buffer.pointer; package = (union acpi_object *)buffer.pointer;
if (!package || (package->package.count < 2)) { if (!package || package->package.count < 2)
status = AE_BAD_DATA;
goto out; goto out;
}
element = &(package->package.elements[0]); element = &(package->package.elements[0]);
if (!element) { if (!element)
status = AE_BAD_DATA;
goto out; goto out;
}
if (element->type == ACPI_TYPE_PACKAGE) { if (element->type == ACPI_TYPE_PACKAGE) {
if ((element->package.count < 2) || if ((element->package.count < 2) ||
(element->package.elements[0].type != (element->package.elements[0].type !=
ACPI_TYPE_LOCAL_REFERENCE) ACPI_TYPE_LOCAL_REFERENCE)
|| (element->package.elements[1].type != ACPI_TYPE_INTEGER)) { || (element->package.elements[1].type != ACPI_TYPE_INTEGER))
status = AE_BAD_DATA;
goto out; goto out;
}
wakeup->gpe_device = wakeup->gpe_device =
element->package.elements[0].reference.handle; element->package.elements[0].reference.handle;
wakeup->gpe_number = wakeup->gpe_number =
...@@ -941,27 +937,24 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, ...@@ -941,27 +937,24 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
wakeup->gpe_device = NULL; wakeup->gpe_device = NULL;
wakeup->gpe_number = element->integer.value; wakeup->gpe_number = element->integer.value;
} else { } else {
status = AE_BAD_DATA;
goto out; goto out;
} }
element = &(package->package.elements[1]); element = &(package->package.elements[1]);
if (element->type != ACPI_TYPE_INTEGER) { if (element->type != ACPI_TYPE_INTEGER)
status = AE_BAD_DATA;
goto out; goto out;
}
wakeup->sleep_state = element->integer.value; wakeup->sleep_state = element->integer.value;
status = acpi_extract_power_resources(package, 2, &wakeup->resources); err = acpi_extract_power_resources(package, 2, &wakeup->resources);
if (ACPI_FAILURE(status)) if (err)
goto out; goto out;
acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number); acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number);
out: out:
kfree(buffer.pointer); kfree(buffer.pointer);
return err;
return status;
} }
static void acpi_bus_set_run_wake_flags(struct acpi_device *device) static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
...@@ -1001,17 +994,17 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) ...@@ -1001,17 +994,17 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
{ {
acpi_handle temp; acpi_handle temp;
acpi_status status = 0; acpi_status status = 0;
int psw_error; int err;
/* Presence of _PRW indicates wake capable */ /* Presence of _PRW indicates wake capable */
status = acpi_get_handle(device->handle, "_PRW", &temp); status = acpi_get_handle(device->handle, "_PRW", &temp);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return; return;
status = acpi_bus_extract_wakeup_device_power_package(device->handle, err = acpi_bus_extract_wakeup_device_power_package(device->handle,
&device->wakeup); &device->wakeup);
if (ACPI_FAILURE(status)) { if (err) {
ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); dev_err(&device->dev, "_PRW evaluation error: %d\n", err);
return; return;
} }
...@@ -1024,8 +1017,8 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) ...@@ -1024,8 +1017,8 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
* So it is necessary to call _DSW object first. Only when it is not * So it is necessary to call _DSW object first. Only when it is not
* present will the _PSW object used. * present will the _PSW object used.
*/ */
psw_error = acpi_device_sleep_wake(device, 0, 0, 0); err = acpi_device_sleep_wake(device, 0, 0, 0);
if (psw_error) if (err)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"error in _DSW or _PSW evaluation\n")); "error in _DSW or _PSW evaluation\n"));
} }
...@@ -1048,9 +1041,9 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state) ...@@ -1048,9 +1041,9 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
if (buffer.length && package if (buffer.length && package
&& package->type == ACPI_TYPE_PACKAGE && package->type == ACPI_TYPE_PACKAGE
&& package->package.count) { && package->package.count) {
status = acpi_extract_power_resources(package, 0, int err = acpi_extract_power_resources(package, 0,
&ps->resources); &ps->resources);
if (ACPI_SUCCESS(status)) if (!err)
device->power.flags.power_resources = 1; device->power.flags.power_resources = 1;
} }
ACPI_FREE(buffer.pointer); ACPI_FREE(buffer.pointer);
......
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