Skip to content

Commit

Permalink
Merge branch 'pm-assorted'
Browse files Browse the repository at this point in the history
* pm-assorted:
  PM / QoS: Add pm_qos and dev_pm_qos to events-power.txt
  PM / QoS: Add dev_pm_qos_request tracepoints
  PM / QoS: Add pm_qos_request tracepoints
  PM / QoS: Add pm_qos_update_target/flags tracepoints
  PM / QoS: Update Documentation/power/pm_qos_interface.txt
  PM / Sleep: Print last wakeup source on failed wakeup_count write
  PM / QoS: correct the valid range of pm_qos_class
  PM / wakeup: Adjust messaging for wake events during suspend
  PM / Runtime: Update .runtime_idle() callback documentation
  PM / Runtime: Rework the "runtime idle" helper routine
  PM / Hibernate: print physical addresses consistently with other parts of kernel
  • Loading branch information
Rafael J. Wysocki committed Jun 28, 2013
2 parents 405a108 + f5ce157 commit e52cff8
Show file tree
Hide file tree
Showing 33 changed files with 315 additions and 113 deletions.
50 changes: 43 additions & 7 deletions Documentation/power/pm_qos_interface.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ one of the parameters.
Two different PM QoS frameworks are available:
1. PM QoS classes for cpu_dma_latency, network_latency, network_throughput.
2. the per-device PM QoS framework provides the API to manage the per-device latency
constraints.
constraints and PM QoS flags.

Each parameters have defined units:
* latency: usec
Expand Down Expand Up @@ -86,13 +86,17 @@ To remove the user mode request for a target value simply close the device
node.


2. PM QoS per-device latency framework
2. PM QoS per-device latency and flags framework

For each device, there are two lists of PM QoS requests. One is maintained
along with the aggregated target of latency value and the other is for PM QoS
flags. Values are updated in response to changes of the request list.

Target latency value is simply the minimum of the request values held in the
parameter list elements. The PM QoS flags aggregate value is a gather (bitwise
OR) of all list elements' values. Two device PM QoS flags are defined currently:
PM_QOS_FLAG_NO_POWER_OFF and PM_QOS_FLAG_REMOTE_WAKEUP.

For each device a list of performance requests is maintained along with
an aggregated target value. The aggregated target value is updated with
changes to the request list or elements of the list. Typically the
aggregated target value is simply the max or min of the request values held
in the parameter list elements.
Note: the aggregated target value is implemented as an atomic variable so that
reading the aggregated value does not require any locking mechanism.

Expand All @@ -119,6 +123,38 @@ the request.
s32 dev_pm_qos_read_value(device):
Returns the aggregated value for a given device's constraints list.

enum pm_qos_flags_status dev_pm_qos_flags(device, mask)
Check PM QoS flags of the given device against the given mask of flags.
The meaning of the return values is as follows:
PM_QOS_FLAGS_ALL: All flags from the mask are set
PM_QOS_FLAGS_SOME: Some flags from the mask are set
PM_QOS_FLAGS_NONE: No flags from the mask are set
PM_QOS_FLAGS_UNDEFINED: The device's PM QoS structure has not been
initialized or the list of requests is empty.

int dev_pm_qos_add_ancestor_request(dev, handle, value)
Add a PM QoS request for the first direct ancestor of the given device whose
power.ignore_children flag is unset.

int dev_pm_qos_expose_latency_limit(device, value)
Add a request to the device's PM QoS list of latency constraints and create
a sysfs attribute pm_qos_resume_latency_us under the device's power directory
allowing user space to manipulate that request.

void dev_pm_qos_hide_latency_limit(device)
Drop the request added by dev_pm_qos_expose_latency_limit() from the device's
PM QoS list of latency constraints and remove sysfs attribute pm_qos_resume_latency_us
from the device's power directory.

int dev_pm_qos_expose_flags(device, value)
Add a request to the device's PM QoS list of flags and create sysfs attributes
pm_qos_no_power_off and pm_qos_remote_wakeup under the device's power directory
allowing user space to change these flags' value.

void dev_pm_qos_hide_flags(device)
Drop the request added by dev_pm_qos_expose_flags() from the device's PM QoS list
of flags and remove sysfs attributes pm_qos_no_power_off and pm_qos_remote_wakeup
under the device's power directory.

