aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/dma-debug.c167
1 files changed, 166 insertions, 1 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index 1abed176d35a..f49ab22643b7 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -23,9 +23,11 @@
23#include <linux/dma-debug.h> 23#include <linux/dma-debug.h>
24#include <linux/spinlock.h> 24#include <linux/spinlock.h>
25#include <linux/debugfs.h> 25#include <linux/debugfs.h>
26#include <linux/uaccess.h>
26#include <linux/device.h> 27#include <linux/device.h>
27#include <linux/types.h> 28#include <linux/types.h>
28#include <linux/sched.h> 29#include <linux/sched.h>
30#include <linux/ctype.h>
29#include <linux/list.h> 31#include <linux/list.h>
30#include <linux/slab.h> 32#include <linux/slab.h>
31 33
@@ -98,6 +100,16 @@ static struct dentry *show_all_errors_dent __read_mostly;
98static struct dentry *show_num_errors_dent __read_mostly; 100static struct dentry *show_num_errors_dent __read_mostly;
99static struct dentry *num_free_entries_dent __read_mostly; 101static struct dentry *num_free_entries_dent __read_mostly;
100static struct dentry *min_free_entries_dent __read_mostly; 102static struct dentry *min_free_entries_dent __read_mostly;
103static struct dentry *filter_dent __read_mostly;
104
105/* per-driver filter related state */
106
107#define NAME_MAX_LEN 64
108
109static char current_driver_name[NAME_MAX_LEN] __read_mostly;
110static struct device_driver *current_driver __read_mostly;
111
112static DEFINE_RWLOCK(driver_name_lock);
101 113
102static const char *type2name[4] = { "single", "page", 114static const char *type2name[4] = { "single", "page",
103 "scather-gather", "coherent" }; 115 "scather-gather", "coherent" };
@@ -133,9 +145,48 @@ static inline void dump_entry_trace(struct dma_debug_entry *entry)
133#endif 145#endif
134} 146}
135 147
148static bool driver_filter(struct device *dev)
149{
150 /* driver filter off */
151 if (likely(!current_driver_name[0]))
152 return true;
153
154 /* driver filter on and initialized */
155 if (current_driver && dev->driver == current_driver)
156 return true;
157
158 /* driver filter on but not yet initialized */
159 if (!current_driver && current_driver_name[0]) {
160 struct device_driver *drv = get_driver(dev->driver);
161 unsigned long flags;
162 bool ret = false;
163
164 if (!drv)
165 return false;
166
167 /* lock to protect against change of current_driver_name */
168 read_lock_irqsave(&driver_name_lock, flags);
169
170 if (drv->name &&
171 strncmp(current_driver_name, drv->name,
172 NAME_MAX_LEN-1) == 0) {
173 current_driver = drv;
174 ret = true;
175 }
176
177 read_unlock_irqrestore(&driver_name_lock, flags);
178 put_driver(drv);
179
180 return ret;
181 }
182
183 return false;
184}
185
136#define err_printk(dev, entry, format, arg...) do { \ 186#define err_printk(dev, entry, format, arg...) do { \
137 error_count += 1; \ 187 error_count += 1; \
138 if (show_all_errors || show_num_errors > 0) { \ 188 if (driver_filter(dev) && \
189 (show_all_errors || show_num_errors > 0)) { \
139 WARN(1, "%s %s: " format, \ 190 WARN(1, "%s %s: " format, \
140 dev_driver_string(dev), \ 191 dev_driver_string(dev), \
141 dev_name(dev) , ## arg); \ 192 dev_name(dev) , ## arg); \
@@ -412,6 +463,97 @@ out_err:
412 return -ENOMEM; 463 return -ENOMEM;
413} 464}
414 465
466static ssize_t filter_read(struct file *file, char __user *user_buf,
467 size_t count, loff_t *ppos)
468{
469 unsigned long flags;
470 char buf[NAME_MAX_LEN + 1];
471 int len;
472
473 if (!current_driver_name[0])
474 return 0;
475
476 /*
477 * We can't copy to userspace directly because current_driver_name can
478 * only be read under the driver_name_lock with irqs disabled. So
479 * create a temporary copy first.
480 */
481 read_lock_irqsave(&driver_name_lock, flags);
482 len = scnprintf(buf, NAME_MAX_LEN + 1, "%s\n", current_driver_name);
483 read_unlock_irqrestore(&driver_name_lock, flags);
484
485 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
486}
487
488static ssize_t filter_write(struct file *file, const char __user *userbuf,
489 size_t count, loff_t *ppos)
490{
491 unsigned long flags;
492 char buf[NAME_MAX_LEN];
493 size_t len = NAME_MAX_LEN - 1;
494 int i;
495
496 /*
497 * We can't copy from userspace directly. Access to
498 * current_driver_name is protected with a write_lock with irqs
499 * disabled. Since copy_from_user can fault and may sleep we
500 * need to copy to temporary buffer first
501 */
502 len = min(count, len);
503 if (copy_from_user(buf, userbuf, len))
504 return -EFAULT;
505
506 buf[len] = 0;
507
508 write_lock_irqsave(&driver_name_lock, flags);
509
510 /* Now handle the string we got from userspace very carefully.
511 * The rules are:
512 * - only use the first token we got
513 * - token delimiter is everything looking like a space
514 * character (' ', '\n', '\t' ...)
515 *
516 */
517 if (!isalnum(buf[0])) {
518 /*
519 If the first character userspace gave us is not
520 * alphanumerical then assume the filter should be
521 * switched off.
522 */
523 if (current_driver_name[0])
524 printk(KERN_INFO "DMA-API: switching off dma-debug "
525 "driver filter\n");
526 current_driver_name[0] = 0;
527 current_driver = NULL;
528 goto out_unlock;
529 }
530
531 /*
532 * Now parse out the first token and use it as the name for the
533 * driver to filter for.
534 */
535 for (i = 0; i < NAME_MAX_LEN; ++i) {
536 current_driver_name[i] = buf[i];
537 if (isspace(buf[i]) || buf[i] == ' ' || buf[i] == 0)
538 break;
539 }
540 current_driver_name[i] = 0;
541 current_driver = NULL;
542
543 printk(KERN_INFO "DMA-API: enable driver filter for driver [%s]\n",
544 current_driver_name);
545
546out_unlock:
547 write_unlock_irqrestore(&driver_name_lock, flags);
548
549 return count;
550}
551
552const struct file_operations filter_fops = {
553 .read = filter_read,
554 .write = filter_write,
555};
556
415static int dma_debug_fs_init(void) 557static int dma_debug_fs_init(void)
416{ 558{
417 dma_debug_dent = debugfs_create_dir("dma-api", NULL); 559 dma_debug_dent = debugfs_create_dir("dma-api", NULL);
@@ -455,6 +597,11 @@ static int dma_debug_fs_init(void)
455 if (!min_free_entries_dent) 597 if (!min_free_entries_dent)
456 goto out_err; 598 goto out_err;
457 599
600 filter_dent = debugfs_create_file("driver_filter", 0644,
601 dma_debug_dent, NULL, &filter_fops);
602 if (!filter_dent)
603 goto out_err;
604
458 return 0; 605 return 0;
459 606
460out_err: 607out_err:
@@ -1044,3 +1191,21 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
1044} 1191}
1045EXPORT_SYMBOL(debug_dma_sync_sg_for_device); 1192EXPORT_SYMBOL(debug_dma_sync_sg_for_device);
1046 1193
1194static int __init dma_debug_driver_setup(char *str)
1195{
1196 int i;
1197
1198 for (i = 0; i < NAME_MAX_LEN - 1; ++i, ++str) {
1199 current_driver_name[i] = *str;
1200 if (*str == 0)
1201 break;
1202 }
1203
1204 if (current_driver_name[0])
1205 printk(KERN_INFO "DMA-API: enable driver filter for "
1206 "driver [%s]\n", current_driver_name);
1207
1208
1209 return 1;
1210}
1211__setup("dma_debug_driver=", dma_debug_driver_setup);