diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2012-03-16 16:49:24 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-03-16 16:49:24 -0400 |
commit | 59fb53ea75eef4aa029cf31c88cdacec2f7b794b (patch) | |
tree | fb2ee7f8e99a72fe858e76ba7f2dbbc0390f3128 /drivers/base | |
parent | ed819e3b964bba8bfae8e65d4d55a3f345f8da16 (diff) | |
parent | efe6a8ad7fc55b350ce968cae4c757d35e986285 (diff) |
Merge branch 'pm-qos'
* pm-qos:
sh_mmcif / PM: Use PM QoS latency constraint
tmio_mmc / PM: Use PM QoS latency constraint
PM / QoS: Make it possible to expose PM QoS latency constraints
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/power.h | 4 | ||||
-rw-r--r-- | drivers/base/power/qos.c | 61 | ||||
-rw-r--r-- | drivers/base/power/sysfs.c | 47 |
3 files changed, 112 insertions, 0 deletions
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 9bf62323aaf3..eeb4bff9505c 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h | |||
@@ -71,6 +71,8 @@ extern void dpm_sysfs_remove(struct device *dev); | |||
71 | extern void rpm_sysfs_remove(struct device *dev); | 71 | extern void rpm_sysfs_remove(struct device *dev); |
72 | extern int wakeup_sysfs_add(struct device *dev); | 72 | extern int wakeup_sysfs_add(struct device *dev); |
73 | extern void wakeup_sysfs_remove(struct device *dev); | 73 | extern void wakeup_sysfs_remove(struct device *dev); |
74 | extern int pm_qos_sysfs_add(struct device *dev); | ||
75 | extern void pm_qos_sysfs_remove(struct device *dev); | ||
74 | 76 | ||
75 | #else /* CONFIG_PM */ | 77 | #else /* CONFIG_PM */ |
76 | 78 | ||
@@ -79,5 +81,7 @@ static inline void dpm_sysfs_remove(struct device *dev) {} | |||
79 | static inline void rpm_sysfs_remove(struct device *dev) {} | 81 | static inline void rpm_sysfs_remove(struct device *dev) {} |
80 | static inline int wakeup_sysfs_add(struct device *dev) { return 0; } | 82 | static inline int wakeup_sysfs_add(struct device *dev) { return 0; } |
81 | static inline void wakeup_sysfs_remove(struct device *dev) {} | 83 | static inline void wakeup_sysfs_remove(struct device *dev) {} |
84 | static inline int pm_qos_sysfs_add(struct device *dev) { return 0; } | ||
85 | static inline void pm_qos_sysfs_remove(struct device *dev) {} | ||
82 | 86 | ||
83 | #endif | 87 | #endif |
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index c5d358837461..71855570922d 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/mutex.h> | 41 | #include <linux/mutex.h> |
42 | #include <linux/export.h> | 42 | #include <linux/export.h> |
43 | 43 | ||
44 | #include "power.h" | ||
44 | 45 | ||
45 | static DEFINE_MUTEX(dev_pm_qos_mtx); | 46 | static DEFINE_MUTEX(dev_pm_qos_mtx); |
46 | 47 | ||
@@ -166,6 +167,12 @@ void dev_pm_qos_constraints_destroy(struct device *dev) | |||
166 | struct dev_pm_qos_request *req, *tmp; | 167 | struct dev_pm_qos_request *req, *tmp; |
167 | struct pm_qos_constraints *c; | 168 | struct pm_qos_constraints *c; |
168 | 169 | ||
170 | /* | ||
171 | * If the device's PM QoS resume latency limit has been exposed to user | ||
172 | * space, it has to be hidden at this point. | ||
173 | */ | ||
174 | dev_pm_qos_hide_latency_limit(dev); | ||
175 | |||
169 | mutex_lock(&dev_pm_qos_mtx); | 176 | mutex_lock(&dev_pm_qos_mtx); |
170 | 177 | ||
171 | dev->power.power_state = PMSG_INVALID; | 178 | dev->power.power_state = PMSG_INVALID; |
@@ -445,3 +452,57 @@ int dev_pm_qos_add_ancestor_request(struct device *dev, | |||
445 | return error; | 452 | return error; |
446 | } | 453 | } |
447 | EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request); | 454 | EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request); |
455 | |||
456 | #ifdef CONFIG_PM_RUNTIME | ||
457 | static void __dev_pm_qos_drop_user_request(struct device *dev) | ||
458 | { | ||
459 | dev_pm_qos_remove_request(dev->power.pq_req); | ||
460 | dev->power.pq_req = 0; | ||
461 | } | ||
462 | |||
463 | /** | ||
464 | * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space. | ||
465 | * @dev: Device whose PM QoS latency limit is to be exposed to user space. | ||
466 | * @value: Initial value of the latency limit. | ||
467 | */ | ||
468 | int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) | ||
469 | { | ||
470 | struct dev_pm_qos_request *req; | ||
471 | int ret; | ||
472 | |||
473 | if (!device_is_registered(dev) || value < 0) | ||
474 | return -EINVAL; | ||
475 | |||
476 | if (dev->power.pq_req) | ||
477 | return -EEXIST; | ||
478 | |||
479 | req = kzalloc(sizeof(*req), GFP_KERNEL); | ||
480 | if (!req) | ||
481 | return -ENOMEM; | ||
482 | |||
483 | ret = dev_pm_qos_add_request(dev, req, value); | ||
484 | if (ret < 0) | ||
485 | return ret; | ||
486 | |||
487 | dev->power.pq_req = req; | ||
488 | ret = pm_qos_sysfs_add(dev); | ||
489 | if (ret) | ||
490 | __dev_pm_qos_drop_user_request(dev); | ||
491 | |||
492 | return ret; | ||
493 | } | ||
494 | EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit); | ||
495 | |||
496 | /** | ||
497 | * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space. | ||
498 | * @dev: Device whose PM QoS latency limit is to be hidden from user space. | ||
499 | */ | ||
500 | void dev_pm_qos_hide_latency_limit(struct device *dev) | ||
501 | { | ||
502 | if (dev->power.pq_req) { | ||
503 | pm_qos_sysfs_remove(dev); | ||
504 | __dev_pm_qos_drop_user_request(dev); | ||
505 | } | ||
506 | } | ||
507 | EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit); | ||
508 | #endif /* CONFIG_PM_RUNTIME */ | ||
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index adf41be0ea66..95c12f6cb5b9 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/device.h> | 5 | #include <linux/device.h> |
6 | #include <linux/string.h> | 6 | #include <linux/string.h> |
7 | #include <linux/export.h> | 7 | #include <linux/export.h> |
8 | #include <linux/pm_qos.h> | ||
8 | #include <linux/pm_runtime.h> | 9 | #include <linux/pm_runtime.h> |
9 | #include <linux/atomic.h> | 10 | #include <linux/atomic.h> |
10 | #include <linux/jiffies.h> | 11 | #include <linux/jiffies.h> |
@@ -217,6 +218,31 @@ static ssize_t autosuspend_delay_ms_store(struct device *dev, | |||
217 | static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show, | 218 | static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show, |
218 | autosuspend_delay_ms_store); | 219 | autosuspend_delay_ms_store); |
219 | 220 | ||
221 | static ssize_t pm_qos_latency_show(struct device *dev, | ||
222 | struct device_attribute *attr, char *buf) | ||
223 | { | ||
224 | return sprintf(buf, "%d\n", dev->power.pq_req->node.prio); | ||
225 | } | ||
226 | |||
227 | static ssize_t pm_qos_latency_store(struct device *dev, | ||
228 | struct device_attribute *attr, | ||
229 | const char *buf, size_t n) | ||
230 | { | ||
231 | s32 value; | ||
232 | int ret; | ||
233 | |||
234 | if (kstrtos32(buf, 0, &value)) | ||
235 | return -EINVAL; | ||
236 | |||
237 | if (value < 0) | ||
238 | return -EINVAL; | ||
239 | |||
240 | ret = dev_pm_qos_update_request(dev->power.pq_req, value); | ||
241 | return ret < 0 ? ret : n; | ||
242 | } | ||
243 | |||
244 | static DEVICE_ATTR(pm_qos_resume_latency_us, 0644, | ||
245 | pm_qos_latency_show, pm_qos_latency_store); | ||
220 | #endif /* CONFIG_PM_RUNTIME */ | 246 | #endif /* CONFIG_PM_RUNTIME */ |
221 | 247 | ||
222 | #ifdef CONFIG_PM_SLEEP | 248 | #ifdef CONFIG_PM_SLEEP |
@@ -490,6 +516,17 @@ static struct attribute_group pm_runtime_attr_group = { | |||
490 | .attrs = runtime_attrs, | 516 | .attrs = runtime_attrs, |
491 | }; | 517 | }; |
492 | 518 | ||
519 | static struct attribute *pm_qos_attrs[] = { | ||
520 | #ifdef CONFIG_PM_RUNTIME | ||
521 | &dev_attr_pm_qos_resume_latency_us.attr, | ||
522 | #endif /* CONFIG_PM_RUNTIME */ | ||
523 | NULL, | ||
524 | }; | ||
525 | static struct attribute_group pm_qos_attr_group = { | ||
526 | .name = power_group_name, | ||
527 | .attrs = pm_qos_attrs, | ||
528 | }; | ||
529 | |||
493 | int dpm_sysfs_add(struct device *dev) | 530 | int dpm_sysfs_add(struct device *dev) |
494 | { | 531 | { |
495 | int rc; | 532 | int rc; |
@@ -530,6 +567,16 @@ void wakeup_sysfs_remove(struct device *dev) | |||
530 | sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group); | 567 | sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group); |
531 | } | 568 | } |
532 | 569 | ||
570 | int pm_qos_sysfs_add(struct device *dev) | ||
571 | { | ||
572 | return sysfs_merge_group(&dev->kobj, &pm_qos_attr_group); | ||
573 | } | ||
574 | |||
575 | void pm_qos_sysfs_remove(struct device *dev) | ||
576 | { | ||
577 | sysfs_unmerge_group(&dev->kobj, &pm_qos_attr_group); | ||
578 | } | ||
579 | |||
533 | void rpm_sysfs_remove(struct device *dev) | 580 | void rpm_sysfs_remove(struct device *dev) |
534 | { | 581 | { |
535 | sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group); | 582 | sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group); |