Skip to content

Commit

Permalink
Merge branch 'acpi-pm'
Browse files Browse the repository at this point in the history
* acpi-pm: (35 commits)
  ACPI / PM: Handle missing _PSC in acpi_bus_update_power()
  ACPI / PM: Do not power manage devices in unknown initial states
  ACPI / PM: Fix acpi_bus_get_device() check in drivers/acpi/device_pm.c
  ACPI / PM: Fix /proc/acpi/wakeup for devices w/o bus or parent
  ACPI / PM: Fix consistency check for power resources during resume
  ACPI / PM: Expose lists of device power resources to user space
  sysfs: Functions for adding/removing symlinks to/from attribute groups
  ACPI / PM: Expose current status of ACPI power resources
  ACPI / PM: Expose power states of ACPI devices to user space
  ACPI / scan: Prevent device add uevents from racing with user space
  ACPI / PM: Fix device power state value after transitions to D3cold
  ACPI / PM: Use string "D3cold" to represent ACPI_STATE_D3_COLD
  ACPI / PM: Sanitize checks in acpi_power_on_resources()
  ACPI / PM: Always evaluate _PSn after setting power resources
  ACPI / PM: Introduce helper for executing _PSn methods
  ACPI / PM: Make acpi_bus_init_power() more robust
  ACPI / PM: Fix build for unusual combination of Kconfig options
  ACPI / PM: remove leading whitespace from #ifdef
  ACPI / PM: Consolidate suspend-specific and hibernate-specific code
  ACPI / PM: Move device power management functions to device_pm.c
  ...
  • Loading branch information
Rafael J. Wysocki committed Feb 11, 2013
2 parents 48694bd + 511d5c4 commit a9834cb
Show file tree
Hide file tree
Showing 23 changed files with 1,329 additions and 901 deletions.
13 changes: 13 additions & 0 deletions Documentation/ABI/testing/sysfs-devices-power_resources_D0
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions Documentation/ABI/testing/sysfs-devices-power_resources_D1
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions Documentation/ABI/testing/sysfs-devices-power_resources_D2
Original file line number Diff line number Diff line change
@@ -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.
14 changes: 14 additions & 0 deletions Documentation/ABI/testing/sysfs-devices-power_resources_D3hot
Original file line number Diff line number Diff line change
@@ -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.
20 changes: 20 additions & 0 deletions Documentation/ABI/testing/sysfs-devices-power_state
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
What: /sys/devices/.../power_state
Date: January 2013
Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Description:
The /sys/devices/.../power_state attribute is only present for
device objects representing ACPI device nodes that provide power
management methods.

If present, it contains a string representing the current ACPI
power state of the given device node. Its possible values,
"D0", "D1", "D2", "D3hot", and "D3cold", reflect the power state
names defined by the ACPI specification (ACPI 4 and above).

If the device node uses shared ACPI power resources, this state
determines a list of power resources required not to be turned
off. However, some power resources needed by the device node in
higher-power (lower-number) states may also be ON because of
some other devices using them at the moment.

This attribute is read-only.
23 changes: 23 additions & 0 deletions Documentation/ABI/testing/sysfs-devices-real_power_state
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
What: /sys/devices/.../real_power_state
Date: January 2013
Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Description:
The /sys/devices/.../real_power_state attribute is only present
for device objects representing ACPI device nodes that provide
power management methods and use ACPI power resources for power
management.

If present, it contains a string representing the real ACPI
power state of the given device node as returned by the _PSC
control method or inferred from the configuration of power
resources. Its possible values, "D0", "D1", "D2", "D3hot", and
"D3cold", reflect the power state names defined by the ACPI
specification (ACPI 4 and above).

In some situations the value of this attribute may be different
from the value of the /sys/devices/.../power_state attribute for
the same device object. If that happens, some shared power
resources used by the device node are only ON because of some
other devices using them at the moment.

This attribute is read-only.
12 changes: 12 additions & 0 deletions Documentation/ABI/testing/sysfs-devices-resource_in_use
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
What: /sys/devices/.../resource_in_use
Date: January 2013
Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Description:
The /sys/devices/.../resource_in_use attribute is only present
for device objects representing ACPI power resources.

If present, it contains a number (0 or 1) representing the
current status of the given power resource (0 means that the
resource is not in use and therefore it has been turned off).

This attribute is read-only.
270 changes: 0 additions & 270 deletions drivers/acpi/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,276 +178,6 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data)
}
EXPORT_SYMBOL(acpi_bus_get_private_data);

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

static const char *state_string(int state)
{
switch (state) {
case ACPI_STATE_D0:
return "D0";
case ACPI_STATE_D1:
return "D1";
case ACPI_STATE_D2:
return "D2";
case ACPI_STATE_D3_HOT:
return "D3hot";
case ACPI_STATE_D3_COLD:
return "D3";
default:
return "(unknown)";
}
}

