aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/power/runtime.c54
-rw-r--r--drivers/base/power/sysfs.c30
-rw-r--r--include/linux/pm.h6
3 files changed, 83 insertions, 7 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index b0ec0e9f27e9..b78c401ffa73 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -123,6 +123,45 @@ int pm_runtime_idle(struct device *dev)
123} 123}
124EXPORT_SYMBOL_GPL(pm_runtime_idle); 124EXPORT_SYMBOL_GPL(pm_runtime_idle);
125 125
126
127/**
128 * update_pm_runtime_accounting - Update the time accounting of power states
129 * @dev: Device to update the accounting for
130 *
131 * In order to be able to have time accounting of the various power states
132 * (as used by programs such as PowerTOP to show the effectiveness of runtime
133 * PM), we need to track the time spent in each state.
134 * update_pm_runtime_accounting must be called each time before the
135 * runtime_status field is updated, to account the time in the old state
136 * correctly.
137 */
138void update_pm_runtime_accounting(struct device *dev)
139{
140 unsigned long now = jiffies;
141 int delta;
142
143 delta = now - dev->power.accounting_timestamp;
144
145 if (delta < 0)
146 delta = 0;
147
148 dev->power.accounting_timestamp = now;
149
150 if (dev->power.disable_depth > 0)
151 return;
152
153 if (dev->power.runtime_status == RPM_SUSPENDED)
154 dev->power.suspended_jiffies += delta;
155 else
156 dev->power.active_jiffies += delta;
157}
158
159static void __update_runtime_status(struct device *dev, enum rpm_status status)
160{
161 update_pm_runtime_accounting(dev);
162 dev->power.runtime_status = status;
163}
164
126/** 165/**
127 * __pm_runtime_suspend - Carry out run-time suspend of given device. 166 * __pm_runtime_suspend - Carry out run-time suspend of given device.
128 * @dev: Device to suspend. 167 * @dev: Device to suspend.
@@ -197,7 +236,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
197 goto repeat; 236 goto repeat;
198 } 237 }
199 238
200 dev->power.runtime_status = RPM_SUSPENDING; 239 __update_runtime_status(dev, RPM_SUSPENDING);
201 dev->power.deferred_resume = false; 240 dev->power.deferred_resume = false;
202 241
203 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) { 242 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
@@ -228,7 +267,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
228 } 267 }
229 268
230 if (retval) { 269 if (retval) {
231 dev->power.runtime_status = RPM_ACTIVE; 270 __update_runtime_status(dev, RPM_ACTIVE);
232 if (retval == -EAGAIN || retval == -EBUSY) { 271 if (retval == -EAGAIN || retval == -EBUSY) {
233 if (dev->power.timer_expires == 0) 272 if (dev->power.timer_expires == 0)
234 notify = true; 273 notify = true;
@@ -237,7 +276,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
237 pm_runtime_cancel_pending(dev); 276 pm_runtime_cancel_pending(dev);
238 } 277 }
239 } else { 278 } else {
240 dev->power.runtime_status = RPM_SUSPENDED; 279 __update_runtime_status(dev, RPM_SUSPENDED);
241 pm_runtime_deactivate_timer(dev); 280 pm_runtime_deactivate_timer(dev);
242 281
243 if (dev->parent) { 282 if (dev->parent) {
@@ -381,7 +420,7 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
381 goto repeat; 420 goto repeat;
382 } 421 }
383 422
384 dev->power.runtime_status = RPM_RESUMING; 423 __update_runtime_status(dev, RPM_RESUMING);
385 424
386 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) { 425 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {
387 spin_unlock_irq(&dev->power.lock); 426 spin_unlock_irq(&dev->power.lock);
@@ -411,10 +450,10 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
411 } 450 }
412 451
413 if (retval) { 452 if (retval) {
414 dev->power.runtime_status = RPM_SUSPENDED; 453 __update_runtime_status(dev, RPM_SUSPENDED);
415 pm_runtime_cancel_pending(dev); 454 pm_runtime_cancel_pending(dev);
416 } else { 455 } else {
417 dev->power.runtime_status = RPM_ACTIVE; 456 __update_runtime_status(dev, RPM_ACTIVE);
418 if (parent) 457 if (parent)
419 atomic_inc(&parent->power.child_count); 458 atomic_inc(&parent->power.child_count);
420 } 459 }
@@ -848,7 +887,7 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
848 } 887 }
849 888
850 out_set: 889 out_set:
851 dev->power.runtime_status = status; 890 __update_runtime_status(dev, status);
852 dev->power.runtime_error = 0; 891 dev->power.runtime_error = 0;
853 out: 892 out:
854 spin_unlock_irqrestore(&dev->power.lock, flags); 893 spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -1077,6 +1116,7 @@ void pm_runtime_init(struct device *dev)
1077 dev->power.request_pending = false; 1116 dev->power.request_pending = false;
1078 dev->power.request = RPM_REQ_NONE; 1117 dev->power.request = RPM_REQ_NONE;
1079 dev->power.deferred_resume = false; 1118 dev->power.deferred_resume = false;
1119 dev->power.accounting_timestamp = jiffies;
1080 INIT_WORK(&dev->power.work, pm_runtime_work); 1120 INIT_WORK(&dev->power.work, pm_runtime_work);
1081 1121
1082 dev->power.timer_expires = 0; 1122 dev->power.timer_expires = 0;
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 1eca50c8e7ca..e56b4388fe61 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -6,6 +6,7 @@
6#include <linux/string.h> 6#include <linux/string.h>
7#include <linux/pm_runtime.h> 7#include <linux/pm_runtime.h>
8#include <asm/atomic.h> 8#include <asm/atomic.h>
9#include <linux/jiffies.h>
9#include "power.h" 10#include "power.h"
10 11
11/* 12/*
@@ -111,6 +112,33 @@ static ssize_t control_store(struct device * dev, struct device_attribute *attr,
111 112
112static DEVICE_ATTR(control, 0644, control_show, control_store); 113static DEVICE_ATTR(control, 0644, control_show, control_store);
113 114
115static ssize_t rtpm_active_time_show(struct device *dev,
116 struct device_attribute *attr, char *buf)
117{
118 int ret;
119 spin_lock_irq(&dev->power.lock);
120 update_pm_runtime_accounting(dev);
121 ret = sprintf(buf, "%i\n", jiffies_to_msecs(dev->power.active_jiffies));
122 spin_unlock_irq(&dev->power.lock);
123 return ret;
124}
125
126static DEVICE_ATTR(runtime_active_time, 0444, rtpm_active_time_show, NULL);
127
128static ssize_t rtpm_suspended_time_show(struct device *dev,
129 struct device_attribute *attr, char *buf)
130{
131 int ret;
132 spin_lock_irq(&dev->power.lock);
133 update_pm_runtime_accounting(dev);
134 ret = sprintf(buf, "%i\n",
135 jiffies_to_msecs(dev->power.suspended_jiffies));
136 spin_unlock_irq(&dev->power.lock);
137 return ret;
138}
139
140static DEVICE_ATTR(runtime_suspended_time, 0444, rtpm_suspended_time_show, NULL);
141
114static ssize_t rtpm_status_show(struct device *dev, 142static ssize_t rtpm_status_show(struct device *dev,
115 struct device_attribute *attr, char *buf) 143 struct device_attribute *attr, char *buf)
116{ 144{
@@ -254,6 +282,8 @@ static struct attribute * power_attrs[] = {
254#ifdef CONFIG_PM_RUNTIME 282#ifdef CONFIG_PM_RUNTIME
255 &dev_attr_control.attr, 283 &dev_attr_control.attr,
256 &dev_attr_runtime_status.attr, 284 &dev_attr_runtime_status.attr,
285 &dev_attr_runtime_suspended_time.attr,
286 &dev_attr_runtime_active_time.attr,
257#endif 287#endif
258 &dev_attr_wakeup.attr, 288 &dev_attr_wakeup.attr,
259#ifdef CONFIG_PM_SLEEP 289#ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/pm.h b/include/linux/pm.h
index b417fc46f3fc..52e8c55ff314 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -477,9 +477,15 @@ struct dev_pm_info {
477 enum rpm_request request; 477 enum rpm_request request;
478 enum rpm_status runtime_status; 478 enum rpm_status runtime_status;
479 int runtime_error; 479 int runtime_error;
480 unsigned long active_jiffies;
481 unsigned long suspended_jiffies;
482 unsigned long accounting_timestamp;
480#endif 483#endif
481}; 484};
482 485
486extern void update_pm_runtime_accounting(struct device *dev);
487
488
483/* 489/*
484 * The PM_EVENT_ messages are also used by drivers implementing the legacy 490 * The PM_EVENT_ messages are also used by drivers implementing the legacy
485 * suspend framework, based on the ->suspend() and ->resume() callbacks common 491 * suspend framework, based on the ->suspend() and ->resume() callbacks common