Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 350912
b: refs/heads/master
c: bc9b640
h: refs/heads/master
v: v3
  • Loading branch information
Rafael J. Wysocki committed Jan 17, 2013
1 parent d81a1fa commit 5b6f704
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 156 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6a8dd80821c215bc49bf6b108e85c1738c82bf43
refs/heads/master: bc9b6407bd6df3ab7189e5622816bbc11ae9d2d8
56 changes: 56 additions & 0 deletions trunk/drivers/acpi/device_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -665,3 +665,59 @@ void acpi_dev_pm_detach(struct device *dev, bool power_off)
}
}
EXPORT_SYMBOL_GPL(acpi_dev_pm_detach);

/**
* acpi_dev_pm_add_dependent - Add physical device depending for PM.
* @handle: Handle of ACPI device node.
* @depdev: Device depending on that node for PM.
*/
void acpi_dev_pm_add_dependent(acpi_handle handle, struct device *depdev)
{
struct acpi_device_physical_node *dep;
struct acpi_device *adev;

if (!depdev || acpi_bus_get_device(handle, &adev))
return;

mutex_lock(&adev->physical_node_lock);

list_for_each_entry(dep, &adev->power_dependent, node)
if (dep->dev == depdev)
goto out;

dep = kzalloc(sizeof(*dep), GFP_KERNEL);
if (dep) {
dep->dev = depdev;
list_add_tail(&dep->node, &adev->power_dependent);
}

out:
mutex_unlock(&adev->physical_node_lock);
}
EXPORT_SYMBOL_GPL(acpi_dev_pm_add_dependent);

/**
* acpi_dev_pm_remove_dependent - Remove physical device depending for PM.
* @handle: Handle of ACPI device node.
* @depdev: Device depending on that node for PM.
*/
void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev)
{
struct acpi_device_physical_node *dep;
struct acpi_device *adev;

if (!depdev || acpi_bus_get_device(handle, &adev))
return;

mutex_lock(&adev->physical_node_lock);

list_for_each_entry(dep, &adev->power_dependent, node)
if (dep->dev == depdev) {
list_del(&dep->node);
kfree(dep);
break;
}

mutex_unlock(&adev->physical_node_lock);
}
EXPORT_SYMBOL_GPL(acpi_dev_pm_remove_dependent);
1 change: 1 addition & 0 deletions trunk/drivers/acpi/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ static inline void acpi_debugfs_init(void) { return; }
Power Resource
-------------------------------------------------------------------------- */
int acpi_power_init(void);
void acpi_power_add_remove_device(struct acpi_device *adev, bool add);
int acpi_device_sleep_wake(struct acpi_device *dev,
int enable, int sleep_state, int dev_state);
int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
Expand Down
219 changes: 82 additions & 137 deletions trunk/drivers/acpi/power.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,31 +83,20 @@ static struct acpi_driver acpi_power_driver = {
.drv.pm = &acpi_power_pm,
};

/*
* A power managed device
* A device may rely on multiple power resources.
* */
struct acpi_power_managed_device {
struct device *dev; /* The physical device */
acpi_handle *handle;
};

struct acpi_power_resource_device {
struct acpi_power_managed_device *device;
struct acpi_power_resource_device *next;
struct acpi_power_dependent_device {
struct list_head node;
struct acpi_device *adev;
struct work_struct work;
};

struct acpi_power_resource {
struct acpi_device * device;
struct acpi_device *device;
struct list_head dependent;
acpi_bus_id name;
u32 system_level;
u32 order;
unsigned int ref_count;
struct mutex resource_lock;

/* List of devices relying on this power resource */
struct acpi_power_resource_device *devices;
struct mutex devices_lock;
};

static struct list_head acpi_power_resource_list;
Expand Down Expand Up @@ -207,21 +196,30 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
return 0;
}

