aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dma-debug.c
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2009-06-09 04:50:57 -0400
committerJoerg Roedel <joerg.roedel@amd.com>2009-06-09 04:50:57 -0400
commitd2dd01de9924ae24afeba5aa5bc2e08287701df6 (patch)
tree3021bf496579a48984666355b59df5e44b42dd32 /lib/dma-debug.c
parent367d04c4ec02dad34d80452e32e3370db7fb6fee (diff)
parent62a6f465f6572e1f28765c583c12753bb3e23715 (diff)
Merge commit 'tip/core/iommu' into amd-iommu/fixes
Diffstat (limited to 'lib/dma-debug.c')
-rw-r--r--lib/dma-debug.c334
1 files changed, 308 insertions, 26 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index cdd205d6bf7c..77053d9ef513 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" };
@@ -105,6 +117,11 @@ static const char *type2name[4] = { "single", "page",
105static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE", 117static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE",
106 "DMA_FROM_DEVICE", "DMA_NONE" }; 118 "DMA_FROM_DEVICE", "DMA_NONE" };
107 119
120/* little merge helper - remove it after the merge window */
121#ifndef BUS_NOTIFY_UNBOUND_DRIVER
122#define BUS_NOTIFY_UNBOUND_DRIVER 0x0005
123#endif
124
108/* 125/*
109 * The access to some variables in this macro is racy. We can't use atomic_t 126 * The access to some variables in this macro is racy. We can't use atomic_t
110 * here because all these variables are exported to debugfs. Some of them even 127 * here because all these variables are exported to debugfs. Some of them even
@@ -128,9 +145,48 @@ static inline void dump_entry_trace(struct dma_debug_entry *entry)
128#endif 145#endif
129} 146}
130 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
131#define err_printk(dev, entry, format, arg...) do { \ 186#define err_printk(dev, entry, format, arg...) do { \
132 error_count += 1; \ 187 error_count += 1; \
133 if (show_all_errors || show_num_errors > 0) { \ 188 if (driver_filter(dev) && \
189 (show_all_errors || show_num_errors > 0)) { \
134 WARN(1, "%s %s: " format, \ 190 WARN(1, "%s %s: " format, \
135 dev_driver_string(dev), \ 191 dev_driver_string(dev), \
136 dev_name(dev) , ## arg); \ 192 dev_name(dev) , ## arg); \
@@ -186,15 +242,50 @@ static void put_hash_bucket(struct hash_bucket *bucket,
186static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket, 242static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket,
187 struct dma_debug_entry *ref) 243 struct dma_debug_entry *ref)
188{ 244{
189 struct dma_debug_entry *entry; 245 struct dma_debug_entry *entry, *ret = NULL;
246 int matches = 0, match_lvl, last_lvl = 0;
190 247
191 list_for_each_entry(entry, &bucket->list, list) { 248 list_for_each_entry(entry, &bucket->list, list) {
192 if ((entry->dev_addr == ref->dev_addr) && 249 if ((entry->dev_addr != ref->dev_addr) ||
193 (entry->dev == ref->dev)) 250 (entry->dev != ref->dev))
251 continue;
252
253 /*
254 * Some drivers map the same physical address multiple
255 * times. Without a hardware IOMMU this results in the
256 * same device addresses being put into the dma-debug
257 * hash multiple times too. This can result in false
258 * positives being reported. Therfore we implement a
259 * best-fit algorithm here which returns the entry from
260 * the hash which fits best to the reference value
261 * instead of the first-fit.
262 */
263 matches += 1;
264 match_lvl = 0;
265 entry->size == ref->size ? ++match_lvl : match_lvl;
266 entry->type == ref->type ? ++match_lvl : match_lvl;
267 entry->direction == ref->direction ? ++match_lvl : match_lvl;
268
269 if (match_lvl == 3) {
270 /* perfect-fit - return the result */
194 return entry; 271 return entry;
272 } else if (match_lvl > last_lvl) {
273 /*
274 * We found an entry that fits better then the
275 * previous one
276 */
277 last_lvl = match_lvl;
278 ret = entry;
279 }
195 } 280 }
196 281
197 return NULL; 282 /*
283 * If we have multiple matches but no perfect-fit, just return
284 * NULL.
285 */
286 ret = (matches == 1) ? ret : NULL;
287
288 return ret;
198} 289}
199 290
200/* 291/*
@@ -407,6 +498,97 @@ out_err:
407 return -ENOMEM; 498 return -ENOMEM;
408} 499}
409 500
501static ssize_t filter_read(struct file *file, char __user *user_buf,
502 size_t count, loff_t *ppos)
503{
504 unsigned long flags;
505 char buf[NAME_MAX_LEN + 1];
506 int len;
507
508 if (!current_driver_name[0])
509 return 0;
510
511 /*
512 * We can't copy to userspace directly because current_driver_name can
513 * only be read under the driver_name_lock with irqs disabled. So
514 * create a temporary copy first.
515 */
516 read_lock_irqsave(&driver_name_lock, flags);
517 len = scnprintf(buf, NAME_MAX_LEN + 1, "%s\n", current_driver_name);
518 read_unlock_irqrestore(&driver_name_lock, flags);
519
520 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
521}
522
523static ssize_t filter_write(struct file *file, const char __user *userbuf,
524 size_t count, loff_t *ppos)
525{
526 unsigned long flags;
527 char buf[NAME_MAX_LEN];
528 size_t len = NAME_MAX_LEN - 1;
529 int i;
530
531 /*
532 * We can't copy from userspace directly. Access to
533 * current_driver_name is protected with a write_lock with irqs
534 * disabled. Since copy_from_user can fault and may sleep we
535 * need to copy to temporary buffer first
536 */
537 len = min(count, len);
538 if (copy_from_user(buf, userbuf, len))
539 return -EFAULT;
540
541 buf[len] = 0;
542
543 write_lock_irqsave(&driver_name_lock, flags);
544
545 /* Now handle the string we got from userspace very carefully.
546 * The rules are:
547 * - only use the first token we got
548 * - token delimiter is everything looking like a space
549 * character (' ', '\n', '\t' ...)
550 *
551 */
552 if (!isalnum(buf[0])) {
553 /*
554 If the first character userspace gave us is not
555 * alphanumerical then assume the filter should be
556 * switched off.
557 */
558 if (current_driver_name[0])
559 printk(KERN_INFO "DMA-API: switching off dma-debug "
560 "driver filter\n");
561 current_driver_name[0] = 0;
562 current_driver = NULL;
563 goto out_unlock;
564 }
565
566 /*
567 * Now parse out the first token and use it as the name for the
568 * driver to filter for.
569 */
570 for (i = 0; i < NAME_MAX_LEN; ++i) {
571 current_driver_name[i] = buf[i];
572 if (isspace(buf[i]) || buf[i] == ' ' || buf[i] == 0)
573 break;
574 }
575 current_driver_name[i] = 0;
576 current_driver = NULL;
577
578 printk(KERN_INFO "DMA-API: enable driver filter for driver [%s]\n",
579 current_driver_name);
580
581out_unlock:
582 write_unlock_irqrestore(&driver_name_lock, flags);
583
584 return count;
585}
586
587const struct file_operations filter_fops = {
588 .read = filter_read,
589 .write = filter_write,
590};
591
410static int dma_debug_fs_init(void) 592static int dma_debug_fs_init(void)
411{ 593{
412 dma_debug_dent = debugfs_create_dir("dma-api", NULL); 594 dma_debug_dent = debugfs_create_dir("dma-api", NULL);
@@ -450,6 +632,11 @@ static int dma_debug_fs_init(void)
450 if (!min_free_entries_dent) 632 if (!min_free_entries_dent)
451 goto out_err; 633 goto out_err;
452 634
635 filter_dent = debugfs_create_file("driver_filter", 0644,
636 dma_debug_dent, NULL, &filter_fops);
637 if (!filter_dent)
638 goto out_err;
639
453 return 0; 640 return 0;
454 641
455out_err: 642out_err:
@@ -458,9 +645,60 @@ out_err:
458 return -ENOMEM; 645 return -ENOMEM;
459} 646}
460 647
648static int device_dma_allocations(struct device *dev)
649{
650 struct dma_debug_entry *entry;
651 unsigned long flags;
652 int count = 0, i;
653
654 for (i = 0; i < HASH_SIZE; ++i) {
655 spin_lock_irqsave(&dma_entry_hash[i].lock, flags);
656 list_for_each_entry(entry, &dma_entry_hash[i].list, list) {
657 if (entry->dev == dev)
658 count += 1;
659 }
660 spin_unlock_irqrestore(&dma_entry_hash[i].lock, flags);
661 }
662
663 return count;
664}
665
666static int dma_debug_device_change(struct notifier_block *nb,
667 unsigned long action, void *data)
668{
669 struct device *dev = data;
670 int count;
671
672
673 switch (action) {
674 case BUS_NOTIFY_UNBOUND_DRIVER:
675 count = device_dma_allocations(dev);
676 if (count == 0)
677 break;
678 err_printk(dev, NULL, "DMA-API: device driver has pending "
679 "DMA allocations while released from device "
680 "[count=%d]\n", count);
681 break;
682 default:
683 break;
684 }
685
686 return 0;
687}
688
461void dma_debug_add_bus(struct bus_type *bus) 689void dma_debug_add_bus(struct bus_type *bus)
462{ 690{
463 /* FIXME: register notifier */ 691 struct notifier_block *nb;
692
693 nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL);
694 if (nb == NULL) {
695 printk(KERN_ERR "dma_debug_add_bus: out of memory\n");
696 return;
697 }
698
699 nb->notifier_call = dma_debug_device_change;
700
701 bus_register_notifier(bus, nb);
464} 702}
465 703
466/* 704/*
@@ -783,15 +1021,15 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
783 entry->type = dma_debug_sg; 1021 entry->type = dma_debug_sg;
784 entry->dev = dev; 1022 entry->dev = dev;
785 entry->paddr = sg_phys(s); 1023 entry->paddr = sg_phys(s);
786 entry->size = s->length; 1024 entry->size = sg_dma_len(s);
787 entry->dev_addr = s->dma_address; 1025 entry->dev_addr = sg_dma_address(s);
788 entry->direction = direction; 1026 entry->direction = direction;
789 entry->sg_call_ents = nents; 1027 entry->sg_call_ents = nents;
790 entry->sg_mapped_ents = mapped_ents; 1028 entry->sg_mapped_ents = mapped_ents;
791 1029
792 if (!PageHighMem(sg_page(s))) { 1030 if (!PageHighMem(sg_page(s))) {
793 check_for_stack(dev, sg_virt(s)); 1031 check_for_stack(dev, sg_virt(s));
794 check_for_illegal_area(dev, sg_virt(s), s->length); 1032 check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s));
795 } 1033 }
796 1034
797 add_dma_entry(entry); 1035 add_dma_entry(entry);
@@ -799,13 +1037,32 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
799} 1037}
800EXPORT_SYMBOL(debug_dma_map_sg); 1038EXPORT_SYMBOL(debug_dma_map_sg);
801 1039
1040static int get_nr_mapped_entries(struct device *dev, struct scatterlist *s)
1041{
1042 struct dma_debug_entry *entry;
1043 struct hash_bucket *bucket;
1044 unsigned long flags;
1045 int mapped_ents = 0;
1046 struct dma_debug_entry ref;
1047
1048 ref.dev = dev;
1049 ref.dev_addr = sg_dma_address(s);
1050 ref.size = sg_dma_len(s),
1051
1052 bucket = get_hash_bucket(&ref, &flags);
1053 entry = hash_bucket_find(bucket, &ref);
1054 if (entry)
1055 mapped_ents = entry->sg_mapped_ents;
1056 put_hash_bucket(bucket, &flags);
1057
1058 return mapped_ents;
1059}
1060
802void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, 1061void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
803 int nelems, int dir) 1062 int nelems, int dir)
804{ 1063{
805 struct dma_debug_entry *entry;
806 struct scatterlist *s; 1064 struct scatterlist *s;
807 int mapped_ents = 0, i; 1065 int mapped_ents = 0, i;
808 unsigned long flags;
809 1066
810 if (unlikely(global_disable)) 1067 if (unlikely(global_disable))
811 return; 1068 return;
@@ -816,8 +1073,8 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
816 .type = dma_debug_sg, 1073 .type = dma_debug_sg,
817 .dev = dev, 1074 .dev = dev,
818 .paddr = sg_phys(s), 1075 .paddr = sg_phys(s),
819 .dev_addr = s->dma_address, 1076 .dev_addr = sg_dma_address(s),
820 .size = s->length, 1077 .size = sg_dma_len(s),
821 .direction = dir, 1078 .direction = dir,
822 .sg_call_ents = 0, 1079 .sg_call_ents = 0,
823 }; 1080 };
@@ -825,14 +1082,9 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
825 if (mapped_ents && i >= mapped_ents) 1082 if (mapped_ents && i >= mapped_ents)
826 break; 1083 break;
827 1084
828 if (mapped_ents == 0) { 1085 if (!i) {
829 struct hash_bucket *bucket;
830 ref.sg_call_ents = nelems; 1086 ref.sg_call_ents = nelems;
831 bucket = get_hash_bucket(&ref, &flags); 1087 mapped_ents = get_nr_mapped_entries(dev, s);
832 entry = hash_bucket_find(bucket, &ref);
833 if (entry)
834 mapped_ents = entry->sg_mapped_ents;
835 put_hash_bucket(bucket, &flags);
836 } 1088 }
837 1089
838 check_unmap(&ref); 1090 check_unmap(&ref);
@@ -934,14 +1186,20 @@ void debug_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
934 int nelems, int direction) 1186 int nelems, int direction)
935{ 1187{
936 struct scatterlist *s; 1188 struct scatterlist *s;
937 int i; 1189 int mapped_ents = 0, i;
938 1190
939 if (unlikely(global_disable)) 1191 if (unlikely(global_disable))
940 return; 1192 return;
941 1193
942 for_each_sg(sg, s, nelems, i) { 1194 for_each_sg(sg, s, nelems, i) {
943 check_sync(dev, s->dma_address, s->dma_length, 0, 1195 if (!i)
944 direction, true); 1196 mapped_ents = get_nr_mapped_entries(dev, s);
1197
1198 if (i >= mapped_ents)
1199 break;
1200
1201 check_sync(dev, sg_dma_address(s), sg_dma_len(s), 0,
1202 direction, true);
945 } 1203 }
946} 1204}
947EXPORT_SYMBOL(debug_dma_sync_sg_for_cpu); 1205EXPORT_SYMBOL(debug_dma_sync_sg_for_cpu);
@@ -950,15 +1208,39 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
950 int nelems, int direction) 1208 int nelems, int direction)
951{ 1209{
952 struct scatterlist *s; 1210 struct scatterlist *s;
953 int i; 1211 int mapped_ents = 0, i;
954 1212
955 if (unlikely(global_disable)) 1213 if (unlikely(global_disable))
956 return; 1214 return;
957 1215
958 for_each_sg(sg, s, nelems, i) { 1216 for_each_sg(sg, s, nelems, i) {
959 check_sync(dev, s->dma_address, s->dma_length, 0, 1217 if (!i)
960 direction, false); 1218 mapped_ents = get_nr_mapped_entries(dev, s);
1219
1220 if (i >= mapped_ents)
1221 break;
1222
1223 check_sync(dev, sg_dma_address(s), sg_dma_len(s), 0,
1224 direction, false);
961 } 1225 }
962} 1226}
963EXPORT_SYMBOL(debug_dma_sync_sg_for_device); 1227EXPORT_SYMBOL(debug_dma_sync_sg_for_device);
964 1228
1229static int __init dma_debug_driver_setup(char *str)
1230{
1231 int i;
1232
1233 for (i = 0; i < NAME_MAX_LEN - 1; ++i, ++str) {
1234 current_driver_name[i] = *str;
1235 if (*str == 0)
1236 break;
1237 }
1238
1239 if (current_driver_name[0])
1240 printk(KERN_INFO "DMA-API: enable driver filter for "
1241 "driver [%s]\n", current_driver_name);
1242
1243
1244 return 1;
1245}
1246__setup("dma_debug_driver=", dma_debug_driver_setup);