ACPI / PM: Expose lists of device power resources to user space
Since ACPI power resources are going to be used more extensively on new hardware platforms, it is necessary to allow user space (powertop in particular) to look at the lists of power resources corresponding to different power states of devices for diagnostics and control purposes. For this reason, for each power state of an ACPI device node using power resources create a special attribute group under the device node's directory in sysfs containing links to sysfs directories representing the power resources in that list. The names of the new attribute groups are "power_resources_<state>", where <state> is the state name i.e. "D0", "D1", "D2", or "D3hot". Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
0bb8f3d6ae
commit
18a387099b
5 changed files with 144 additions and 11 deletions
13
Documentation/ABI/testing/sysfs-devices-power_resources_D0
Normal file
13
Documentation/ABI/testing/sysfs-devices-power_resources_D0
Normal file
|
@ -0,0 +1,13 @@
|
|||
What: /sys/devices/.../power_resources_D0/
|
||||
Date: January 2013
|
||||
Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
Description:
|
||||
The /sys/devices/.../power_resources_D0/ directory is only
|
||||
present for device objects representing ACPI device nodes that
|
||||
use ACPI power resources for power management.
|
||||
|
||||
If present, it contains symbolic links to device directories
|
||||
representing ACPI power resources that need to be turned on for
|
||||
the given device node to be in ACPI power state D0. The names
|
||||
of the links are the same as the names of the directories they
|
||||
point to.
|
14
Documentation/ABI/testing/sysfs-devices-power_resources_D1
Normal file
14
Documentation/ABI/testing/sysfs-devices-power_resources_D1
Normal file
|
@ -0,0 +1,14 @@
|
|||
What: /sys/devices/.../power_resources_D1/
|
||||
Date: January 2013
|
||||
Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
Description:
|
||||
The /sys/devices/.../power_resources_D1/ directory is only
|
||||
present for device objects representing ACPI device nodes that
|
||||
use ACPI power resources for power management and support ACPI
|
||||
power state D1.
|
||||
|
||||
If present, it contains symbolic links to device directories
|
||||
representing ACPI power resources that need to be turned on for
|
||||
the given device node to be in ACPI power state D1. The names
|
||||
of the links are the same as the names of the directories they
|
||||
point to.
|
14
Documentation/ABI/testing/sysfs-devices-power_resources_D2
Normal file
14
Documentation/ABI/testing/sysfs-devices-power_resources_D2
Normal file
|
@ -0,0 +1,14 @@
|
|||
What: /sys/devices/.../power_resources_D2/
|
||||
Date: January 2013
|
||||
Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
Description:
|
||||
The /sys/devices/.../power_resources_D2/ directory is only
|
||||
present for device objects representing ACPI device nodes that
|
||||
use ACPI power resources for power management and support ACPI
|
||||
power state D2.
|
||||
|
||||
If present, it contains symbolic links to device directories
|
||||
representing ACPI power resources that need to be turned on for
|
||||
the given device node to be in ACPI power state D2. The names
|
||||
of the links are the same as the names of the directories they
|
||||
point to.
|
|
@ -0,0 +1,14 @@
|
|||
What: /sys/devices/.../power_resources_D3hot/
|
||||
Date: January 2013
|
||||
Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
Description:
|
||||
The /sys/devices/.../power_resources_D3hot/ directory is only
|
||||
present for device objects representing ACPI device nodes that
|
||||
use ACPI power resources for power management and support ACPI
|
||||
power state D3hot.
|
||||
|
||||
If present, it contains symbolic links to device directories
|
||||
representing ACPI power resources that need to be turned on for
|
||||
the given device node to be in ACPI power state D3hot. The
|
||||
names of the links are the same as the names of the directories
|
||||
they point to.
|
|
@ -41,6 +41,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include "sleep.h"
|
||||
|
@ -417,21 +418,98 @@ static void acpi_power_remove_dependent(struct acpi_power_resource *resource,
|
|||
}
|
||||
}
|
||||
|
||||
static struct attribute *attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group attr_groups[] = {
|
||||
[ACPI_STATE_D0] = {
|
||||
.name = "power_resources_D0",
|
||||
.attrs = attrs,
|
||||
},
|
||||
[ACPI_STATE_D1] = {
|
||||
.name = "power_resources_D1",
|
||||
.attrs = attrs,
|
||||
},
|
||||
[ACPI_STATE_D2] = {
|
||||
.name = "power_resources_D2",
|
||||
.attrs = attrs,
|
||||
},
|
||||
[ACPI_STATE_D3_HOT] = {
|
||||
.name = "power_resources_D3hot",
|
||||
.attrs = attrs,
|
||||
},
|
||||
};
|
||||
|
||||
static void acpi_power_hide_list(struct acpi_device *adev, int state)
|
||||
{
|
||||
struct acpi_device_power_state *ps = &adev->power.states[state];
|
||||
struct acpi_power_resource_entry *entry;
|
||||
|
||||
if (list_empty(&ps->resources))
|
||||
return;
|
||||
|
||||
list_for_each_entry_reverse(entry, &ps->resources, node) {
|
||||
struct acpi_device *res_dev = &entry->resource->device;
|
||||
|
||||
sysfs_remove_link_from_group(&adev->dev.kobj,
|
||||
attr_groups[state].name,
|
||||
dev_name(&res_dev->dev));
|
||||
}
|
||||
sysfs_remove_group(&adev->dev.kobj, &attr_groups[state]);
|
||||
}
|
||||
|
||||
static void acpi_power_expose_list(struct acpi_device *adev, int state)
|
||||
{
|
||||
struct acpi_device_power_state *ps = &adev->power.states[state];
|
||||
struct acpi_power_resource_entry *entry;
|
||||
int ret;
|
||||
|
||||
if (list_empty(&ps->resources))
|
||||
return;
|
||||
|
||||
ret = sysfs_create_group(&adev->dev.kobj, &attr_groups[state]);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
list_for_each_entry(entry, &ps->resources, node) {
|
||||
struct acpi_device *res_dev = &entry->resource->device;
|
||||
|
||||
ret = sysfs_add_link_to_group(&adev->dev.kobj,
|
||||
attr_groups[state].name,
|
||||
&res_dev->dev.kobj,
|
||||
dev_name(&res_dev->dev));
|
||||
if (ret) {
|
||||
acpi_power_hide_list(adev, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
|
||||
{
|
||||
if (adev->power.flags.power_resources) {
|
||||
struct acpi_device_power_state *ps;
|
||||
struct acpi_power_resource_entry *entry;
|
||||
struct acpi_device_power_state *ps;
|
||||
struct acpi_power_resource_entry *entry;
|
||||
int state;
|
||||
|
||||
ps = &adev->power.states[ACPI_STATE_D0];
|
||||
list_for_each_entry(entry, &ps->resources, node) {
|
||||
struct acpi_power_resource *resource = entry->resource;
|
||||
if (!adev->power.flags.power_resources)
|
||||
return;
|
||||
|
||||
if (add)
|
||||
acpi_power_add_dependent(resource, adev);
|
||||
else
|
||||
acpi_power_remove_dependent(resource, adev);
|
||||
}
|
||||
ps = &adev->power.states[ACPI_STATE_D0];
|
||||
list_for_each_entry(entry, &ps->resources, node) {
|
||||
struct acpi_power_resource *resource = entry->resource;
|
||||
|
||||
if (add)
|
||||
acpi_power_add_dependent(resource, adev);
|
||||
else
|
||||
acpi_power_remove_dependent(resource, adev);
|
||||
}
|
||||
|
||||
for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) {
|
||||
if (add)
|
||||
acpi_power_expose_list(adev, state);
|
||||
else
|
||||
acpi_power_hide_list(adev, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue