aboutsummaryrefslogtreecommitdiffstats
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
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>
-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 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}
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 3f3ed83a9aa5..a7676efa6831 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -521,6 +521,8 @@ struct dev_pm_info {
521 unsigned long active_jiffies; 521 unsigned long active_jiffies;
522 unsigned long suspended_jiffies; 522 unsigned long suspended_jiffies;
523 unsigned long accounting_timestamp; 523 unsigned long accounting_timestamp;
524 ktime_t suspend_time;
525 s64 max_time_suspended_ns;
524#endif 526#endif
525 struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ 527 struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */
526 struct pm_qos_constraints *constraints; 528 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)