aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-12-25 17:43:05 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2011-12-25 17:43:05 -0500
commit0015afaa1f818d38ea9f8e81a84a6aeeca5fdaf0 (patch)
tree8f8279cf0117d210230ef9fcacb05f960bf6f8f5
parentb7ba68c4a072c9aa8f04b8cf7838b6cd2f48d918 (diff)
parent00dc9ad18d707f36b2fb4af98fd2cf0548d2b258 (diff)
Merge branch 'pm-runtime' into pm-for-linus
* pm-runtime: PM / Runtime: Use device PM QoS constraints (v2)
-rw-r--r--drivers/base/power/qos.c24
-rw-r--r--drivers/base/power/runtime.c148
-rw-r--r--include/linux/pm.h2
-rw-r--r--include/linux/pm_qos.h3
-rw-r--r--include/linux/pm_runtime.h5
5 files changed, 154 insertions, 28 deletions
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 86de6c50fc41..03f4bd069ca8 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -47,21 +47,29 @@ static DEFINE_MUTEX(dev_pm_qos_mtx);
47static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); 47static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
48 48
49/** 49/**
50 * dev_pm_qos_read_value - Get PM QoS constraint for a given device. 50 * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
51 * @dev: Device to get the PM QoS constraint value for.
52 *
53 * This routine must be called with dev->power.lock held.
54 */
55s32 __dev_pm_qos_read_value(struct device *dev)
56{
57 struct pm_qos_constraints *c = dev->power.constraints;
58
59 return c ? pm_qos_read_value(c) : 0;
60}
61
62/**
63 * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
51 * @dev: Device to get the PM QoS constraint value for. 64 * @dev: Device to get the PM QoS constraint value for.
52 */ 65 */
53s32 dev_pm_qos_read_value(struct device *dev) 66s32 dev_pm_qos_read_value(struct device *dev)
54{ 67{
55 struct pm_qos_constraints *c;
56 unsigned long flags; 68 unsigned long flags;
57 s32 ret = 0; 69 s32 ret;
58 70
59 spin_lock_irqsave(&dev->power.lock, flags); 71 spin_lock_irqsave(&dev->power.lock, flags);
60 72 ret = __dev_pm_qos_read_value(dev);
61 c = dev->power.constraints;
62 if (c)
63 ret = pm_qos_read_value(c);
64
65 spin_unlock_irqrestore(&dev->power.lock, flags); 73 spin_unlock_irqrestore(&dev->power.lock, flags);
66 74
67 return ret; 75 return ret;
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index c56efd756531..541f821d4ea6 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -282,6 +282,47 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
282 return retval != -EACCES ? retval : -EIO; 282 return retval != -EACCES ? retval : -EIO;
283} 283}
284 284
285struct rpm_qos_data {
286 ktime_t time_now;
287 s64 constraint_ns;
288};
289
290/**
291 * rpm_update_qos_constraint - Update a given PM QoS constraint data.
292 * @dev: Device whose timing data to use.
293 * @data: PM QoS constraint data to update.
294 *
295 * Use the suspend timing data of @dev to update PM QoS constraint data pointed
296 * to by @data.
297 */
298static int rpm_update_qos_constraint(struct device *dev, void *data)
299{
300 struct rpm_qos_data *qos = data;
301 unsigned long flags;
302 s64 delta_ns;
303 int ret = 0;
304
305 spin_lock_irqsave(&dev->power.lock, flags);
306
307 if (dev->power.max_time_suspended_ns < 0)
308 goto out;
309
310 delta_ns = dev->power.max_time_suspended_ns -
311 ktime_to_ns(ktime_sub(qos->time_now, dev->power.suspend_time));
312 if (delta_ns <= 0) {
313 ret = -EBUSY;
314 goto out;
315 }
316
317 if (qos->constraint_ns > delta_ns || qos->constraint_ns == 0)
318 qos->constraint_ns = delta_ns;
319
320 out:
321 spin_unlock_irqrestore(&dev->power.lock, flags);
322
323 return ret;
324}
325
285/** 326/**
286 * rpm_suspend - Carry out runtime suspend of given device. 327 * rpm_suspend - Carry out runtime suspend of given device.
287 * @dev: Device to suspend. 328 * @dev: Device to suspend.
@@ -308,6 +349,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
308{ 349{
309 int (*callback)(struct device *); 350 int (*callback)(struct device *);
310 struct device *parent = NULL; 351 struct device *parent = NULL;
352 struct rpm_qos_data qos;
311 int retval; 353 int retval;
312 354
313 trace_rpm_suspend(dev, rpmflags); 355 trace_rpm_suspend(dev, rpmflags);
@@ -403,8 +445,38 @@ static int rpm_suspend(struct device *dev, int rpmflags)
403 goto out; 445 goto out;
404 } 446 }
405 447
448 qos.constraint_ns = __dev_pm_qos_read_value(dev);
449 if (qos.constraint_ns < 0) {
450 /* Negative constraint means "never suspend". */
451 retval = -EPERM;
452 goto out;
453 }
454 qos.constraint_ns *= NSEC_PER_USEC;
455 qos.time_now = ktime_get();
456
406 __update_runtime_status(dev, RPM_SUSPENDING); 457 __update_runtime_status(dev, RPM_SUSPENDING);
407 458
459 if (!dev->power.ignore_children) {
460 if (dev->power.irq_safe)
461 spin_unlock(&dev->power.lock);
462 else
463 spin_unlock_irq(&dev->power.lock);
464
465 retval = device_for_each_child(dev, &qos,
466 rpm_update_qos_constraint);
467
468 if (dev->power.irq_safe)
469 spin_lock(&dev->power.lock);
470 else
471 spin_lock_irq(&dev->power.lock);
472
473 if (retval)
474 goto fail;
475 }
476
477 dev->power.suspend_time = qos.time_now;
478 dev->power.max_time_suspended_ns = qos.constraint_ns ? : -1;
479
408 if (dev->pm_domain) 480 if (dev->pm_domain)
409 callback = dev->pm_domain->ops.runtime_suspend; 481 callback = dev->pm_domain->ops.runtime_suspend;
410 else if (dev->type && dev->type->pm) 482 else if (dev->type && dev->type->pm)
@@ -420,27 +492,9 @@ static int rpm_suspend(struct device *dev, int rpmflags)
420 callback = dev->driver->pm->runtime_suspend; 492 callback = dev->driver->pm->runtime_suspend;
421 493
422 retval = rpm_callback(callback, dev); 494 retval = rpm_callback(callback, dev);
423 if (retval) { 495 if (retval)
424 __update_runtime_status(dev, RPM_ACTIVE); 496 goto fail;
425 dev->power.deferred_resume = false;
426 if (retval == -EAGAIN || retval == -EBUSY) {
427 dev->power.runtime_error = 0;
428 497
429 /*
430 * If the callback routine failed an autosuspend, and
431 * if the last_busy time has been updated so that there
432 * is a new autosuspend expiration time, automatically
433 * reschedule another autosuspend.
434 */
435 if ((rpmflags & RPM_AUTO) &&
436 pm_runtime_autosuspend_expiration(dev) != 0)
437 goto repeat;
438 } else {
439 pm_runtime_cancel_pending(dev);
440 }
441 wake_up_all(&dev->power.wait_queue);
442 goto out;
443 }
444 no_callback: 498 no_callback:
445 __update_runtime_status(dev, RPM_SUSPENDED); 499 __update_runtime_status(dev, RPM_SUSPENDED);
446 pm_runtime_deactivate_timer(dev); 500 pm_runtime_deactivate_timer(dev);
@@ -472,6 +526,29 @@ static int rpm_suspend(struct device *dev, int rpmflags)
472 trace_rpm_return_int(dev, _THIS_IP_, retval); 526 trace_rpm_return_int(dev, _THIS_IP_, retval);
473 527
474 return retval; 528 return retval;
529
530 fail:
531 __update_runtime_status(dev, RPM_ACTIVE);
532 dev->power.suspend_time = ktime_set(0, 0);
533 dev->power.max_time_suspended_ns = -1;
534 dev->power.deferred_resume = false;
535 if (retval == -EAGAIN || retval == -EBUSY) {
536 dev->power.runtime_error = 0;
537
538 /*
539 * If the callback routine failed an autosuspend, and
540 * if the last_busy time has been updated so that there
541 * is a new autosuspend expiration time, automatically
542 * reschedule another autosuspend.
543 */
544 if ((rpmflags & RPM_AUTO) &&
545 pm_runtime_autosuspend_expiration(dev) != 0)
546 goto repeat;
547 } else {
548 pm_runtime_cancel_pending(dev);
549 }
550 wake_up_all(&dev->power.wait_queue);
551 goto out;
475} 552}
476 553
477/** 554/**
@@ -626,6 +703,9 @@ static int rpm_resume(struct device *dev, int rpmflags)
626 if (dev->power.no_callbacks) 703 if (dev->power.no_callbacks)
627 goto no_callback; /* Assume success. */ 704 goto no_callback; /* Assume success. */
628 705
706 dev->power.suspend_time = ktime_set(0, 0);
707 dev->power.max_time_suspended_ns = -1;
708
629 __update_runtime_status(dev, RPM_RESUMING); 709 __update_runtime_status(dev, RPM_RESUMING);
630 710
631 if (dev->pm_domain) 711 if (dev->pm_domain)
@@ -1288,6 +1368,9 @@ void pm_runtime_init(struct device *dev)
1288 setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn, 1368 setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
1289 (unsigned long)dev); 1369 (unsigned long)dev);
1290 1370
1371 dev->power.suspend_time = ktime_set(0, 0);
1372 dev->power.max_time_suspended_ns = -1;
1373
1291 init_waitqueue_head(&dev->power.wait_queue); 1374 init_waitqueue_head(&dev->power.wait_queue);
1292} 1375}
1293 1376
@@ -1305,3 +1388,28 @@ void pm_runtime_remove(struct device *dev)
1305 if (dev->power.irq_safe && dev->parent) 1388 if (dev->power.irq_safe && dev->parent)
1306 pm_runtime_put_sync(dev->parent); 1389 pm_runtime_put_sync(dev->parent);
1307} 1390}
1391
1392/**
1393 * pm_runtime_update_max_time_suspended - Update device's suspend time data.
1394 * @dev: Device to handle.
1395 * @delta_ns: Value to subtract from the device's max_time_suspended_ns field.
1396 *
1397 * Update the device's power.max_time_suspended_ns field by subtracting
1398 * @delta_ns from it. The resulting value of power.max_time_suspended_ns is
1399 * never negative.
1400 */
1401void pm_runtime_update_max_time_suspended(struct device *dev, s64 delta_ns)
1402{
1403 unsigned long flags;
1404
1405 spin_lock_irqsave(&dev->power.lock, flags);
1406
1407 if (delta_ns > 0 && dev->power.max_time_suspended_ns > 0) {
1408 if (dev->power.max_time_suspended_ns > delta_ns)
1409 dev->power.max_time_suspended_ns -= delta_ns;
1410 else
1411 dev->power.max_time_suspended_ns = 0;
1412 }
1413
1414 spin_unlock_irqrestore(&dev->power.lock, flags);
1415}
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 21e04dd72a84..e4982ac3fbbc 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -508,6 +508,8 @@ struct dev_pm_info {
508 unsigned long active_jiffies; 508 unsigned long active_jiffies;
509 unsigned long suspended_jiffies; 509 unsigned long suspended_jiffies;
510 unsigned long accounting_timestamp; 510 unsigned long accounting_timestamp;
511 ktime_t suspend_time;
512 s64 max_time_suspended_ns;
511#endif 513#endif
512 struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ 514 struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */
513 struct pm_qos_constraints *constraints; 515 struct pm_qos_constraints *constraints;
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 83b0ea302a80..775a3236343d 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -78,6 +78,7 @@ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
78int pm_qos_request_active(struct pm_qos_request *req); 78int pm_qos_request_active(struct pm_qos_request *req);
79s32 pm_qos_read_value(struct pm_qos_constraints *c); 79s32 pm_qos_read_value(struct pm_qos_constraints *c);
80 80
81s32 __dev_pm_qos_read_value(struct device *dev);
81s32 dev_pm_qos_read_value(struct device *dev); 82s32 dev_pm_qos_read_value(struct device *dev);
82int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, 83int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
83 s32 value); 84 s32 value);
@@ -119,6 +120,8 @@ static inline int pm_qos_request_active(struct pm_qos_request *req)
119static inline s32 pm_qos_read_value(struct pm_qos_constraints *c) 120static inline s32 pm_qos_read_value(struct pm_qos_constraints *c)
120 { return 0; } 121 { return 0; }
121 122
123static inline s32 __dev_pm_qos_read_value(struct device *dev)
124 { return 0; }
122static inline s32 dev_pm_qos_read_value(struct device *dev) 125static inline s32 dev_pm_qos_read_value(struct device *dev)
123 { return 0; } 126 { return 0; }
124static inline int dev_pm_qos_add_request(struct device *dev, 127static inline int dev_pm_qos_add_request(struct device *dev,
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index d3085e72a0ee..609daae7a014 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -45,6 +45,8 @@ extern void pm_runtime_irq_safe(struct device *dev);
45extern void __pm_runtime_use_autosuspend(struct device *dev, bool use); 45extern void __pm_runtime_use_autosuspend(struct device *dev, bool use);
46extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay); 46extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
47extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev); 47extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev);
48extern void pm_runtime_update_max_time_suspended(struct device *dev,
49 s64 delta_ns);
48 50
49static inline bool pm_children_suspended(struct device *dev) 51static inline bool pm_children_suspended(struct device *dev)
50{ 52{
@@ -148,6 +150,9 @@ static inline void pm_runtime_set_autosuspend_delay(struct device *dev,
148static inline unsigned long pm_runtime_autosuspend_expiration( 150static inline unsigned long pm_runtime_autosuspend_expiration(
149 struct device *dev) { return 0; } 151 struct device *dev) { return 0; }
150 152
153static inline void pm_runtime_update_max_time_suspended(struct device *dev,
154 s64 delta_ns) {}
155
151#endif /* !CONFIG_PM_RUNTIME */ 156#endif /* !CONFIG_PM_RUNTIME */
152 157
153static inline int pm_runtime_idle(struct device *dev) 158static inline int pm_runtime_idle(struct device *dev)