aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-11-30 18:01:31 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2011-12-01 15:46:42 -0500
commit00dc9ad18d707f36b2fb4af98fd2cf0548d2b258 (patch)
treef41672d9dae9bf15f2ee17abf3b5b6c31c966088 /drivers/base/power
parentb930c26416c4ea6855726fd977145ccea9afbdda (diff)
PM / Runtime: Use device PM QoS constraints (v2)
Make the runtime PM core use device PM QoS constraints to check if it is allowed to suspend a given device, so that an error code is returned if the device's own PM QoS constraint is negative or one of its children has already been suspended for too long. If this is not the case, the maximum estimated time the device is allowed to be suspended, computed as the minimum of the device's PM QoS constraint and the PM QoS constraints of its children (reduced by the difference between the current time and their suspend times) is stored in a new device's PM field power.max_time_suspended_ns that can be used by the device's subsystem or PM domain to decide whether or not to put the device into lower-power (and presumably higher-latency) states later (if the constraint is 0, which means "no constraint", the power.max_time_suspended_ns is set to -1). Additionally, the time of execution of the subsystem-level .runtime_suspend() callback for the device is recorded in the new power.suspend_time field for later use by the device's subsystem or PM domain along with power.max_time_suspended_ns (it also is used by the core code when the device's parent is suspended). Introduce a new helper function, pm_runtime_update_max_time_suspended(), allowing subsystems and PM domains (or device drivers) to update the power.max_time_suspended_ns field, for example after changing the power state of a suspended device. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
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 8c78443bca8f..068f7ed1f009 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -279,6 +279,47 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
279 return retval != -EACCES ? retval : -EIO; 279 return retval != -EACCES ? retval : -EIO;
280} 280}
281 281
282struct rpm_qos_data {
283 ktime_t time_now;
284 s64 constraint_ns;
285};
286
287/**
288 * rpm_update_qos_constraint - Update a given PM QoS constraint data.
289 * @dev: Device whose timing data to use.
290 * @data: PM QoS constraint data to update.
291 *
292 * Use the suspend timing data of @dev to update PM QoS constraint data pointed
293 * to by @data.
294 */
295static int rpm_update_qos_constraint(struct device *dev, void *data)
296{
297 struct rpm_qos_data *qos = data;
298 unsigned long flags;
299 s64 delta_ns;
300 int ret = 0;
301
302 spin_lock_irqsave(&dev->power.lock, flags);
303
304 if (dev->power.max_time_suspended_ns < 0)
305 goto out;
306
307 delta_ns = dev->power.max_time_suspended_ns -
308 ktime_to_ns(ktime_sub(qos->time_now, dev->power.suspend_time));
309 if (delta_ns <= 0) {
310 ret = -EBUSY;
311 goto out;
312 }
313
314 if (qos->constraint_ns > delta_ns || qos->constraint_ns == 0)
315 qos->constraint_ns = delta_ns;
316
317 out:
318 spin_unlock_irqrestore(&dev->power.lock, flags);
319
320 return ret;
321}
322
282/** 323/**
283 * rpm_suspend - Carry out runtime suspend of given device. 324 * rpm_suspend - Carry out runtime suspend of given device.
284 * @dev: Device to suspend. 325 * @dev: Device to suspend.
@@ -305,6 +346,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
305{ 346{
306 int (*callback)(struct device *); 347 int (*callback)(struct device *);
307 struct device *parent = NULL; 348 struct device *parent = NULL;
349 struct rpm_qos_data qos;
308 int retval; 350 int retval;
309 351
310 trace_rpm_suspend(dev, rpmflags); 352 trace_rpm_suspend(dev, rpmflags);
@@ -400,8 +442,38 @@ static int rpm_suspend(struct device *dev, int rpmflags)
400 goto out; 442 goto out;
401 } 443 }
402 444
445 qos.constraint_ns = __dev_pm_qos_read_value(dev);
446 if (qos.constraint_ns < 0) {
447 /* Negative constraint means "never suspend". */
448 retval = -EPERM;
449 goto out;
450 }
451 qos.constraint_ns *= NSEC_PER_USEC;
452 qos.time_now = ktime_get();
453
403 __update_runtime_status(dev, RPM_SUSPENDING); 454 __update_runtime_status(dev, RPM_SUSPENDING);
404 455
456 if (!dev->power.ignore_children) {
457 if (dev->power.irq_safe)
458 spin_unlock(&dev->power.lock);
459 else
460 spin_unlock_irq(&dev->power.lock);
461
462 retval = device_for_each_child(dev, &qos,
463 rpm_update_qos_constraint);
464
465 if (dev->power.irq_safe)
466 spin_lock(&dev->power.lock);
467 else
468 spin_lock_irq(&dev->power.lock);
469
470 if (retval)
471 goto fail;
472 }
473
474 dev->power.suspend_time = qos.time_now;
475 dev->power.max_time_suspended_ns = qos.constraint_ns ? : -1;
476
405 if (dev->pm_domain) 477 if (dev->pm_domain)
406 callback = dev->pm_domain->ops.runtime_suspend; 478 callback = dev->pm_domain->ops.runtime_suspend;
407 else if (dev->type && dev->type->pm) 479 else if (dev->type && dev->type->pm)
@@ -414,27 +486,9 @@ static int rpm_suspend(struct device *dev, int rpmflags)
414 callback = NULL; 486 callback = NULL;
415 487
416 retval = rpm_callback(callback, dev); 488 retval = rpm_callback(callback, dev);
417 if (retval) { 489 if (retval)
418 __update_runtime_status(dev, RPM_ACTIVE); 490 goto fail;
419 dev->power.deferred_resume = false;
420 if (retval == -EAGAIN || retval == -EBUSY) {
421 dev->power.runtime_error = 0;
422 491
423 /*
424 * If the callback routine failed an autosuspend, and
425 * if the last_busy time has been updated so that there
426 * is a new autosuspend expiration time, automatically
427 * reschedule another autosuspend.
428 */
429 if ((rpmflags & RPM_AUTO) &&
430 pm_runtime_autosuspend_expiration(dev) != 0)
431 goto repeat;
432 } else {
433 pm_runtime_cancel_pending(dev);
434 }
435 wake_up_all(&dev->power.wait_queue);
436 goto out;
437 }
438 no_callback: 492 no_callback:
439 __update_runtime_status(dev, RPM_SUSPENDED); 493 __update_runtime_status(dev, RPM_SUSPENDED);
440 pm_runtime_deactivate_timer(dev); 494 pm_runtime_deactivate_timer(dev);
@@ -466,6 +520,29 @@ static int rpm_suspend(struct device *dev, int rpmflags)
466 trace_rpm_return_int(dev, _THIS_IP_, retval); 520 trace_rpm_return_int(dev, _THIS_IP_, retval);
467 521
468 return retval; 522 return retval;
523
524 fail:
525 __update_runtime_status(dev, RPM_ACTIVE);
526 dev->power.suspend_time = ktime_set(0, 0);
527 dev->power.max_time_suspended_ns = -1;
528 dev->power.deferred_resume = false;
529 if (retval == -EAGAIN || retval == -EBUSY) {
530 dev->power.runtime_error = 0;
531
532 /*
533 * If the callback routine failed an autosuspend, and
534 * if the last_busy time has been updated so that there
535 * is a new autosuspend expiration time, automatically
536 * reschedule another autosuspend.
537 */
538 if ((rpmflags & RPM_AUTO) &&
539 pm_runtime_autosuspend_expiration(dev) != 0)
540 goto repeat;
541 } else {
542 pm_runtime_cancel_pending(dev);
543 }
544 wake_up_all(&dev->power.wait_queue);
545 goto out;
469} 546}
470 547
471/** 548/**
@@ -620,6 +697,9 @@ static int rpm_resume(struct device *dev, int rpmflags)
620 if (dev->power.no_callbacks) 697 if (dev->power.no_callbacks)
621 goto no_callback; /* Assume success. */ 698 goto no_callback; /* Assume success. */
622 699
700 dev->power.suspend_time = ktime_set(0, 0);
701 dev->power.max_time_suspended_ns = -1;
702
623 __update_runtime_status(dev, RPM_RESUMING); 703 __update_runtime_status(dev, RPM_RESUMING);
624 704
625 if (dev->pm_domain) 705 if (dev->pm_domain)
@@ -1279,6 +1359,9 @@ void pm_runtime_init(struct device *dev)
1279 setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn, 1359 setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
1280 (unsigned long)dev); 1360 (unsigned long)dev);
1281 1361
1362 dev->power.suspend_time = ktime_set(0, 0);
1363 dev->power.max_time_suspended_ns = -1;
1364
1282 init_waitqueue_head(&dev->power.wait_queue); 1365 init_waitqueue_head(&dev->power.wait_queue);
1283} 1366}
1284 1367
@@ -1296,3 +1379,28 @@ void pm_runtime_remove(struct device *dev)
1296 if (dev->power.irq_safe && dev->parent) 1379 if (dev->power.irq_safe && dev->parent)
1297 pm_runtime_put_sync(dev->parent); 1380 pm_runtime_put_sync(dev->parent);
1298} 1381}
1382
1383/**
1384 * pm_runtime_update_max_time_suspended - Update device's suspend time data.
1385 * @dev: Device to handle.
1386 * @delta_ns: Value to subtract from the device's max_time_suspended_ns field.
1387 *
1388 * Update the device's power.max_time_suspended_ns field by subtracting
1389 * @delta_ns from it. The resulting value of power.max_time_suspended_ns is
1390 * never negative.
1391 */
1392void pm_runtime_update_max_time_suspended(struct device *dev, s64 delta_ns)
1393{
1394 unsigned long flags;
1395
1396 spin_lock_irqsave(&dev->power.lock, flags);
1397
1398 if (delta_ns > 0 && dev->power.max_time_suspended_ns > 0) {
1399 if (dev->power.max_time_suspended_ns > delta_ns)
1400 dev->power.max_time_suspended_ns -= delta_ns;
1401 else
1402 dev->power.max_time_suspended_ns = 0;
1403 }
1404
1405 spin_unlock_irqrestore(&dev->power.lock, flags);
1406}