aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
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 /drivers/base/power
parentb7ba68c4a072c9aa8f04b8cf7838b6cd2f48d918 (diff)
parent00dc9ad18d707f36b2fb4af98fd2cf0548d2b258 (diff)
Merge branch 'pm-runtime' into pm-for-linus
* pm-runtime: PM / Runtime: Use device PM QoS constraints (v2)
Diffstat (limited to 'drivers/base/power')
-rw-r--r--drivers/base/power/qos.c24
-rw-r--r--drivers/base/power/runtime.c148
2 files changed, 144 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}