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

Merge branch 'acpi-pm' into fixes

* acpi-pm:
  ACPI / PM: Take unusual configurations of power resources into account
parents bf900afb b5d667eb
...@@ -65,7 +65,7 @@ int acpi_extract_power_resources(union acpi_object *package, unsigned int start, ...@@ -65,7 +65,7 @@ int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
struct list_head *list); struct list_head *list);
int acpi_add_power_resource(acpi_handle handle); int 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_power_min_system_level(struct list_head *list); int acpi_power_wakeup_list_init(struct list_head *list, int *system_level);
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);
int acpi_power_get_inferred_state(struct acpi_device *device, int *state); int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
......
...@@ -73,6 +73,7 @@ struct acpi_power_resource { ...@@ -73,6 +73,7 @@ struct acpi_power_resource {
u32 system_level; u32 system_level;
u32 order; u32 order;
unsigned int ref_count; unsigned int ref_count;
bool wakeup_enabled;
struct mutex resource_lock; struct mutex resource_lock;
}; };
...@@ -272,11 +273,9 @@ static int __acpi_power_on(struct acpi_power_resource *resource) ...@@ -272,11 +273,9 @@ static int __acpi_power_on(struct acpi_power_resource *resource)
return 0; return 0;
} }
static int acpi_power_on(struct acpi_power_resource *resource) static int acpi_power_on_unlocked(struct acpi_power_resource *resource)
{ {
int result = 0;; int result = 0;
mutex_lock(&resource->resource_lock);
if (resource->ref_count++) { if (resource->ref_count++) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
...@@ -293,9 +292,16 @@ static int acpi_power_on(struct acpi_power_resource *resource) ...@@ -293,9 +292,16 @@ static int acpi_power_on(struct acpi_power_resource *resource)
schedule_work(&dep->work); schedule_work(&dep->work);
} }
} }
return result;
}
mutex_unlock(&resource->resource_lock); static int acpi_power_on(struct acpi_power_resource *resource)
{
int result;
mutex_lock(&resource->resource_lock);
result = acpi_power_on_unlocked(resource);
mutex_unlock(&resource->resource_lock);
return result; return result;
} }
...@@ -313,17 +319,15 @@ static int __acpi_power_off(struct acpi_power_resource *resource) ...@@ -313,17 +319,15 @@ static int __acpi_power_off(struct acpi_power_resource *resource)
return 0; return 0;
} }
static int acpi_power_off(struct acpi_power_resource *resource) static int acpi_power_off_unlocked(struct acpi_power_resource *resource)
{ {
int result = 0; int result = 0;
mutex_lock(&resource->resource_lock);
if (!resource->ref_count) { if (!resource->ref_count) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Power resource [%s] already off", "Power resource [%s] already off",
resource->name)); resource->name));
goto unlock; return 0;
} }
if (--resource->ref_count) { if (--resource->ref_count) {
...@@ -335,10 +339,16 @@ static int acpi_power_off(struct acpi_power_resource *resource) ...@@ -335,10 +339,16 @@ static int acpi_power_off(struct acpi_power_resource *resource)
if (result) if (result)
resource->ref_count++; resource->ref_count++;
} }
return result;
}
unlock: static int acpi_power_off(struct acpi_power_resource *resource)
mutex_unlock(&resource->resource_lock); {
int result;
mutex_lock(&resource->resource_lock);
result = acpi_power_off_unlocked(resource);
mutex_unlock(&resource->resource_lock);
return result; return result;
} }
...@@ -521,18 +531,35 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add) ...@@ -521,18 +531,35 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
} }
} }
int acpi_power_min_system_level(struct list_head *list) int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)
{ {
struct acpi_power_resource_entry *entry; struct acpi_power_resource_entry *entry;
int system_level = 5; int system_level = 5;
list_for_each_entry(entry, list, node) { list_for_each_entry(entry, list, node) {
struct acpi_power_resource *resource = entry->resource; struct acpi_power_resource *resource = entry->resource;
acpi_handle handle = resource->device.handle;
int result;
int state;
mutex_lock(&resource->resource_lock);
result = acpi_power_get_state(handle, &state);
if (result) {
mutex_unlock(&resource->resource_lock);
return result;
}
if (state == ACPI_POWER_RESOURCE_STATE_ON) {
resource->ref_count++;
resource->wakeup_enabled = true;
}
if (system_level > resource->system_level) if (system_level > resource->system_level)
system_level = resource->system_level; system_level = resource->system_level;
mutex_unlock(&resource->resource_lock);
} }
return system_level; *system_level_p = system_level;
return 0;
} }
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
...@@ -610,6 +637,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev, ...@@ -610,6 +637,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev,
*/ */
int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
{ {
struct acpi_power_resource_entry *entry;
int err = 0; int err = 0;
if (!dev || !dev->wakeup.flags.valid) if (!dev || !dev->wakeup.flags.valid)
...@@ -620,17 +648,31 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) ...@@ -620,17 +648,31 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
if (dev->wakeup.prepare_count++) if (dev->wakeup.prepare_count++)
goto out; goto out;
err = acpi_power_on_list(&dev->wakeup.resources); list_for_each_entry(entry, &dev->wakeup.resources, node) {
if (err) { struct acpi_power_resource *resource = entry->resource;
dev_err(&dev->dev, "Cannot turn wakeup power resources on\n");
dev->wakeup.flags.valid = 0; mutex_lock(&resource->resource_lock);
} else {
/* if (!resource->wakeup_enabled) {
* Passing 3 as the third argument below means the device may be err = acpi_power_on_unlocked(resource);
* put into arbitrary power state afterward. if (!err)
*/ resource->wakeup_enabled = true;
err = acpi_device_sleep_wake(dev, 1, sleep_state, 3); }
mutex_unlock(&resource->resource_lock);
if (err) {
dev_err(&dev->dev,
"Cannot turn wakeup power resources on\n");
dev->wakeup.flags.valid = 0;
goto out;
}
} }
/*
* 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);
if (err) if (err)
dev->wakeup.prepare_count = 0; dev->wakeup.prepare_count = 0;
...@@ -647,6 +689,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) ...@@ -647,6 +689,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 acpi_disable_wakeup_device_power(struct acpi_device *dev)
{ {
struct acpi_power_resource_entry *entry;
int err = 0; int err = 0;
if (!dev || !dev->wakeup.flags.valid) if (!dev || !dev->wakeup.flags.valid)
...@@ -668,10 +711,25 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) ...@@ -668,10 +711,25 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
if (err) if (err)
goto out; goto out;
err = acpi_power_off_list(&dev->wakeup.resources); list_for_each_entry(entry, &dev->wakeup.resources, node) {
if (err) { struct acpi_power_resource *resource = entry->resource;
dev_err(&dev->dev, "Cannot turn wakeup power resources off\n");
dev->wakeup.flags.valid = 0; mutex_lock(&resource->resource_lock);
if (resource->wakeup_enabled) {
err = acpi_power_off_unlocked(resource);
if (!err)
resource->wakeup_enabled = false;
}
mutex_unlock(&resource->resource_lock);
if (err) {
dev_err(&dev->dev,
"Cannot turn wakeup power resources off\n");
dev->wakeup.flags.valid = 0;
break;
}
} }
out: out:
......
...@@ -1002,7 +1002,14 @@ static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, ...@@ -1002,7 +1002,14 @@ static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
if (!list_empty(&wakeup->resources)) { if (!list_empty(&wakeup->resources)) {
int sleep_state; int sleep_state;
sleep_state = acpi_power_min_system_level(&wakeup->resources); err = acpi_power_wakeup_list_init(&wakeup->resources,
&sleep_state);
if (err) {
acpi_handle_warn(handle, "Retrieving current states "
"of wakeup power resources failed\n");
acpi_power_resources_list_free(&wakeup->resources);
goto out;
}
if (sleep_state < wakeup->sleep_state) { if (sleep_state < wakeup->sleep_state) {
acpi_handle_warn(handle, "Overriding _PRW sleep state " acpi_handle_warn(handle, "Overriding _PRW sleep state "
"(S%d) by S%d from power resources\n", "(S%d) by S%d from power resources\n",
......
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