Notification mechanisms:
The per-device PM QoS framework has 2 different and distinct notification trees:
Expand Down
20 changes: 10 additions & 10 deletions Documentation/power/runtime_pm.txt
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,12 @@ The action performed by the idle callback is totally dependent on the subsystem
(or driver) in question, but the expected and recommended action is to check
if the device can be suspended (i.e. if all of the conditions necessary for
suspending the device are satisfied) and to queue up a suspend request for the
device in that case. The value returned by this callback is ignored by the PM
core.
device in that case. If there is no idle callback, or if the callback returns
0, then the PM core will attempt to carry out a runtime suspend of the device;
in essence, it will call pm_runtime_suspend() directly. To prevent this (for
example, if the callback routine has started a delayed suspend), the routine
should return a non-zero value. Negative error return codes are ignored by the
PM core.

The helper functions provided by the PM core, described in Section 4, guarantee
that the following constraints are met with respect to runtime PM callbacks for
Expand Down Expand Up @@ -301,9 +305,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
removing the device from device hierarchy

int pm_runtime_idle(struct device *dev);
- execute the subsystem-level idle callback for the device; returns 0 on
success or error code on failure, where -EINPROGRESS means that
->runtime_idle() is already being executed
- execute the subsystem-level idle callback for the device; returns an
error code on failure, where -EINPROGRESS means that ->runtime_idle() is
already being executed; if there is no callback or the callback returns 0
then run pm_runtime_suspend(dev) and return its result

int pm_runtime_suspend(struct device *dev);
- execute the subsystem-level suspend callback for the device; returns 0 on
Expand Down Expand Up @@ -660,11 +665,6 @@ Subsystems may wish to conserve code space by using the set of generic power
management callbacks provided by the PM core, defined in
driver/base/power/generic_ops.c:

int pm_generic_runtime_idle(struct device *dev);
- invoke the ->runtime_idle() callback provided by the driver of this
device, if defined, and call pm_runtime_suspend() for this device if the
return value is 0 or the callback is not defined

int pm_generic_runtime_suspend(struct device *dev);
- invoke the ->runtime_suspend() callback provided by the driver of this
device and return its result, or return -EINVAL if not defined
Expand Down
31 changes: 31 additions & 0 deletions Documentation/trace/events-power.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,34 @@ power_domain_target "%s state=%lu cpu_id=%lu"
The first parameter gives the power domain name (e.g. "mpu_pwrdm").
The second parameter is the power domain target state.

4. PM QoS events
================
The PM QoS events are used for QoS add/update/remove request and for
target/flags update.

pm_qos_add_request "pm_qos_class=%s value=%d"
pm_qos_update_request "pm_qos_class=%s value=%d"
pm_qos_remove_request "pm_qos_class=%s value=%d"
pm_qos_update_request_timeout "pm_qos_class=%s value=%d, timeout_us=%ld"

The first parameter gives the QoS class name (e.g. "CPU_DMA_LATENCY").
The second parameter is value to be added/updated/removed.
The third parameter is timeout value in usec.

pm_qos_update_target "action=%s prev_value=%d curr_value=%d"
pm_qos_update_flags "action=%s prev_value=0x%x curr_value=0x%x"

The first parameter gives the QoS action name (e.g. "ADD_REQ").
The second parameter is the previous QoS value.
The third parameter is the current QoS value to update.

And, there are also events used for device PM QoS add/update/remove request.

dev_pm_qos_add_request "device=%s type=%s new_value=%d"
dev_pm_qos_update_request "device=%s type=%s new_value=%d"
dev_pm_qos_remove_request "device=%s type=%s new_value=%d"

The first parameter gives the device name which tries to add/update/remove
QoS requests.
The second parameter gives the request type (e.g. "DEV_PM_QOS_LATENCY").
The third parameter is value to be added/updated/removed.
7 changes: 1 addition & 6 deletions arch/arm/mach-omap2/omap_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -591,11 +591,6 @@ static int _od_runtime_suspend(struct device *dev)
return ret;
}