/* Resume the device when all power resources in _PR0 are on */
static void acpi_power_on_device(struct acpi_power_managed_device *device)
static void acpi_power_resume_dependent(struct work_struct *work)
{
struct acpi_device *acpi_dev;
acpi_handle handle = device->handle;
struct acpi_power_dependent_device *dep;
struct acpi_device_physical_node *pn;
struct acpi_device *adev;
int state;

if (acpi_bus_get_device(handle, &acpi_dev))
dep = container_of(work, struct acpi_power_dependent_device, work);
adev = dep->adev;
if (acpi_power_get_inferred_state(adev, &state))
return;

if(acpi_power_get_inferred_state(acpi_dev, &state))
if (state > ACPI_STATE_D0)
return;

if (state == ACPI_STATE_D0 && pm_runtime_suspended(device->dev))
pm_request_resume(device->dev);
mutex_lock(&adev->physical_node_lock);

list_for_each_entry(pn, &adev->physical_node_list, node)
pm_request_resume(pn->dev);

list_for_each_entry(pn, &adev->power_dependent, node)
pm_request_resume(pn->dev);

mutex_unlock(&adev->physical_node_lock);
}

static int __acpi_power_on(struct acpi_power_resource *resource)
Expand All @@ -244,9 +242,7 @@ static int __acpi_power_on(struct acpi_power_resource *resource)
static int acpi_power_on(acpi_handle handle)
{
int result = 0;
bool resume_device = false;
struct acpi_power_resource *resource = NULL;
struct acpi_power_resource_device *device_list;

result = acpi_power_get_context(handle, &resource);
if (result)
Expand All @@ -260,26 +256,17 @@ static int acpi_power_on(acpi_handle handle)
resource->name));
} else {
result = __acpi_power_on(resource);
if (result)
if (result) {
resource->ref_count--;
else
resume_device = true;
}
} else {
struct acpi_power_dependent_device *dep;

mutex_unlock(&resource->resource_lock);

if (!resume_device)
return result;

mutex_lock(&resource->devices_lock);

device_list = resource->devices;
while (device_list) {
acpi_power_on_device(device_list->device);
device_list = device_list->next;
list_for_each_entry(dep, &resource->dependent, node)
schedule_work(&dep->work);
}
}

mutex_unlock(&resource->devices_lock);
mutex_unlock(&resource->resource_lock);

return result;
}
Expand Down Expand Up @@ -357,119 +344,81 @@ static int acpi_power_on_list(struct acpi_handle_list *list)
return result;
}

static void __acpi_power_resource_unregister_device(struct device *dev,
acpi_handle res_handle)
static void acpi_power_add_dependent(acpi_handle rhandle,
struct acpi_device *adev)
{
struct acpi_power_resource *resource = NULL;
struct acpi_power_resource_device *prev, *curr;
struct acpi_power_dependent_device *dep;
struct acpi_power_resource *resource;

if (acpi_power_get_context(res_handle, &resource))
if (!rhandle || !adev || acpi_power_get_context(rhandle, &resource))
return;

mutex_lock(&resource->devices_lock);
prev = NULL;
curr = resource->devices;
while (curr) {
if (curr->device->dev == dev) {
if (!prev)
resource->devices = curr->next;
else
prev->next = curr->next;

kfree(curr);
break;
}

prev = curr;
curr = curr->next;
}
mutex_unlock(&resource->devices_lock);
}

/* Unlink dev from all power resources in _PR0 */
void acpi_power_resource_unregister_device(struct device *dev, acpi_handle handle)
{
struct acpi_device *acpi_dev;
struct acpi_handle_list *list;
int i;
mutex_lock(&resource->resource_lock);

if (!dev || !handle)
return;
list_for_each_entry(dep, &resource->dependent, node)
if (dep->adev == adev)
goto out;

if (acpi_bus_get_device(handle, &acpi_dev))
return;
dep = kzalloc(sizeof(*dep), GFP_KERNEL);
if (!dep)
goto out;

list = &acpi_dev->power.states[ACPI_STATE_D0].resources;
dep->adev = adev;
INIT_WORK(&dep->work, acpi_power_resume_dependent);
list_add_tail(&dep->node, &resource->dependent);

for (i = 0; i < list->count; i++)
__acpi_power_resource_unregister_device(dev,
list->handles[i]);
out:
mutex_unlock(&resource->resource_lock);
}
EXPORT_SYMBOL_GPL(acpi_power_resource_unregister_device);

