diff options
Diffstat (limited to 'kernel/power/qos.c')
| -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); |