static int __acpi_bus_get_power(struct acpi_device *device, int *state)
{
int result = ACPI_STATE_UNKNOWN;

if (!device || !state)
return -EINVAL;

if (!device->flags.power_manageable) {
/* TBD: Non-recursive algorithm for walking up hierarchy. */
*state = device->parent ?
device->parent->power.state : ACPI_STATE_D0;
goto out;
}

/*
* Get the device's power state either directly (via _PSC) or
* indirectly (via power resources).
*/
if (device->power.flags.explicit_get) {
unsigned long long psc;
acpi_status status = acpi_evaluate_integer(device->handle,
"_PSC", NULL, &psc);
if (ACPI_FAILURE(status))
return -ENODEV;

result = psc;
}
/* The test below covers ACPI_STATE_UNKNOWN too. */
if (result <= ACPI_STATE_D2) {
; /* Do nothing. */
} else if (device->power.flags.power_resources) {
int error = acpi_power_get_inferred_state(device, &result);
if (error)
return error;
} else if (result == ACPI_STATE_D3_HOT) {
result = ACPI_STATE_D3;
}

/*
* If we were unsure about the device parent's power state up to this
* point, the fact that the device is in D0 implies that the parent has
* to be in D0 too.
*/
if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN
&& result == ACPI_STATE_D0)
device->parent->power.state = ACPI_STATE_D0;

*state = result;

out:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
device->pnp.bus_id, state_string(*state)));

return 0;
}


/**
* acpi_device_set_power - Set power state of an ACPI device.
* @device: Device to set the power state of.
* @state: New power state to set.
*
* Callers must ensure that the device is power manageable before using this
* function.
*/
int acpi_device_set_power(struct acpi_device *device, int state)
{
int result = 0;
acpi_status status = AE_OK;
char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };

if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
return -EINVAL;

/* Make sure this is a valid target state */

if (state == device->power.state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
state_string(state)));
return 0;
}

if (!device->power.states[state].flags.valid) {
printk(KERN_WARNING PREFIX "Device does not support %s\n",
state_string(state));
return -ENODEV;
}
if (device->parent && (state < device->parent->power.state)) {
printk(KERN_WARNING PREFIX
"Cannot set device to a higher-powered"
" state than parent\n");
return -ENODEV;
}

/* For D3cold we should execute _PS3, not _PS4. */
if (state == ACPI_STATE_D3_COLD)
object_name[3] = '3';

/*
* Transition Power
* ----------------
* On transitions to a high-powered state we first apply power (via
* power resources) then evalute _PSx. Conversly for transitions to
* a lower-powered state.
*/
if (state < device->power.state) {
if (device->power.state >= ACPI_STATE_D3_HOT &&
state != ACPI_STATE_D0) {
printk(KERN_WARNING PREFIX
"Cannot transition to non-D0 state from D3\n");
return -ENODEV;
}
if (device->power.flags.power_resources) {
result = acpi_power_transition(device, state);
if (result)
goto end;
}
if (device->power.states[state].flags.explicit_set) {
status = acpi_evaluate_object(device->handle,
object_name, NULL, NULL);
if (ACPI_FAILURE(status)) {
result = -ENODEV;
goto end;
}
}
} else {
if (device->power.states[state].flags.explicit_set) {
status = acpi_evaluate_object(device->handle,
object_name, NULL, NULL);
if (ACPI_FAILURE(status)) {
result = -ENODEV;
goto end;
}
}
if (device->power.flags.power_resources) {
result = acpi_power_transition(device, state);
if (result)
goto end;
}
}

end:
if (result)
printk(KERN_WARNING PREFIX
"Device [%s] failed to transition to %s\n",
device->pnp.bus_id, state_string(state));
else {
device->power.state = state;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device [%s] transitioned to %s\n",
device->pnp.bus_id, state_string(state)));
}

return result;
}
EXPORT_SYMBOL(acpi_device_set_power);


int acpi_bus_set_power(acpi_handle handle, int state)
{
struct acpi_device *device;
int result;

result = acpi_bus_get_device(handle, &device);
if (result)
return result;

if (!device->flags.power_manageable) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device [%s] is not power manageable\n",
dev_name(&device->dev)));
return -ENODEV;
}

return acpi_device_set_power(device, state);
}
EXPORT_SYMBOL(acpi_bus_set_power);


int acpi_bus_init_power(struct acpi_device *device)
{
int state;
int result;

if (!device)
return -EINVAL;

device->power.state = ACPI_STATE_UNKNOWN;

result = __acpi_bus_get_power(device, &state);
if (result)
return result;

if (device->power.flags.power_resources)
result = acpi_power_on_resources(device, state);

if (!result)
device->power.state = state;

return result;
}


int acpi_bus_update_power(acpi_handle handle, int *state_p)
{
struct acpi_device *device;
int state;
int result;

result = acpi_bus_get_device(handle, &device);
if (result)
return result;

result = __acpi_bus_get_power(device, &state);
if (result)
return result;

result = acpi_device_set_power(device, state);
if (!result && state_p)
*state_p = state;

return result;
}
EXPORT_SYMBOL_GPL(acpi_bus_update_power);


bool acpi_bus_power_manageable(acpi_handle handle)
{
struct acpi_device *device;
int result;

result = acpi_bus_get_device(handle, &device);
return result ? false : device->flags.power_manageable;
}

EXPORT_SYMBOL(acpi_bus_power_manageable);

bool acpi_bus_can_wakeup(acpi_handle handle)
{
struct acpi_device *device;
int result;

result = acpi_bus_get_device(handle, &device);
return result ? false : device->wakeup.flags.valid;
}

EXPORT_SYMBOL(acpi_bus_can_wakeup);

static void acpi_print_osc_error(acpi_handle handle,
struct acpi_osc_context *context, char *error)
{
Expand Down
Loading

0 comments on commit a9834cb

Please sign in to comment.