aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/runtime.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/power/runtime.c')
-rw-r--r--drivers/base/power/runtime.c54
1 files changed, 47 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;