You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'pm-assorted'
* 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
This commit is contained in:
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
+1
-1
@@ -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
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1405,7 +1405,7 @@ static int dma_runtime_idle(struct device *dev)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return pm_schedule_suspend(dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ static int mmc_runtime_resume(struct device *dev)
|
||||
|
||||
static int mmc_runtime_idle(struct device *dev)
|
||||
{
|
||||
return pm_runtime_suspend(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_PM_RUNTIME */
|
||||
|
||||
@@ -211,7 +211,7 @@ static const struct dev_pm_ops sdio_bus_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(
|
||||
pm_generic_runtime_suspend,
|
||||
pm_generic_runtime_resume,
|
||||
pm_generic_runtime_idle
|
||||
NULL
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
@@ -1050,26 +1050,22 @@ static int pci_pm_runtime_idle(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* If pci_dev->driver is not set (unbound), the device should
|
||||
* always remain in D0 regardless of the runtime PM status
|
||||
*/
|
||||
if (!pci_dev->driver)
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
if (!pm)
|
||||
return -ENOSYS;
|
||||
|
||||
if (pm->runtime_idle) {
|
||||
int ret = pm->runtime_idle(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
if (pm->runtime_idle)
|
||||
ret = pm->runtime_idle(dev);
|
||||
|
||||
out:
|
||||
pm_runtime_suspend(dev);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_PM_RUNTIME */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user