static int _od_runtime_idle(struct device *dev)
{
return pm_generic_runtime_idle(dev);
}

static int _od_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
Expand Down Expand Up @@ -653,7 +648,7 @@ static int _od_resume_noirq(struct device *dev)
struct dev_pm_domain omap_device_pm_domain = {
.ops = {
SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
_od_runtime_idle)
NULL)
USE_PLATFORM_PM_SLEEP_OPS
.suspend_noirq = _od_suspend_noirq,
.resume_noirq = _od_resume_noirq,
Expand Down
1 change: 0 additions & 1 deletion drivers/acpi/device_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,6 @@ static struct dev_pm_domain acpi_general_pm_domain = {
#ifdef CONFIG_PM_RUNTIME
.runtime_suspend = acpi_subsys_runtime_suspend,
.runtime_resume = acpi_subsys_runtime_resume,
.runtime_idle = pm_generic_runtime_idle,
#endif
#ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare,
Expand Down
2 changes: 1 addition & 1 deletion drivers/amba/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ static const struct dev_pm_ops amba_pm = {
SET_RUNTIME_PM_OPS(
amba_pm_runtime_suspend,
amba_pm_runtime_resume,
pm_generic_runtime_idle
NULL
)
};

Expand Down
2 changes: 1 addition & 1 deletion drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -5436,7 +5436,7 @@ static int ata_port_runtime_idle(struct device *dev)
return -EBUSY;
}

return pm_runtime_suspend(dev);
return 0;
}

static int ata_port_runtime_suspend(struct device *dev)
Expand Down
1 change: 0 additions & 1 deletion drivers/base/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,6 @@ int platform_pm_restore(struct device *dev)
static const struct dev_pm_ops platform_dev_pm_ops = {
.runtime_suspend = pm_generic_runtime_suspend,
.runtime_resume = pm_generic_runtime_resume,
.runtime_idle = pm_generic_runtime_idle,
USE_PLATFORM_PM_SLEEP_OPS
};

Expand Down
1 change: 0 additions & 1 deletion drivers/base/power/domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -2143,7 +2143,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
genpd->max_off_time_changed = true;
genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
genpd->domain.ops.prepare = pm_genpd_prepare;
genpd->domain.ops.suspend = pm_genpd_suspend;
genpd->domain.ops.suspend_late = pm_genpd_suspend_late;
Expand Down
23 changes: 0 additions & 23 deletions drivers/base/power/generic_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,6 @@
#include <linux/export.h>

#ifdef CONFIG_PM_RUNTIME
/**
* pm_generic_runtime_idle - Generic runtime idle callback for subsystems.
* @dev: Device to handle.
*
* If PM operations are defined for the @dev's driver and they include
* ->runtime_idle(), execute it and return its error code, if nonzero.
* Otherwise, execute pm_runtime_suspend() for the device and return 0.
*/
int pm_generic_runtime_idle(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;

if (pm && pm->runtime_idle) {
int ret = pm->runtime_idle(dev);
if (ret)
return ret;
}

pm_runtime_suspend(dev);
return 0;
}
EXPORT_SYMBOL_GPL(pm_generic_runtime_idle);

/**
* pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems.
* @dev: Device to suspend.
Expand Down
6 changes: 6 additions & 0 deletions drivers/base/power/qos.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <linux/export.h>
#include <linux/pm_runtime.h>
#include <linux/err.h>
#include <trace/events/power.h>

#include "power.h"

Expand Down Expand Up @@ -305,6 +306,7 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
else if (!dev->power.qos)
ret = dev_pm_qos_constraints_allocate(dev);

trace_dev_pm_qos_add_request(dev_name(dev), type, value);
if (!ret) {
req->dev = dev;
req->type = type;
Expand Down Expand Up @@ -349,6 +351,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
return -EINVAL;
}

trace_dev_pm_qos_update_request(dev_name(req->dev), req->type,
new_value);
if (curr_value != new_value)
ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value);

Expand Down Expand Up @@ -398,6 +402,8 @@ static int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
if (IS_ERR_OR_NULL(req->dev->power.qos))
return -ENODEV;

trace_dev_pm_qos_remove_request(dev_name(req->dev), req->type,
PM_QOS_DEFAULT_VALUE);
ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
memset(req, 0, sizeof(*req));
return ret;
Expand Down
12 changes: 5 additions & 7 deletions drivers/base/power/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,8 @@ static int rpm_idle(struct device *dev, int rpmflags)
/* Pending requests need to be canceled. */
dev->power.request = RPM_REQ_NONE;

