diff options
-rw-r--r-- | kernel/power/qos.c | 91 |
1 files changed, 89 insertions, 2 deletions
diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 5f4c006c4b1e..97b0df71303e 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c | |||
@@ -41,6 +41,8 @@ | |||
41 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
42 | #include <linux/init.h> | 42 | #include <linux/init.h> |
43 | #include <linux/kernel.h> | 43 | #include <linux/kernel.h> |
44 | #include <linux/debugfs.h> | ||
45 | #include <linux/seq_file.h> | ||
44 | 46 | ||
45 | #include <linux/uaccess.h> | 47 | #include <linux/uaccess.h> |
46 | #include <linux/export.h> | 48 | #include <linux/export.h> |
@@ -182,6 +184,81 @@ static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value) | |||
182 | c->target_value = value; | 184 | c->target_value = value; |
183 | } | 185 | } |
184 | 186 | ||
187 | static inline int pm_qos_get_value(struct pm_qos_constraints *c); | ||
188 | static int pm_qos_dbg_show_requests(struct seq_file *s, void *unused) | ||
189 | { | ||
190 | struct pm_qos_object *qos = (struct pm_qos_object *)s->private; | ||
191 | struct pm_qos_constraints *c; | ||
192 | struct pm_qos_request *req; | ||
193 | char *type; | ||
194 | unsigned long flags; | ||
195 | int tot_reqs = 0; | ||
196 | int active_reqs = 0; | ||
197 | |||
198 | if (IS_ERR_OR_NULL(qos)) { | ||
199 | pr_err("%s: bad qos param!\n", __func__); | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | c = qos->constraints; | ||
203 | if (IS_ERR_OR_NULL(c)) { | ||
204 | pr_err("%s: Bad constraints on qos?\n", __func__); | ||
205 | return -EINVAL; | ||
206 | } | ||
207 | |||
208 | /* Lock to ensure we have a snapshot */ | ||
209 | spin_lock_irqsave(&pm_qos_lock, flags); | ||
210 | if (plist_head_empty(&c->list)) { | ||
211 | seq_puts(s, "Empty!\n"); | ||
212 | goto out; | ||
213 | } | ||
214 | |||
215 | switch (c->type) { | ||
216 | case PM_QOS_MIN: | ||
217 | type = "Minimum"; | ||
218 | break; | ||
219 | case PM_QOS_MAX: | ||
220 | type = "Maximum"; | ||
221 | break; | ||
222 | case PM_QOS_SUM: | ||
223 | type = "Sum"; | ||
224 | break; | ||
225 | default: | ||
226 | type = "Unknown"; | ||
227 | } | ||
228 | |||
229 | plist_for_each_entry(req, &c->list, node) { | ||
230 | char *state = "Default"; | ||
231 | |||
232 | if ((req->node).prio != c->default_value) { | ||
233 | active_reqs++; | ||
234 | state = "Active"; | ||
235 | } | ||
236 | tot_reqs++; | ||
237 | seq_printf(s, "%d: %d: %s\n", tot_reqs, | ||
238 | (req->node).prio, state); | ||
239 | } | ||
240 | |||
241 | seq_printf(s, "Type=%s, Value=%d, Requests: active=%d / total=%d\n", | ||
242 | type, pm_qos_get_value(c), active_reqs, tot_reqs); | ||
243 | |||
244 | out: | ||
245 | spin_unlock_irqrestore(&pm_qos_lock, flags); | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int pm_qos_dbg_open(struct inode *inode, struct file *file) | ||
250 | { | ||
251 | return single_open(file, pm_qos_dbg_show_requests, | ||
252 | inode->i_private); | ||
253 | } | ||
254 | |||
255 | static const struct file_operations pm_qos_debug_fops = { | ||
256 | .open = pm_qos_dbg_open, | ||
257 | .read = seq_read, | ||
258 | .llseek = seq_lseek, | ||
259 | .release = single_release, | ||
260 | }; | ||
261 | |||
185 | /** | 262 | /** |
186 | * pm_qos_update_target - manages the constraints list and calls the notifiers | 263 | * pm_qos_update_target - manages the constraints list and calls the notifiers |
187 | * if needed | 264 | * if needed |
@@ -509,12 +586,17 @@ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier) | |||
509 | EXPORT_SYMBOL_GPL(pm_qos_remove_notifier); | 586 | EXPORT_SYMBOL_GPL(pm_qos_remove_notifier); |
510 | 587 | ||
511 | /* User space interface to PM QoS classes via misc devices */ | 588 | /* User space interface to PM QoS classes via misc devices */ |
512 | static int register_pm_qos_misc(struct pm_qos_object *qos) | 589 | static int register_pm_qos_misc(struct pm_qos_object *qos, struct dentry *d) |
513 | { | 590 | { |
514 | qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR; | 591 | qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR; |
515 | qos->pm_qos_power_miscdev.name = qos->name; | 592 | qos->pm_qos_power_miscdev.name = qos->name; |
516 | qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops; | 593 | qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops; |
517 | 594 | ||
595 | if (d) { | ||
596 | (void)debugfs_create_file(qos->name, S_IRUGO, d, | ||
597 | (void *)qos, &pm_qos_debug_fops); | ||
598 | } | ||
599 | |||
518 | return misc_register(&qos->pm_qos_power_miscdev); | 600 | return misc_register(&qos->pm_qos_power_miscdev); |
519 | } | 601 | } |
520 | 602 | ||
@@ -608,11 +690,16 @@ static int __init pm_qos_power_init(void) | |||
608 | { | 690 | { |
609 | int ret = 0; | 691 | int ret = 0; |
610 | int i; | 692 | int i; |
693 | struct dentry *d; | ||
611 | 694 | ||
612 | BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES); | 695 | BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES); |
613 | 696 | ||
697 | d = debugfs_create_dir("pm_qos", NULL); | ||
698 | if (IS_ERR_OR_NULL(d)) | ||
699 | d = NULL; | ||
700 | |||
614 | for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) { | 701 | for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) { |
615 | ret = register_pm_qos_misc(pm_qos_array[i]); | 702 | ret = register_pm_qos_misc(pm_qos_array[i], d); |
616 | if (ret < 0) { | 703 | if (ret < 0) { |
617 | printk(KERN_ERR "pm_qos_param: %s setup failed\n", | 704 | printk(KERN_ERR "pm_qos_param: %s setup failed\n", |
618 | pm_qos_array[i]->name); | 705 | pm_qos_array[i]->name); |