static int __acpi_power_resource_register_device(
struct acpi_power_managed_device *powered_device, acpi_handle handle)
static void acpi_power_remove_dependent(acpi_handle rhandle,
struct acpi_device *adev)
{
struct acpi_power_resource *resource = NULL;
struct acpi_power_resource_device *power_resource_device;
int result;
struct acpi_power_dependent_device *dep;
struct acpi_power_resource *resource;
struct work_struct *work = NULL;

result = acpi_power_get_context(handle, &resource);
if (result)
return result;
if (!rhandle || !adev || acpi_power_get_context(rhandle, &resource))
return;

power_resource_device = kzalloc(
sizeof(*power_resource_device), GFP_KERNEL);
if (!power_resource_device)
return -ENOMEM;
mutex_lock(&resource->resource_lock);

power_resource_device->device = powered_device;
list_for_each_entry(dep, &resource->dependent, node)
if (dep->adev == adev) {
list_del(&dep->node);
work = &dep->work;
break;
}

mutex_lock(&resource->devices_lock);
power_resource_device->next = resource->devices;
resource->devices = power_resource_device;
mutex_unlock(&resource->devices_lock);
mutex_unlock(&resource->resource_lock);

return 0;
if (work) {
cancel_work_sync(work);
kfree(dep);
}
}

/* Link dev to all power resources in _PR0 */
int acpi_power_resource_register_device(struct device *dev, acpi_handle handle)
void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
{
struct acpi_device *acpi_dev;
struct acpi_handle_list *list;
struct acpi_power_managed_device *powered_device;
int i, ret;
if (adev->power.flags.power_resources) {
struct acpi_device_power_state *ps;
int j;

if (!dev || !handle)
return -ENODEV;

ret = acpi_bus_get_device(handle, &acpi_dev);
if (ret || !acpi_dev->power.flags.power_resources)
return -ENODEV;
ps = &adev->power.states[ACPI_STATE_D0];
for (j = 0; j < ps->resources.count; j++) {
acpi_handle rhandle = ps->resources.handles[j];

powered_device = kzalloc(sizeof(*powered_device), GFP_KERNEL);
if (!powered_device)
return -ENOMEM;

powered_device->dev = dev;
powered_device->handle = handle;

list = &acpi_dev->power.states[ACPI_STATE_D0].resources;

for (i = 0; i < list->count; i++) {
ret = __acpi_power_resource_register_device(powered_device,
list->handles[i]);

if (ret) {
acpi_power_resource_unregister_device(dev, handle);
break;
if (add)
acpi_power_add_dependent(rhandle, adev);
else
acpi_power_remove_dependent(rhandle, adev);
}
}

return ret;
}
EXPORT_SYMBOL_GPL(acpi_power_resource_register_device);

/* --------------------------------------------------------------------------
Device Power Management
-------------------------------------------------------------------------- */

/**
* acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
Expand Down Expand Up @@ -623,10 +572,6 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
return err;
}

/* --------------------------------------------------------------------------
Device Power Management
-------------------------------------------------------------------------- */

int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
{
int result = 0;
Expand Down Expand Up @@ -725,7 +670,7 @@ static int acpi_power_add(struct acpi_device *device)

resource->device = device;
mutex_init(&resource->resource_lock);
mutex_init(&resource->devices_lock);
INIT_LIST_HEAD(&resource->dependent);
strcpy(resource->name, device->pnp.bus_id);
strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
Expand Down
Loading

0 comments on commit 5b6f704

Please sign in to comment.