diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-06-28 07:01:40 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-06-28 07:01:40 -0400 |
| commit | e52cff8bdd4a30c40a7f65c7ea8f1f425f8a15eb (patch) | |
| tree | 1729332ebab51bb560ca64effe46cdab38ab537f | |
| parent | 405a1086bdd091d2d55db0ac905cd6332b35cec1 (diff) | |
| parent | f5ce1572109049b90484e2bb44927cb6034c5eb1 (diff) | |
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
33 files changed, 315 insertions, 113 deletions
diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt index 79a2a58425ee..483632087788 100644 --- a/Documentation/power/pm_qos_interface.txt +++ b/Documentation/power/pm_qos_interface.txt | |||
| @@ -7,7 +7,7 @@ one of the parameters. | |||
| 7 | Two different PM QoS frameworks are available: | 7 | Two different PM QoS frameworks are available: |
| 8 | 1. PM QoS classes for cpu_dma_latency, network_latency, network_throughput. | 8 | 1. PM QoS classes for cpu_dma_latency, network_latency, network_throughput. |
| 9 | 2. the per-device PM QoS framework provides the API to manage the per-device latency | 9 | 2. the per-device PM QoS framework provides the API to manage the per-device latency |
| 10 | constraints. | 10 | constraints and PM QoS flags. |
| 11 | 11 | ||
| 12 | Each parameters have defined units: | 12 | Each parameters have defined units: |
| 13 | * latency: usec | 13 | * latency: usec |
| @@ -86,13 +86,17 @@ To remove the user mode request for a target value simply close the device | |||
| 86 | node. | 86 | node. |
| 87 | 87 | ||
| 88 | 88 | ||
| 89 | 2. PM QoS per-device latency framework | 89 | 2. PM QoS per-device latency and flags framework |
| 90 | |||
| 91 | For each device, there are two lists of PM QoS requests. One is maintained | ||
| 92 | along with the aggregated target of latency value and the other is for PM QoS | ||
| 93 | flags. Values are updated in response to changes of the request list. | ||
| 94 | |||
| 95 | Target latency value is simply the minimum of the request values held in the | ||
| 96 | parameter list elements. The PM QoS flags aggregate value is a gather (bitwise | ||
| 97 | OR) of all list elements' values. Two device PM QoS flags are defined currently: | ||
| 98 | PM_QOS_FLAG_NO_POWER_OFF and PM_QOS_FLAG_REMOTE_WAKEUP. | ||
| 90 | 99 | ||
| 91 | For each device a list of performance requests is maintained along with | ||
| 92 | an aggregated target value. The aggregated target value is updated with | ||
| 93 | changes to the request list or elements of the list. Typically the | ||
| 94 | aggregated target value is simply the max or min of the request values held | ||
| 95 | in the parameter list elements. | ||
| 96 | Note: the aggregated target value is implemented as an atomic variable so that | 100 | Note: the aggregated target value is implemented as an atomic variable so that |
| 97 | reading the aggregated value does not require any locking mechanism. | 101 | reading the aggregated value does not require any locking mechanism. |
| 98 | 102 | ||
| @@ -119,6 +123,38 @@ the request. | |||
| 119 | s32 dev_pm_qos_read_value(device): | 123 | s32 dev_pm_qos_read_value(device): |
| 120 | Returns the aggregated value for a given device's constraints list. | 124 | Returns the aggregated value for a given device's constraints list. |
| 121 | 125 | ||
| 126 | enum pm_qos_flags_status dev_pm_qos_flags(device, mask) | ||
| 127 | Check PM QoS flags of the given device against the given mask of flags. | ||
| 128 | The meaning of the return values is as follows: | ||
| 129 | PM_QOS_FLAGS_ALL: All flags from the mask are set | ||
| 130 | PM_QOS_FLAGS_SOME: Some flags from the mask are set | ||
| 131 | PM_QOS_FLAGS_NONE: No flags from the mask are set | ||
| 132 | PM_QOS_FLAGS_UNDEFINED: The device's PM QoS structure has not been | ||
| 133 | initialized or the list of requests is empty. | ||
| 134 | |||
| 135 | int dev_pm_qos_add_ancestor_request(dev, handle, value) | ||
| 136 | Add a PM QoS request for the first direct ancestor of the given device whose | ||
| 137 | power.ignore_children flag is unset. | ||
| 138 | |||
| 139 | int dev_pm_qos_expose_latency_limit(device, value) | ||
| 140 | Add a request to the device's PM QoS list of latency constraints and create | ||
| 141 | a sysfs attribute pm_qos_resume_latency_us under the device's power directory | ||
| 142 | allowing user space to manipulate that request. | ||
| 143 | |||
| 144 | void dev_pm_qos_hide_latency_limit(device) | ||
| 145 | Drop the request added by dev_pm_qos_expose_latency_limit() from the device's | ||
| 146 | PM QoS list of latency constraints and remove sysfs attribute pm_qos_resume_latency_us | ||
| 147 | from the device's power directory. | ||
| 148 | |||
| 149 | int dev_pm_qos_expose_flags(device, value) | ||
| 150 | Add a request to the device's PM QoS list of flags and create sysfs attributes | ||
| 151 | pm_qos_no_power_off and pm_qos_remote_wakeup under the device's power directory | ||
| 152 | allowing user space to change these flags' value. | ||
| 153 | |||
| 154 | void dev_pm_qos_hide_flags(device) | ||
| 155 | Drop the request added by dev_pm_qos_expose_flags() from the device's PM QoS list | ||
| 156 | of flags and remove sysfs attributes pm_qos_no_power_off and pm_qos_remote_wakeup | ||
| 157 | under the device's power directory. | ||
| 122 | 158 | ||
| 123 | Notification mechanisms: | 159 | Notification mechanisms: |
| 124 | The per-device PM QoS framework has 2 different and distinct notification trees: | 160 | The per-device PM QoS framework has 2 different and distinct notification trees: |
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index 6c9f5d9aa115..71d8fe4e75d3 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt | |||
| @@ -144,8 +144,12 @@ The action performed by the idle callback is totally dependent on the subsystem | |||
| 144 | (or driver) in question, but the expected and recommended action is to check | 144 | (or driver) in question, but the expected and recommended action is to check |
| 145 | if the device can be suspended (i.e. if all of the conditions necessary for | 145 | if the device can be suspended (i.e. if all of the conditions necessary for |
| 146 | suspending the device are satisfied) and to queue up a suspend request for the | 146 | suspending the device are satisfied) and to queue up a suspend request for the |
| 147 | device in that case. The value returned by this callback is ignored by the PM | 147 | device in that case. If there is no idle callback, or if the callback returns |
| 148 | core. | 148 | 0, then the PM core will attempt to carry out a runtime suspend of the device; |
| 149 | in essence, it will call pm_runtime_suspend() directly. To prevent this (for | ||
| 150 | example, if the callback routine has started a delayed suspend), the routine | ||
| 151 | should return a non-zero value. Negative error return codes are ignored by the | ||
| 152 | PM core. | ||
| 149 | 153 | ||
| 150 | The helper functions provided by the PM core, described in Section 4, guarantee | 154 | The helper functions provided by the PM core, described in Section 4, guarantee |
| 151 | that the following constraints are met with respect to runtime PM callbacks for | 155 | 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: | |||
| 301 | removing the device from device hierarchy | 305 | removing the device from device hierarchy |
| 302 | 306 | ||
| 303 | int pm_runtime_idle(struct device *dev); | 307 | int pm_runtime_idle(struct device *dev); |
| 304 | - execute the subsystem-level idle callback for the device; returns 0 on | 308 | - execute the subsystem-level idle callback for the device; returns an |
| 305 | success or error code on failure, where -EINPROGRESS means that | 309 | error code on failure, where -EINPROGRESS means that ->runtime_idle() is |
| 306 | ->runtime_idle() is already being executed | 310 | already being executed; if there is no callback or the callback returns 0 |
| 311 | then run pm_runtime_suspend(dev) and return its result | ||
| 307 | 312 | ||
| 308 | int pm_runtime_suspend(struct device *dev); | 313 | int pm_runtime_suspend(struct device *dev); |
| 309 | - execute the subsystem-level suspend callback for the device; returns 0 on | 314 | - 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 | |||
| 660 | management callbacks provided by the PM core, defined in | 665 | management callbacks provided by the PM core, defined in |
| 661 | driver/base/power/generic_ops.c: | 666 | driver/base/power/generic_ops.c: |
| 662 | 667 | ||
| 663 | int pm_generic_runtime_idle(struct device *dev); | ||
| 664 | - invoke the ->runtime_idle() callback provided by the driver of this | ||
| 665 | device, if defined, and call pm_runtime_suspend() for this device if the | ||
| 666 | return value is 0 or the callback is not defined | ||
| 667 | |||
| 668 | int pm_generic_runtime_suspend(struct device *dev); | 668 | int pm_generic_runtime_suspend(struct device *dev); |
| 669 | - invoke the ->runtime_suspend() callback provided by the driver of this | 669 | - invoke the ->runtime_suspend() callback provided by the driver of this |
| 670 | device and return its result, or return -EINVAL if not defined | 670 | device and return its result, or return -EINVAL if not defined |
diff --git a/Documentation/trace/events-power.txt b/Documentation/trace/events-power.txt index e1498ff8cf94..3bd33b8dc7c4 100644 --- a/Documentation/trace/events-power.txt +++ b/Documentation/trace/events-power.txt | |||
| @@ -63,3 +63,34 @@ power_domain_target "%s state=%lu cpu_id=%lu" | |||
| 63 | The first parameter gives the power domain name (e.g. "mpu_pwrdm"). | 63 | The first parameter gives the power domain name (e.g. "mpu_pwrdm"). |
| 64 | The second parameter is the power domain target state. | 64 | The second parameter is the power domain target state. |
| 65 | 65 | ||
| 66 | 4. PM QoS events | ||
| 67 | ================ | ||
| 68 | The PM QoS events are used for QoS add/update/remove request and for | ||
| 69 | target/flags update. | ||
| 70 | |||
| 71 | pm_qos_add_request "pm_qos_class=%s value=%d" | ||
| 72 | pm_qos_update_request "pm_qos_class=%s value=%d" | ||
| 73 | pm_qos_remove_request "pm_qos_class=%s value=%d" | ||
| 74 | pm_qos_update_request_timeout "pm_qos_class=%s value=%d, timeout_us=%ld" | ||
| 75 | |||
| 76 | The first parameter gives the QoS class name (e.g. "CPU_DMA_LATENCY"). | ||
| 77 | The second parameter is value to be added/updated/removed. | ||
| 78 | The third parameter is timeout value in usec. | ||
| 79 | |||
| 80 | pm_qos_update_target "action=%s prev_value=%d curr_value=%d" | ||
| 81 | pm_qos_update_flags "action=%s prev_value=0x%x curr_value=0x%x" | ||
| 82 | |||
| 83 | The first parameter gives the QoS action name (e.g. "ADD_REQ"). | ||
| 84 | The second parameter is the previous QoS value. | ||
| 85 | The third parameter is the current QoS value to update. | ||
| 86 | |||
| 87 | And, there are also events used for device PM QoS add/update/remove request. | ||
| 88 | |||
| 89 | dev_pm_qos_add_request "device=%s type=%s new_value=%d" | ||
| 90 | dev_pm_qos_update_request "device=%s type=%s new_value=%d" | ||
| 91 | dev_pm_qos_remove_request "device=%s type=%s new_value=%d" | ||
| 92 | |||
| 93 | The first parameter gives the device name which tries to add/update/remove | ||
| 94 | QoS requests. | ||
| 95 | The second parameter gives the request type (e.g. "DEV_PM_QOS_LATENCY"). | ||
| 96 | The third parameter is value to be added/updated/removed. | ||
diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c index e6d230700b2b..e37feb2f05a3 100644 --- a/arch/arm/mach-omap2/omap_device.c +++ b/arch/arm/mach-omap2/omap_device.c | |||
| @@ -591,11 +591,6 @@ static int _od_runtime_suspend(struct device *dev) | |||
| 591 | return ret; | 591 | return ret; |
| 592 | } | 592 | } |
| 593 | 593 | ||
| 594 | static int _od_runtime_idle(struct device *dev) | ||
| 595 | { | ||
| 596 | return pm_generic_runtime_idle(dev); | ||
| 597 | } | ||
| 598 | |||
| 599 | static int _od_runtime_resume(struct device *dev) | 594 | static int _od_runtime_resume(struct device *dev) |
| 600 | { | 595 | { |
| 601 | struct platform_device *pdev = to_platform_device(dev); | 596 | struct platform_device *pdev = to_platform_device(dev); |
| @@ -653,7 +648,7 @@ static int _od_resume_noirq(struct device *dev) | |||
| 653 | struct dev_pm_domain omap_device_pm_domain = { | 648 | struct dev_pm_domain omap_device_pm_domain = { |
| 654 | .ops = { | 649 | .ops = { |
| 655 | SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume, | 650 | SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume, |
| 656 | _od_runtime_idle) | 651 | NULL) |
| 657 | USE_PLATFORM_PM_SLEEP_OPS | 652 | USE_PLATFORM_PM_SLEEP_OPS |
| 658 | .suspend_noirq = _od_suspend_noirq, | 653 | .suspend_noirq = _od_suspend_noirq, |
| 659 | .resume_noirq = _od_resume_noirq, | 654 | .resume_noirq = _od_resume_noirq, |
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 5f3597b87f27..67624d4d5aef 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c | |||
| @@ -933,7 +933,6 @@ static struct dev_pm_domain acpi_general_pm_domain = { | |||
| 933 | #ifdef CONFIG_PM_RUNTIME | 933 | #ifdef CONFIG_PM_RUNTIME |
| 934 | .runtime_suspend = acpi_subsys_runtime_suspend, | 934 | .runtime_suspend = acpi_subsys_runtime_suspend, |
| 935 | .runtime_resume = acpi_subsys_runtime_resume, | 935 | .runtime_resume = acpi_subsys_runtime_resume, |
| 936 | .runtime_idle = pm_generic_runtime_idle, | ||
| 937 | #endif | 936 | #endif |
| 938 | #ifdef CONFIG_PM_SLEEP | 937 | #ifdef CONFIG_PM_SLEEP |
| 939 | .prepare = acpi_subsys_prepare, | 938 | .prepare = acpi_subsys_prepare, |
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index cdbad3a454a0..c6707278a6bb 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c | |||
| @@ -284,7 +284,7 @@ static const struct dev_pm_ops amba_pm = { | |||
| 284 | SET_RUNTIME_PM_OPS( | 284 | SET_RUNTIME_PM_OPS( |
| 285 | amba_pm_runtime_suspend, | 285 | amba_pm_runtime_suspend, |
| 286 | amba_pm_runtime_resume, | 286 | amba_pm_runtime_resume, |
| 287 | pm_generic_runtime_idle | 287 | NULL |
| 288 | ) | 288 | ) |
| 289 | }; | 289 | }; |
| 290 | 290 | ||
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index adf002a3c584..6e458a40a93b 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
| @@ -5436,7 +5436,7 @@ static int ata_port_runtime_idle(struct device *dev) | |||
| 5436 | return -EBUSY; | 5436 | return -EBUSY; |
| 5437 | } | 5437 | } |
| 5438 | 5438 | ||
| 5439 | return pm_runtime_suspend(dev); | 5439 | return 0; |
| 5440 | } | 5440 | } |
| 5441 | 5441 | ||
| 5442 | static int ata_port_runtime_suspend(struct device *dev) | 5442 | static int ata_port_runtime_suspend(struct device *dev) |
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 9eda84246ffd..96a930387ebc 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
| @@ -888,7 +888,6 @@ int platform_pm_restore(struct device *dev) | |||
| 888 | static const struct dev_pm_ops platform_dev_pm_ops = { | 888 | static const struct dev_pm_ops platform_dev_pm_ops = { |
| 889 | .runtime_suspend = pm_generic_runtime_suspend, | 889 | .runtime_suspend = pm_generic_runtime_suspend, |
| 890 | .runtime_resume = pm_generic_runtime_resume, | 890 | .runtime_resume = pm_generic_runtime_resume, |
| 891 | .runtime_idle = pm_generic_runtime_idle, | ||
| 892 | USE_PLATFORM_PM_SLEEP_OPS | 891 | USE_PLATFORM_PM_SLEEP_OPS |
| 893 | }; | 892 | }; |
| 894 | 893 | ||
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 7072404c8b6d..bfb8955c406c 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
| @@ -2143,7 +2143,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
| 2143 | genpd->max_off_time_changed = true; | 2143 | genpd->max_off_time_changed = true; |
| 2144 | genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; | 2144 | genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; |
| 2145 | genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; | 2145 | genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; |
| 2146 | genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; | ||
| 2147 | genpd->domain.ops.prepare = pm_genpd_prepare; | 2146 | genpd->domain.ops.prepare = pm_genpd_prepare; |
| 2148 | genpd->domain.ops.suspend = pm_genpd_suspend; | 2147 | genpd->domain.ops.suspend = pm_genpd_suspend; |
| 2149 | genpd->domain.ops.suspend_late = pm_genpd_suspend_late; | 2148 | genpd->domain.ops.suspend_late = pm_genpd_suspend_late; |
diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index bfd898b8988e..5ee030a864f9 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c | |||
| @@ -12,29 +12,6 @@ | |||
| 12 | 12 | ||
| 13 | #ifdef CONFIG_PM_RUNTIME | 13 | #ifdef CONFIG_PM_RUNTIME |
| 14 | /** | 14 | /** |
| 15 | * pm_generic_runtime_idle - Generic runtime idle callback for subsystems. | ||
| 16 | * @dev: Device to handle. | ||
| 17 | * | ||
| 18 | * If PM operations are defined for the @dev's driver and they include | ||
| 19 | * ->runtime_idle(), execute it and return its error code, if nonzero. | ||
| 20 | * Otherwise, execute pm_runtime_suspend() for the device and return 0. | ||
| 21 | */ | ||
| 22 | int pm_generic_runtime_idle(struct device *dev) | ||
| 23 | { | ||
| 24 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
| 25 | |||
| 26 | if (pm && pm->runtime_idle) { | ||
| 27 | int ret = pm->runtime_idle(dev); | ||
| 28 | if (ret) | ||
| 29 | return ret; | ||
| 30 | } | ||
| 31 | |||
| 32 | pm_runtime_suspend(dev); | ||
| 33 | return 0; | ||
| 34 | } | ||
| 35 | EXPORT_SYMBOL_GPL(pm_generic_runtime_idle); | ||
| 36 | |||
| 37 | /** | ||
| 38 | * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. | 15 | * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. |
| 39 | * @dev: Device to suspend. | 16 | * @dev: Device to suspend. |
| 40 | * | 17 | * |
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 71671c42ef45..5c1361a9e5dd 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c | |||
| @@ -42,6 +42,7 @@ | |||
| 42 | #include <linux/export.h> | 42 | #include <linux/export.h> |
| 43 | #include <linux/pm_runtime.h> | 43 | #include <linux/pm_runtime.h> |
| 44 | #include <linux/err.h> | 44 | #include <linux/err.h> |
| 45 | #include <trace/events/power.h> | ||
| 45 | 46 | ||
| 46 | #include "power.h" | 47 | #include "power.h" |
| 47 | 48 | ||
| @@ -305,6 +306,7 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, | |||
| 305 | else if (!dev->power.qos) | 306 | else if (!dev->power.qos) |
| 306 | ret = dev_pm_qos_constraints_allocate(dev); | 307 | ret = dev_pm_qos_constraints_allocate(dev); |
| 307 | 308 | ||
| 309 | trace_dev_pm_qos_add_request(dev_name(dev), type, value); | ||
| 308 | if (!ret) { | 310 | if (!ret) { |
| 309 | req->dev = dev; | 311 | req->dev = dev; |
| 310 | req->type = type; | 312 | req->type = type; |
| @@ -349,6 +351,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req, | |||
| 349 | return -EINVAL; | 351 | return -EINVAL; |
| 350 | } | 352 | } |
| 351 | 353 | ||
| 354 | trace_dev_pm_qos_update_request(dev_name(req->dev), req->type, | ||
| 355 | new_value); | ||
| 352 | if (curr_value != new_value) | 356 | if (curr_value != new_value) |
| 353 | ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value); | 357 | ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value); |
| 354 | 358 | ||
| @@ -398,6 +402,8 @@ static int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req) | |||
| 398 | if (IS_ERR_OR_NULL(req->dev->power.qos)) | 402 | if (IS_ERR_OR_NULL(req->dev->power.qos)) |
| 399 | return -ENODEV; | 403 | return -ENODEV; |
| 400 | 404 | ||
| 405 | trace_dev_pm_qos_remove_request(dev_name(req->dev), req->type, | ||
| 406 | PM_QOS_DEFAULT_VALUE); | ||
| 401 | ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); | 407 | ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); |
| 402 | memset(req, 0, sizeof(*req)); | 408 | memset(req, 0, sizeof(*req)); |
| 403 | return ret; | 409 | return ret; |
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index ef13ad08afb2..268a35097578 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c | |||
| @@ -293,11 +293,8 @@ static int rpm_idle(struct device *dev, int rpmflags) | |||
| 293 | /* Pending requests need to be canceled. */ | 293 | /* Pending requests need to be canceled. */ |
| 294 | dev->power.request = RPM_REQ_NONE; | 294 | dev->power.request = RPM_REQ_NONE; |
| 295 | 295 | ||
| 296 | if (dev->power.no_callbacks) { | 296 | if (dev->power.no_callbacks) |
| 297 | /* Assume ->runtime_idle() callback would have suspended. */ | ||
| 298 | retval = rpm_suspend(dev, rpmflags); | ||
| 299 | goto out; | 297 | goto out; |
| 300 | } | ||
| 301 | 298 | ||
| 302 | /* Carry out an asynchronous or a synchronous idle notification. */ | 299 | /* Carry out an asynchronous or a synchronous idle notification. */ |
| 303 | if (rpmflags & RPM_ASYNC) { | 300 | if (rpmflags & RPM_ASYNC) { |
| @@ -306,7 +303,8 @@ static int rpm_idle(struct device *dev, int rpmflags) | |||
| 306 | dev->power.request_pending = true; | 303 | dev->power.request_pending = true; |
| 307 | queue_work(pm_wq, &dev->power.work); | 304 | queue_work(pm_wq, &dev->power.work); |
| 308 | } | 305 | } |
| 309 | goto out; | 306 | trace_rpm_return_int(dev, _THIS_IP_, 0); |
| 307 | return 0; | ||
| 310 | } | 308 | } |
| 311 | 309 | ||
| 312 | dev->power.idle_notification = true; | 310 | dev->power.idle_notification = true; |
| @@ -326,14 +324,14 @@ static int rpm_idle(struct device *dev, int rpmflags) | |||
| 326 | callback = dev->driver->pm->runtime_idle; | 324 | callback = dev->driver->pm->runtime_idle; |
| 327 | 325 | ||
| 328 | if (callback) | 326 | if (callback) |
| 329 | __rpm_callback(callback, dev); | 327 | retval = __rpm_callback(callback, dev); |
| 330 | 328 | ||
| 331 | dev->power.idle_notification = false; | 329 | dev->power.idle_notification = false; |
| 332 | wake_up_all(&dev->power.wait_queue); | 330 | wake_up_all(&dev->power.wait_queue); |
| 333 | 331 | ||
| 334 | out: | 332 | out: |
| 335 | trace_rpm_return_int(dev, _THIS_IP_, retval); | 333 | trace_rpm_return_int(dev, _THIS_IP_, retval); |
| 336 | return retval; | 334 | return retval ? retval : rpm_suspend(dev, rpmflags); |
| 337 | } | 335 | } |
| 338 | 336 | ||
| 339 | /** | 337 | /** |
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 79715e7fa43e..2d56f4113ae7 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c | |||
| @@ -659,7 +659,7 @@ void pm_wakeup_event(struct device *dev, unsigned int msec) | |||
| 659 | } | 659 | } |
| 660 | EXPORT_SYMBOL_GPL(pm_wakeup_event); | 660 | EXPORT_SYMBOL_GPL(pm_wakeup_event); |
| 661 | 661 | ||
| 662 | static void print_active_wakeup_sources(void) | 662 | void pm_print_active_wakeup_sources(void) |
| 663 | { | 663 | { |
| 664 | struct wakeup_source *ws; | 664 | struct wakeup_source *ws; |
| 665 | int active = 0; | 665 | int active = 0; |
| @@ -683,6 +683,7 @@ static void print_active_wakeup_sources(void) | |||
| 683 | last_activity_ws->name); | 683 | last_activity_ws->name); |
| 684 | rcu_read_unlock(); | 684 | rcu_read_unlock(); |
| 685 | } | 685 | } |
| 686 | EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources); | ||
| 686 | 687 | ||
| 687 | /** | 688 | /** |
| 688 | * pm_wakeup_pending - Check if power transition in progress should be aborted. | 689 | * pm_wakeup_pending - Check if power transition in progress should be aborted. |
| @@ -707,8 +708,10 @@ bool pm_wakeup_pending(void) | |||
| 707 | } | 708 | } |
| 708 | spin_unlock_irqrestore(&events_lock, flags); | 709 | spin_unlock_irqrestore(&events_lock, flags); |
| 709 | 710 | ||
| 710 | if (ret) | 711 | if (ret) { |
| 711 | print_active_wakeup_sources(); | 712 | pr_info("PM: Wakeup pending, aborting suspend\n"); |
| 713 | pm_print_active_wakeup_sources(); | ||
| 714 | } | ||
| 712 | 715 | ||
| 713 | return ret; | 716 | return ret; |
| 714 | } | 717 | } |
diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index a0de82e21a7c..a975ebebea8a 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c | |||
| @@ -1405,7 +1405,7 @@ static int dma_runtime_idle(struct device *dev) | |||
| 1405 | return -EAGAIN; | 1405 | return -EAGAIN; |
| 1406 | } | 1406 | } |
| 1407 | 1407 | ||
| 1408 | return pm_schedule_suspend(dev, 0); | 1408 | return 0; |
| 1409 | } | 1409 | } |
| 1410 | 1410 | ||
| 1411 | /****************************************************************************** | 1411 | /****************************************************************************** |
diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c index 62ef10a641c4..89d0d2a3b1bb 100644 --- a/drivers/gpio/gpio-langwell.c +++ b/drivers/gpio/gpio-langwell.c | |||
| @@ -305,11 +305,7 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = { | |||
| 305 | 305 | ||
| 306 | static int lnw_gpio_runtime_idle(struct device *dev) | 306 | static int lnw_gpio_runtime_idle(struct device *dev) |
| 307 | { | 307 | { |
| 308 | int err = pm_schedule_suspend(dev, 500); | 308 | pm_schedule_suspend(dev, 500); |
| 309 | |||
| 310 | if (!err) | ||
| 311 | return 0; | ||
| 312 | |||
| 313 | return -EBUSY; | 309 | return -EBUSY; |
| 314 | } | 310 | } |
| 315 | 311 | ||
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 48e31ed69dbf..f32ca293ae0e 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
| @@ -435,7 +435,7 @@ static const struct dev_pm_ops i2c_device_pm_ops = { | |||
| 435 | SET_RUNTIME_PM_OPS( | 435 | SET_RUNTIME_PM_OPS( |
| 436 | pm_generic_runtime_suspend, | 436 | pm_generic_runtime_suspend, |
| 437 | pm_generic_runtime_resume, | 437 | pm_generic_runtime_resume, |
| 438 | pm_generic_runtime_idle | 438 | NULL |
| 439 | ) | 439 | ) |
| 440 | }; | 440 | }; |
| 441 | 441 | ||
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 13f7866de46e..3598b0ecf8c7 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c | |||
| @@ -886,12 +886,6 @@ static int ab8500_gpadc_runtime_resume(struct device *dev) | |||
| 886 | return ret; | 886 | return ret; |
| 887 | } | 887 | } |
| 888 | 888 | ||
| 889 | static int ab8500_gpadc_runtime_idle(struct device *dev) | ||
| 890 | { | ||
| 891 | pm_runtime_suspend(dev); | ||
| 892 | return 0; | ||
| 893 | } | ||
| 894 | |||
| 895 | static int ab8500_gpadc_suspend(struct device *dev) | 889 | static int ab8500_gpadc_suspend(struct device *dev) |
| 896 | { | 890 | { |
| 897 | struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); | 891 | struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); |
| @@ -1039,7 +1033,7 @@ static int ab8500_gpadc_remove(struct platform_device *pdev) | |||
| 1039 | static const struct dev_pm_ops ab8500_gpadc_pm_ops = { | 1033 | static const struct dev_pm_ops ab8500_gpadc_pm_ops = { |
| 1040 | SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend, | 1034 | SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend, |
| 1041 | ab8500_gpadc_runtime_resume, | 1035 | ab8500_gpadc_runtime_resume, |
| 1042 | ab8500_gpadc_runtime_idle) | 1036 | NULL) |
| 1043 | SET_SYSTEM_SLEEP_PM_OPS(ab8500_gpadc_suspend, | 1037 | SET_SYSTEM_SLEEP_PM_OPS(ab8500_gpadc_suspend, |
| 1044 | ab8500_gpadc_resume) | 1038 | ab8500_gpadc_resume) |
| 1045 | 1039 | ||
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index e219c97a02a4..9d5c71125576 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c | |||
| @@ -164,7 +164,7 @@ static int mmc_runtime_resume(struct device *dev) | |||
| 164 | 164 | ||
| 165 | static int mmc_runtime_idle(struct device *dev) | 165 | static int mmc_runtime_idle(struct device *dev) |
| 166 | { | 166 | { |
| 167 | return pm_runtime_suspend(dev); | 167 | return 0; |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | #endif /* !CONFIG_PM_RUNTIME */ | 170 | #endif /* !CONFIG_PM_RUNTIME */ |
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 546c67c2bbbf..6d67492a9247 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c | |||
| @@ -211,7 +211,7 @@ static const struct dev_pm_ops sdio_bus_pm_ops = { | |||
| 211 | SET_RUNTIME_PM_OPS( | 211 | SET_RUNTIME_PM_OPS( |
| 212 | pm_generic_runtime_suspend, | 212 | pm_generic_runtime_suspend, |
| 213 | pm_generic_runtime_resume, | 213 | pm_generic_runtime_resume, |
| 214 | pm_generic_runtime_idle | 214 | NULL |
| 215 | ) | 215 | ) |
| 216 | }; | 216 | }; |
| 217 | 217 | ||
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 79277fb36c6b..e6515e21afa3 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
| @@ -1050,26 +1050,22 @@ static int pci_pm_runtime_idle(struct device *dev) | |||
| 1050 | { | 1050 | { |
| 1051 | struct pci_dev *pci_dev = to_pci_dev(dev); | 1051 | struct pci_dev *pci_dev = to_pci_dev(dev); |
| 1052 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | 1052 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
| 1053 | int ret = 0; | ||
| 1053 | 1054 | ||
| 1054 | /* | 1055 | /* |
| 1055 | * If pci_dev->driver is not set (unbound), the device should | 1056 | * If pci_dev->driver is not set (unbound), the device should |
| 1056 | * always remain in D0 regardless of the runtime PM status | 1057 | * always remain in D0 regardless of the runtime PM status |
| 1057 | */ | 1058 | */ |
| 1058 | if (!pci_dev->driver) | 1059 | if (!pci_dev->driver) |
| 1059 | goto out; | 1060 | return 0; |
| 1060 | 1061 | ||
| 1061 | if (!pm) | 1062 | if (!pm) |
| 1062 | return -ENOSYS; | 1063 | return -ENOSYS; |
| 1063 | 1064 | ||
| 1064 | if (pm->runtime_idle) { | 1065 | if (pm->runtime_idle) |
| 1065 | int ret = pm->runtime_idle(dev); | 1066 | ret = pm->runtime_idle(dev); |
| 1066 | if (ret) | ||
| 1067 | return ret; | ||
| 1068 | } | ||
| 1069 | 1067 | ||
| 1070 | out: | 1068 | return ret; |
| 1071 | pm_runtime_suspend(dev); | ||
| 1072 | return 0; | ||
| 1073 | } | 1069 | } |
| 1074 | 1070 | ||
| 1075 | #else /* !CONFIG_PM_RUNTIME */ | 1071 | #else /* !CONFIG_PM_RUNTIME */ |
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index 42539ee2cb11..4c5aabe21755 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c | |||
| @@ -229,8 +229,6 @@ static int scsi_runtime_resume(struct device *dev) | |||
| 229 | 229 | ||
| 230 | static int scsi_runtime_idle(struct device *dev) | 230 | static int scsi_runtime_idle(struct device *dev) |
| 231 | { | 231 | { |
| 232 | int err; | ||
| 233 | |||
| 234 | dev_dbg(dev, "scsi_runtime_idle\n"); | 232 | dev_dbg(dev, "scsi_runtime_idle\n"); |
| 235 | 233 | ||
| 236 | /* Insert hooks here for targets, hosts, and transport classes */ | 234 | /* Insert hooks here for targets, hosts, and transport classes */ |
| @@ -240,14 +238,11 @@ static int scsi_runtime_idle(struct device *dev) | |||
| 240 | 238 | ||
| 241 | if (sdev->request_queue->dev) { | 239 | if (sdev->request_queue->dev) { |
| 242 | pm_runtime_mark_last_busy(dev); | 240 | pm_runtime_mark_last_busy(dev); |
| 243 | err = pm_runtime_autosuspend(dev); | 241 | pm_runtime_autosuspend(dev); |
| 244 | } else { | 242 | return -EBUSY; |
| 245 | err = pm_runtime_suspend(dev); | ||
| 246 | } | 243 | } |
| 247 | } else { | ||
| 248 | err = pm_runtime_suspend(dev); | ||
| 249 | } | 244 | } |
| 250 | return err; | 245 | return 0; |
| 251 | } | 246 | } |
| 252 | 247 | ||
| 253 | int scsi_autopm_get_device(struct scsi_device *sdev) | 248 | int scsi_autopm_get_device(struct scsi_device *sdev) |
diff --git a/drivers/sh/pm_runtime.c b/drivers/sh/pm_runtime.c index afe9282629b9..8afa5a4589f2 100644 --- a/drivers/sh/pm_runtime.c +++ b/drivers/sh/pm_runtime.c | |||
| @@ -25,7 +25,7 @@ | |||
| 25 | static int default_platform_runtime_idle(struct device *dev) | 25 | static int default_platform_runtime_idle(struct device *dev) |
| 26 | { | 26 | { |
| 27 | /* suspend synchronously to disable clocks immediately */ | 27 | /* suspend synchronously to disable clocks immediately */ |
| 28 | return pm_runtime_suspend(dev); | 28 | return 0; |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | static struct dev_pm_domain default_pm_domain = { | 31 | static struct dev_pm_domain default_pm_domain = { |
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 32b7bb111eb6..095cfaded1c0 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
| @@ -223,7 +223,7 @@ static const struct dev_pm_ops spi_pm = { | |||
| 223 | SET_RUNTIME_PM_OPS( | 223 | SET_RUNTIME_PM_OPS( |
| 224 | pm_generic_runtime_suspend, | 224 | pm_generic_runtime_suspend, |
| 225 | pm_generic_runtime_resume, | 225 | pm_generic_runtime_resume, |
| 226 | pm_generic_runtime_idle | 226 | NULL |
| 227 | ) | 227 | ) |
| 228 | }; | 228 | }; |
| 229 | 229 | ||
diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index 5f4765a7a5c5..5dfcf3bae23a 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c | |||
| @@ -1248,13 +1248,8 @@ static int serial_hsu_resume(struct pci_dev *pdev) | |||
| 1248 | #ifdef CONFIG_PM_RUNTIME | 1248 | #ifdef CONFIG_PM_RUNTIME |
| 1249 | static int serial_hsu_runtime_idle(struct device *dev) | 1249 | static int serial_hsu_runtime_idle(struct device *dev) |
| 1250 | { | 1250 | { |
| 1251 | int err; | 1251 | pm_schedule_suspend(dev, 500); |
| 1252 | 1252 | return -EBUSY; | |
| 1253 | err = pm_schedule_suspend(dev, 500); | ||
| 1254 | if (err) | ||
| 1255 | return -EBUSY; | ||
| 1256 | |||
| 1257 | return 0; | ||
| 1258 | } | 1253 | } |
| 1259 | 1254 | ||
| 1260 | static int serial_hsu_runtime_suspend(struct device *dev) | 1255 | static int serial_hsu_runtime_suspend(struct device *dev) |
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 6eab440e1542..7609ac4aed1c 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
| @@ -1765,7 +1765,8 @@ int usb_runtime_idle(struct device *dev) | |||
| 1765 | */ | 1765 | */ |
| 1766 | if (autosuspend_check(udev) == 0) | 1766 | if (autosuspend_check(udev) == 0) |
| 1767 | pm_runtime_autosuspend(dev); | 1767 | pm_runtime_autosuspend(dev); |
| 1768 | return 0; | 1768 | /* Tell the core not to suspend it, though. */ |
| 1769 | return -EBUSY; | ||
| 1769 | } | 1770 | } |
| 1770 | 1771 | ||
| 1771 | int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) | 1772 | int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) |
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index b8bad294eeb8..8c1b2c509467 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c | |||
| @@ -141,7 +141,6 @@ static const struct dev_pm_ops usb_port_pm_ops = { | |||
| 141 | #ifdef CONFIG_PM_RUNTIME | 141 | #ifdef CONFIG_PM_RUNTIME |
| 142 | .runtime_suspend = usb_port_runtime_suspend, | 142 | .runtime_suspend = usb_port_runtime_suspend, |
| 143 | .runtime_resume = usb_port_runtime_resume, | 143 | .runtime_resume = usb_port_runtime_resume, |
| 144 | .runtime_idle = pm_generic_runtime_idle, | ||
| 145 | #endif | 144 | #endif |
| 146 | }; | 145 | }; |
| 147 | 146 | ||
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 7d7e09efff9b..6fa7cea25da9 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h | |||
| @@ -37,7 +37,6 @@ extern void pm_runtime_enable(struct device *dev); | |||
| 37 | extern void __pm_runtime_disable(struct device *dev, bool check_resume); | 37 | extern void __pm_runtime_disable(struct device *dev, bool check_resume); |
| 38 | extern void pm_runtime_allow(struct device *dev); | 38 | extern void pm_runtime_allow(struct device *dev); |
| 39 | extern void pm_runtime_forbid(struct device *dev); | 39 | extern void pm_runtime_forbid(struct device *dev); |
| 40 | extern int pm_generic_runtime_idle(struct device *dev); | ||
| 41 | extern int pm_generic_runtime_suspend(struct device *dev); | 40 | extern int pm_generic_runtime_suspend(struct device *dev); |
| 42 | extern int pm_generic_runtime_resume(struct device *dev); | 41 | extern int pm_generic_runtime_resume(struct device *dev); |
| 43 | extern void pm_runtime_no_callbacks(struct device *dev); | 42 | extern void pm_runtime_no_callbacks(struct device *dev); |
| @@ -143,7 +142,6 @@ static inline bool pm_runtime_active(struct device *dev) { return true; } | |||
| 143 | static inline bool pm_runtime_status_suspended(struct device *dev) { return false; } | 142 | static inline bool pm_runtime_status_suspended(struct device *dev) { return false; } |
| 144 | static inline bool pm_runtime_enabled(struct device *dev) { return false; } | 143 | static inline bool pm_runtime_enabled(struct device *dev) { return false; } |
| 145 | 144 | ||
| 146 | static inline int pm_generic_runtime_idle(struct device *dev) { return 0; } | ||
| 147 | static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; } | 145 | static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; } |
| 148 | static inline int pm_generic_runtime_resume(struct device *dev) { return 0; } | 146 | static inline int pm_generic_runtime_resume(struct device *dev) { return 0; } |
| 149 | static inline void pm_runtime_no_callbacks(struct device *dev) {} | 147 | static inline void pm_runtime_no_callbacks(struct device *dev) {} |
diff --git a/include/linux/suspend.h b/include/linux/suspend.h index d4e3f16d5e89..f73cabf59012 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h | |||
| @@ -363,6 +363,7 @@ extern bool pm_wakeup_pending(void); | |||
| 363 | extern bool pm_get_wakeup_count(unsigned int *count, bool block); | 363 | extern bool pm_get_wakeup_count(unsigned int *count, bool block); |
| 364 | extern bool pm_save_wakeup_count(unsigned int count); | 364 | extern bool pm_save_wakeup_count(unsigned int count); |
| 365 | extern void pm_wakep_autosleep_enabled(bool set); | 365 | extern void pm_wakep_autosleep_enabled(bool set); |
| 366 | extern void pm_print_active_wakeup_sources(void); | ||
| 366 | 367 | ||
| 367 | static inline void lock_system_sleep(void) | 368 | static inline void lock_system_sleep(void) |
| 368 | { | 369 | { |
diff --git a/include/trace/events/power.h b/include/trace/events/power.h index 427acab5d69a..8e42410bd159 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #define _TRACE_POWER_H | 5 | #define _TRACE_POWER_H |
| 6 | 6 | ||
| 7 | #include <linux/ktime.h> | 7 | #include <linux/ktime.h> |
| 8 | #include <linux/pm_qos.h> | ||
| 8 | #include <linux/tracepoint.h> | 9 | #include <linux/tracepoint.h> |
| 9 | 10 | ||
| 10 | DECLARE_EVENT_CLASS(cpu, | 11 | DECLARE_EVENT_CLASS(cpu, |
| @@ -177,6 +178,178 @@ DEFINE_EVENT(power_domain, power_domain_target, | |||
| 177 | 178 | ||
| 178 | TP_ARGS(name, state, cpu_id) | 179 | TP_ARGS(name, state, cpu_id) |
| 179 | ); | 180 | ); |
| 181 | |||
| 182 | /* | ||
| 183 | * The pm qos events are used for pm qos update | ||
| 184 | */ | ||
| 185 | DECLARE_EVENT_CLASS(pm_qos_request, | ||
| 186 | |||
| 187 | TP_PROTO(int pm_qos_class, s32 value), | ||
| 188 | |||
| 189 | TP_ARGS(pm_qos_class, value), | ||
| 190 | |||
| 191 | TP_STRUCT__entry( | ||
| 192 | __field( int, pm_qos_class ) | ||
| 193 | __field( s32, value ) | ||
| 194 | ), | ||
| 195 | |||
| 196 | TP_fast_assign( | ||
| 197 | __entry->pm_qos_class = pm_qos_class; | ||
| 198 | __entry->value = value; | ||
| 199 | ), | ||
| 200 | |||
| 201 | TP_printk("pm_qos_class=%s value=%d", | ||
| 202 | __print_symbolic(__entry->pm_qos_class, | ||
| 203 | { PM_QOS_CPU_DMA_LATENCY, "CPU_DMA_LATENCY" }, | ||
| 204 | { PM_QOS_NETWORK_LATENCY, "NETWORK_LATENCY" }, | ||
| 205 | { PM_QOS_NETWORK_THROUGHPUT, "NETWORK_THROUGHPUT" }), | ||
| 206 | __entry->value) | ||
| 207 | ); | ||
| 208 | |||
| 209 | DEFINE_EVENT(pm_qos_request, pm_qos_add_request, | ||
| 210 | |||
| 211 | TP_PROTO(int pm_qos_class, s32 value), | ||
| 212 | |||
| 213 | TP_ARGS(pm_qos_class, value) | ||
| 214 | ); | ||
| 215 | |||
| 216 | DEFINE_EVENT(pm_qos_request, pm_qos_update_request, | ||
| 217 | |||
| 218 | TP_PROTO(int pm_qos_class, s32 value), | ||
| 219 | |||
| 220 | TP_ARGS(pm_qos_class, value) | ||
| 221 | ); | ||
| 222 | |||
| 223 | DEFINE_EVENT(pm_qos_request, pm_qos_remove_request, | ||
| 224 | |||
| 225 | TP_PROTO(int pm_qos_class, s32 value), | ||
| 226 | |||
| 227 | TP_ARGS(pm_qos_class, value) | ||
| 228 | ); | ||
| 229 | |||
| 230 | TRACE_EVENT(pm_qos_update_request_timeout, | ||
| 231 | |||
| 232 | TP_PROTO(int pm_qos_class, s32 value, unsigned long timeout_us), | ||
| 233 | |||
| 234 | TP_ARGS(pm_qos_class, value, timeout_us), | ||
| 235 | |||
| 236 | TP_STRUCT__entry( | ||
| 237 | __field( int, pm_qos_class ) | ||
| 238 | __field( s32, value ) | ||
| 239 | __field( unsigned long, timeout_us ) | ||
| 240 | ), | ||
| 241 | |||
| 242 | TP_fast_assign( | ||
| 243 | __entry->pm_qos_class = pm_qos_class; | ||
| 244 | __entry->value = value; | ||
| 245 | __entry->timeout_us = timeout_us; | ||
| 246 | ), | ||
| 247 | |||
| 248 | TP_printk("pm_qos_class=%s value=%d, timeout_us=%ld", | ||
| 249 | __print_symbolic(__entry->pm_qos_class, | ||
| 250 | { PM_QOS_CPU_DMA_LATENCY, "CPU_DMA_LATENCY" }, | ||
| 251 | { PM_QOS_NETWORK_LATENCY, "NETWORK_LATENCY" }, | ||
| 252 | { PM_QOS_NETWORK_THROUGHPUT, "NETWORK_THROUGHPUT" }), | ||
| 253 | __entry->value, __entry->timeout_us) | ||
| 254 | ); | ||
| 255 | |||
| 256 | DECLARE_EVENT_CLASS(pm_qos_update, | ||
| 257 | |||
| 258 | TP_PROTO(enum pm_qos_req_action action, int prev_value, int curr_value), | ||
| 259 | |||
| 260 | TP_ARGS(action, prev_value, curr_value), | ||
| 261 | |||
| 262 | TP_STRUCT__entry( | ||
| 263 | __field( enum pm_qos_req_action, action ) | ||
| 264 | __field( int, prev_value ) | ||
| 265 | __field( int, curr_value ) | ||
| 266 | ), | ||
| 267 | |||
| 268 | TP_fast_assign( | ||
| 269 | __entry->action = action; | ||
| 270 | __entry->prev_value = prev_value; | ||
| 271 | __entry->curr_value = curr_value; | ||
| 272 | ), | ||
| 273 | |||
| 274 | TP_printk("action=%s prev_value=%d curr_value=%d", | ||
| 275 | __print_symbolic(__entry->action, | ||
| 276 | { PM_QOS_ADD_REQ, "ADD_REQ" }, | ||
| 277 | { PM_QOS_UPDATE_REQ, "UPDATE_REQ" }, | ||
| 278 | { PM_QOS_REMOVE_REQ, "REMOVE_REQ" }), | ||
| 279 | __entry->prev_value, __entry->curr_value) | ||
| 280 | ); | ||
| 281 | |||
| 282 | DEFINE_EVENT(pm_qos_update, pm_qos_update_target, | ||
| 283 | |||
| 284 | TP_PROTO(enum pm_qos_req_action action, int prev_value, int curr_value), | ||
| 285 | |||
| 286 | TP_ARGS(action, prev_value, curr_value) | ||
| 287 | ); | ||
| 288 | |||
| 289 | DEFINE_EVENT_PRINT(pm_qos_update, pm_qos_update_flags, | ||
| 290 | |||
| 291 | TP_PROTO(enum pm_qos_req_action action, int prev_value, int curr_value), | ||
| 292 | |||
| 293 | TP_ARGS(action, prev_value, curr_value), | ||
| 294 | |||
| 295 | TP_printk("action=%s prev_value=0x%x curr_value=0x%x", | ||
| 296 | __print_symbolic(__entry->action, | ||
| 297 | { PM_QOS_ADD_REQ, "ADD_REQ" }, | ||
| 298 | { PM_QOS_UPDATE_REQ, "UPDATE_REQ" }, | ||
| 299 | { PM_QOS_REMOVE_REQ, "REMOVE_REQ" }), | ||
| 300 | __entry->prev_value, __entry->curr_value) | ||
| 301 | ); | ||
| 302 | |||
| 303 | DECLARE_EVENT_CLASS(dev_pm_qos_request, | ||
| 304 | |||
| 305 | TP_PROTO(const char *name, enum dev_pm_qos_req_type type, | ||
| 306 | s32 new_value), | ||
| 307 | |||
| 308 | TP_ARGS(name, type, new_value), | ||
| 309 | |||
| 310 | TP_STRUCT__entry( | ||
| 311 | __string( name, name ) | ||
| 312 | __field( enum dev_pm_qos_req_type, type ) | ||
| 313 | __field( s32, new_value ) | ||
| 314 | ), | ||
| 315 | |||
| 316 | TP_fast_assign( | ||
| 317 | __assign_str(name, name); | ||
| 318 | __entry->type = type; | ||
| 319 | __entry->new_value = new_value; | ||
| 320 | ), | ||
| 321 | |||
| 322 | TP_printk("device=%s type=%s new_value=%d", | ||
| 323 | __get_str(name), | ||
| 324 | __print_symbolic(__entry->type, | ||
| 325 | { DEV_PM_QOS_LATENCY, "DEV_PM_QOS_LATENCY" }, | ||
| 326 | { DEV_PM_QOS_FLAGS, "DEV_PM_QOS_FLAGS" }), | ||
| 327 | __entry->new_value) | ||
| 328 | ); | ||
| 329 | |||
| 330 | DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_add_request, | ||
| 331 | |||
| 332 | TP_PROTO(const char *name, enum dev_pm_qos_req_type type, | ||
| 333 | s32 new_value), | ||
| 334 | |||
| 335 | TP_ARGS(name, type, new_value) | ||
| 336 | ); | ||
| 337 | |||
| 338 | DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_update_request, | ||
| 339 | |||
| 340 | TP_PROTO(const char *name, enum dev_pm_qos_req_type type, | ||
| 341 | s32 new_value), | ||
| 342 | |||
| 343 | TP_ARGS(name, type, new_value) | ||
| 344 | ); | ||
| 345 | |||
| 346 | DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_remove_request, | ||
| 347 | |||
| 348 | TP_PROTO(const char *name, enum dev_pm_qos_req_type type, | ||
| 349 | s32 new_value), | ||
| 350 | |||
| 351 | TP_ARGS(name, type, new_value) | ||
| 352 | ); | ||
| 180 | #endif /* _TRACE_POWER_H */ | 353 | #endif /* _TRACE_POWER_H */ |
| 181 | 354 | ||
| 182 | /* This part must be outside protection */ | 355 | /* This part must be outside protection */ |
diff --git a/kernel/power/main.c b/kernel/power/main.c index d77663bfedeb..0828070d38b4 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
| @@ -424,6 +424,8 @@ static ssize_t wakeup_count_store(struct kobject *kobj, | |||
| 424 | if (sscanf(buf, "%u", &val) == 1) { | 424 | if (sscanf(buf, "%u", &val) == 1) { |
| 425 | if (pm_save_wakeup_count(val)) | 425 | if (pm_save_wakeup_count(val)) |
| 426 | error = n; | 426 | error = n; |
| 427 | else | ||
| 428 | pm_print_active_wakeup_sources(); | ||
| 427 | } | 429 | } |
| 428 | 430 | ||
| 429 | out: | 431 | out: |
diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 587dddeebf15..06fe28589e9c 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c | |||
| @@ -44,6 +44,7 @@ | |||
| 44 | 44 | ||
| 45 | #include <linux/uaccess.h> | 45 | #include <linux/uaccess.h> |
| 46 | #include <linux/export.h> | 46 | #include <linux/export.h> |
| 47 | #include <trace/events/power.h> | ||
| 47 | 48 | ||
| 48 | /* | 49 | /* |
| 49 | * locking rule: all changes to constraints or notifiers lists | 50 | * locking rule: all changes to constraints or notifiers lists |
| @@ -202,6 +203,7 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, | |||
| 202 | 203 | ||
| 203 | spin_unlock_irqrestore(&pm_qos_lock, flags); | 204 | spin_unlock_irqrestore(&pm_qos_lock, flags); |
| 204 | 205 | ||
| 206 | trace_pm_qos_update_target(action, prev_value, curr_value); | ||
| 205 | if (prev_value != curr_value) { | 207 | if (prev_value != curr_value) { |
| 206 | blocking_notifier_call_chain(c->notifiers, | 208 | blocking_notifier_call_chain(c->notifiers, |
| 207 | (unsigned long)curr_value, | 209 | (unsigned long)curr_value, |
| @@ -272,6 +274,7 @@ bool pm_qos_update_flags(struct pm_qos_flags *pqf, | |||
| 272 | 274 | ||
| 273 | spin_unlock_irqrestore(&pm_qos_lock, irqflags); | 275 | spin_unlock_irqrestore(&pm_qos_lock, irqflags); |
| 274 | 276 | ||
| 277 | trace_pm_qos_update_flags(action, prev_value, curr_value); | ||
| 275 | return prev_value != curr_value; | 278 | return prev_value != curr_value; |
| 276 | } | 279 | } |
| 277 | 280 | ||
| @@ -333,6 +336,7 @@ void pm_qos_add_request(struct pm_qos_request *req, | |||
| 333 | } | 336 | } |
| 334 | req->pm_qos_class = pm_qos_class; | 337 | req->pm_qos_class = pm_qos_class; |
| 335 | INIT_DELAYED_WORK(&req->work, pm_qos_work_fn); | 338 | INIT_DELAYED_WORK(&req->work, pm_qos_work_fn); |
| 339 | trace_pm_qos_add_request(pm_qos_class, value); | ||
| 336 | pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints, | 340 | pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints, |
| 337 | &req->node, PM_QOS_ADD_REQ, value); | 341 | &req->node, PM_QOS_ADD_REQ, value); |
| 338 | } | 342 | } |
| @@ -361,6 +365,7 @@ void pm_qos_update_request(struct pm_qos_request *req, | |||
| 361 | 365 | ||
| 362 | cancel_delayed_work_sync(&req->work); | 366 | cancel_delayed_work_sync(&req->work); |
| 363 | 367 | ||
| 368 | trace_pm_qos_update_request(req->pm_qos_class, new_value); | ||
| 364 | if (new_value != req->node.prio) | 369 | if (new_value != req->node.prio) |
| 365 | pm_qos_update_target( | 370 | pm_qos_update_target( |
| 366 | pm_qos_array[req->pm_qos_class]->constraints, | 371 | pm_qos_array[req->pm_qos_class]->constraints, |
| @@ -387,6 +392,8 @@ void pm_qos_update_request_timeout(struct pm_qos_request *req, s32 new_value, | |||
| 387 | 392 | ||
| 388 | cancel_delayed_work_sync(&req->work); | 393 | cancel_delayed_work_sync(&req->work); |
| 389 | 394 | ||
| 395 | trace_pm_qos_update_request_timeout(req->pm_qos_class, | ||
| 396 | new_value, timeout_us); | ||
| 390 | if (new_value != req->node.prio) | 397 | if (new_value != req->node.prio) |
| 391 | pm_qos_update_target( | 398 | pm_qos_update_target( |
| 392 | pm_qos_array[req->pm_qos_class]->constraints, | 399 | pm_qos_array[req->pm_qos_class]->constraints, |
| @@ -416,6 +423,7 @@ void pm_qos_remove_request(struct pm_qos_request *req) | |||
| 416 | 423 | ||
| 417 | cancel_delayed_work_sync(&req->work); | 424 | cancel_delayed_work_sync(&req->work); |
| 418 | 425 | ||
| 426 | trace_pm_qos_remove_request(req->pm_qos_class, PM_QOS_DEFAULT_VALUE); | ||
| 419 | pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints, | 427 | pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints, |
| 420 | &req->node, PM_QOS_REMOVE_REQ, | 428 | &req->node, PM_QOS_REMOVE_REQ, |
| 421 | PM_QOS_DEFAULT_VALUE); | 429 | PM_QOS_DEFAULT_VALUE); |
| @@ -477,7 +485,7 @@ static int find_pm_qos_object_by_minor(int minor) | |||
| 477 | { | 485 | { |
| 478 | int pm_qos_class; | 486 | int pm_qos_class; |
| 479 | 487 | ||
| 480 | for (pm_qos_class = 0; | 488 | for (pm_qos_class = PM_QOS_CPU_DMA_LATENCY; |
| 481 | pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) { | 489 | pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) { |
| 482 | if (minor == | 490 | if (minor == |
| 483 | pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor) | 491 | pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor) |
| @@ -491,7 +499,7 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp) | |||
| 491 | long pm_qos_class; | 499 | long pm_qos_class; |
| 492 | 500 | ||
| 493 | pm_qos_class = find_pm_qos_object_by_minor(iminor(inode)); | 501 | pm_qos_class = find_pm_qos_object_by_minor(iminor(inode)); |
| 494 | if (pm_qos_class >= 0) { | 502 | if (pm_qos_class >= PM_QOS_CPU_DMA_LATENCY) { |
| 495 | struct pm_qos_request *req = kzalloc(sizeof(*req), GFP_KERNEL); | 503 | struct pm_qos_request *req = kzalloc(sizeof(*req), GFP_KERNEL); |
| 496 | if (!req) | 504 | if (!req) |
| 497 | return -ENOMEM; | 505 | return -ENOMEM; |
| @@ -584,7 +592,7 @@ static int __init pm_qos_power_init(void) | |||
| 584 | 592 | ||
| 585 | BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES); | 593 | BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES); |
| 586 | 594 | ||
| 587 | for (i = 1; i < PM_QOS_NUM_CLASSES; i++) { | 595 | for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) { |
| 588 | ret = register_pm_qos_misc(pm_qos_array[i]); | 596 | ret = register_pm_qos_misc(pm_qos_array[i]); |
| 589 | if (ret < 0) { | 597 | if (ret < 0) { |
| 590 | printk(KERN_ERR "pm_qos_param: %s setup failed\n", | 598 | printk(KERN_ERR "pm_qos_param: %s setup failed\n", |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 0de28576807d..7872a35eafe7 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
| @@ -642,8 +642,9 @@ __register_nosave_region(unsigned long start_pfn, unsigned long end_pfn, | |||
| 642 | region->end_pfn = end_pfn; | 642 | region->end_pfn = end_pfn; |
| 643 | list_add_tail(®ion->list, &nosave_regions); | 643 | list_add_tail(®ion->list, &nosave_regions); |
| 644 | Report: | 644 | Report: |
| 645 | printk(KERN_INFO "PM: Registered nosave memory: %016lx - %016lx\n", | 645 | printk(KERN_INFO "PM: Registered nosave memory: [mem %#010llx-%#010llx]\n", |
| 646 | start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT); | 646 | (unsigned long long) start_pfn << PAGE_SHIFT, |
| 647 | ((unsigned long long) end_pfn << PAGE_SHIFT) - 1); | ||
| 647 | } | 648 | } |
| 648 | 649 | ||
| 649 | /* | 650 | /* |
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index bef86d121eb2..ece04223bb1e 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
| @@ -269,7 +269,7 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
| 269 | suspend_test_start(); | 269 | suspend_test_start(); |
| 270 | error = dpm_suspend_start(PMSG_SUSPEND); | 270 | error = dpm_suspend_start(PMSG_SUSPEND); |
| 271 | if (error) { | 271 | if (error) { |
| 272 | printk(KERN_ERR "PM: Some devices failed to suspend\n"); | 272 | pr_err("PM: Some devices failed to suspend, or early wake event detected\n"); |
| 273 | goto Recover_platform; | 273 | goto Recover_platform; |
| 274 | } | 274 | } |
| 275 | suspend_test_finish("suspend devices"); | 275 | suspend_test_finish("suspend devices"); |