if (dev->power.no_callbacks) {
/* Assume ->runtime_idle() callback would have suspended. */
retval = rpm_suspend(dev, rpmflags);
if (dev->power.no_callbacks)
goto out;
}

/* Carry out an asynchronous or a synchronous idle notification. */
if (rpmflags & RPM_ASYNC) {
Expand All @@ -306,7 +303,8 @@ static int rpm_idle(struct device *dev, int rpmflags)
dev->power.request_pending = true;
queue_work(pm_wq, &dev->power.work);
}
goto out;
trace_rpm_return_int(dev, _THIS_IP_, 0);
return 0;
}

dev->power.idle_notification = true;
Expand All @@ -326,14 +324,14 @@ static int rpm_idle(struct device *dev, int rpmflags)
callback = dev->driver->pm->runtime_idle;

if (callback)
__rpm_callback(callback, dev);
retval = __rpm_callback(callback, dev);

dev->power.idle_notification = false;
wake_up_all(&dev->power.wait_queue);

out:
trace_rpm_return_int(dev, _THIS_IP_, retval);
return retval;
return retval ? retval : rpm_suspend(dev, rpmflags);
}

/**
Expand Down
9 changes: 6 additions & 3 deletions drivers/base/power/wakeup.c
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ void pm_wakeup_event(struct device *dev, unsigned int msec)
}
EXPORT_SYMBOL_GPL(pm_wakeup_event);

static void print_active_wakeup_sources(void)
void pm_print_active_wakeup_sources(void)
{
struct wakeup_source *ws;
int active = 0;
Expand All @@ -683,6 +683,7 @@ static void print_active_wakeup_sources(void)
last_activity_ws->name);
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources);

/**
* pm_wakeup_pending - Check if power transition in progress should be aborted.
Expand All @@ -707,8 +708,10 @@ bool pm_wakeup_pending(void)
}
spin_unlock_irqrestore(&events_lock, flags);

if (ret)
print_active_wakeup_sources();
if (ret) {
pr_info("PM: Wakeup pending, aborting suspend\n");
pm_print_active_wakeup_sources();
}

return ret;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/dma/intel_mid_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -1405,7 +1405,7 @@ static int dma_runtime_idle(struct device *dev)
return -EAGAIN;
}

return pm_schedule_suspend(dev, 0);
return 0;
}

/******************************************************************************
Expand Down
6 changes: 1 addition & 5 deletions drivers/gpio/gpio-langwell.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,7 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = {

static int lnw_gpio_runtime_idle(struct device *dev)
{
int err = pm_schedule_suspend(dev, 500);

if (!err)
return 0;

pm_schedule_suspend(dev, 500);
return -EBUSY;
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/i2c/i2c-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ static const struct dev_pm_ops i2c_device_pm_ops = {
SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend,
pm_generic_runtime_resume,
pm_generic_runtime_idle
NULL
)
};

Expand Down
8 changes: 1 addition & 7 deletions drivers/mfd/ab8500-gpadc.c
Original file line number Diff line number Diff line change
Expand Up @@ -886,12 +886,6 @@ static int ab8500_gpadc_runtime_resume(struct device *dev)
return ret;
}

static int ab8500_gpadc_runtime_idle(struct device *dev)
{
pm_runtime_suspend(dev);
return 0;
}

static int ab8500_gpadc_suspend(struct device *dev)
{
struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
Expand Down Expand Up @@ -1039,7 +1033,7 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
static const struct dev_pm_ops ab8500_gpadc_pm_ops = {
SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend,
ab8500_gpadc_runtime_resume,
ab8500_gpadc_runtime_idle)
NULL)
SET_SYSTEM_SLEEP_PM_OPS(ab8500_gpadc_suspend,
ab8500_gpadc_resume)

Expand Down
Loading

0 comments on commit e52cff8

Please sign in to comment.