aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/DMA-API.txt12
-rw-r--r--Documentation/kernel-parameters.txt7
-rw-r--r--lib/dma-debug.c167
3 files changed, 185 insertions, 1 deletions
diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
index d9aa43d78bcc..25fb8bcf32a2 100644
--- a/Documentation/DMA-API.txt
+++ b/Documentation/DMA-API.txt
@@ -704,12 +704,24 @@ this directory the following files can currently be found:
704 The current number of free dma_debug_entries 704 The current number of free dma_debug_entries
705 in the allocator. 705 in the allocator.
706 706
707 dma-api/driver-filter
708 You can write a name of a driver into this file
709 to limit the debug output to requests from that
710 particular driver. Write an empty string to
711 that file to disable the filter and see
712 all errors again.
713
707If you have this code compiled into your kernel it will be enabled by default. 714If you have this code compiled into your kernel it will be enabled by default.
708If you want to boot without the bookkeeping anyway you can provide 715If you want to boot without the bookkeeping anyway you can provide
709'dma_debug=off' as a boot parameter. This will disable DMA-API debugging. 716'dma_debug=off' as a boot parameter. This will disable DMA-API debugging.
710Notice that you can not enable it again at runtime. You have to reboot to do 717Notice that you can not enable it again at runtime. You have to reboot to do
711so. 718so.
712 719
720If you want to see debug messages only for a special device driver you can
721specify the dma_debug_driver=<drivername> parameter. This will enable the
722driver filter at boot time. The debug code will only print errors for that
723driver afterwards. This filter can be disabled or changed later using debugfs.
724
713When the code disables itself at runtime this is most likely because it ran 725When the code disables itself at runtime this is most likely because it ran
714out of dma_debug_entries. These entries are preallocated at boot. The number 726out of dma_debug_entries. These entries are preallocated at boot. The number
715of preallocated entries is defined per architecture. If it is too low for you 727of preallocated entries is defined per architecture. If it is too low for you
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index e87bdbfbcc75..b3f1314588c9 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -646,6 +646,13 @@ and is between 256 and 4096 characters. It is defined in the file
646 DMA-API debugging code disables itself because the 646 DMA-API debugging code disables itself because the
647 architectural default is too low. 647 architectural default is too low.
648 648
649 dma_debug_driver=<driver_name>
650 With this option the DMA-API debugging driver
651 filter feature can be enabled at boot time. Just
652 pass the driver to filter for as the parameter.
653 The filter can be disabled or changed to another
654 driver later using sysfs.
655
649 dscc4.setup= [NET] 656 dscc4.setup= [NET]
650 657
651 dtc3181e= [HW,SCSI] 658 dtc3181e= [HW,SCSI]
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);