aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-06-07 05:36:02 -0400
committerIngo Molnar <mingo@elte.hu>2009-06-07 05:36:02 -0400
commit62a6f465f6572e1f28765c583c12753bb3e23715 (patch)
tree35ccf596b4abbeec9e1244f31e5b4e5d079899f5 /lib
parent56fdd18c7b89a2fac1dfe5d54750c9143867fdc4 (diff)
parentbdc2911cde7d18580a545483844d75fdb3551729 (diff)
Merge branch 'dma-debug/2.6.31' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/linux-2.6-iommu into core/iommu
Diffstat (limited to 'lib')
-rw-r--r--lib/dma-debug.c291
1 files changed, 269 insertions, 22 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index 8fcc09c91e1b..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); \
@@ -442,6 +498,97 @@ out_err:
442 return -ENOMEM; 498 return -ENOMEM;
443} 499}
444 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
445static int dma_debug_fs_init(void) 592static int dma_debug_fs_init(void)
446{ 593{
447 dma_debug_dent = debugfs_create_dir("dma-api", NULL); 594 dma_debug_dent = debugfs_create_dir("dma-api", NULL);
@@ -485,6 +632,11 @@ static int dma_debug_fs_init(void)
485 if (!min_free_entries_dent) 632 if (!min_free_entries_dent)
486 goto out_err; 633 goto out_err;
487 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
488 return 0; 640 return 0;
489 641
490out_err: 642out_err:
@@ -493,9 +645,60 @@ out_err:
493 return -ENOMEM; 645 return -ENOMEM;
494} 646}
495 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
496void dma_debug_add_bus(struct bus_type *bus) 689void dma_debug_add_bus(struct bus_type *bus)
497{ 690{
498 /* 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);
499} 702}
500 703
501/* 704/*
@@ -818,15 +1021,15 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
818 entry->type = dma_debug_sg; 1021 entry->type = dma_debug_sg;
819 entry->dev = dev; 1022 entry->dev = dev;
820 entry->paddr = sg_phys(s); 1023 entry->paddr = sg_phys(s);
821 entry->size = s->length; 1024 entry->size = sg_dma_len(s);
822 entry->dev_addr = s->dma_address; 1025 entry->dev_addr = sg_dma_address(s);
823 entry->direction = direction; 1026 entry->direction = direction;
824 entry->sg_call_ents = nents; 1027 entry->sg_call_ents = nents;
825 entry->sg_mapped_ents = mapped_ents; 1028 entry->sg_mapped_ents = mapped_ents;
826 1029
827 if (!PageHighMem(sg_page(s))) { 1030 if (!PageHighMem(sg_page(s))) {
828 check_for_stack(dev, sg_virt(s)); 1031 check_for_stack(dev, sg_virt(s));
829 check_for_illegal_area(dev, sg_virt(s), s->length); 1032 check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s));
830 } 1033 }
831 1034
832 add_dma_entry(entry); 1035 add_dma_entry(entry);
@@ -834,13 +1037,32 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
834} 1037}
835EXPORT_SYMBOL(debug_dma_map_sg); 1038EXPORT_SYMBOL(debug_dma_map_sg);
836 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
837void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, 1061void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
838 int nelems, int dir) 1062 int nelems, int dir)
839{ 1063{
840 struct dma_debug_entry *entry;
841 struct scatterlist *s; 1064 struct scatterlist *s;
842 int mapped_ents = 0, i; 1065 int mapped_ents = 0, i;
843 unsigned long flags;
844 1066
845 if (unlikely(global_disable)) 1067 if (unlikely(global_disable))
846 return; 1068 return;
@@ -851,8 +1073,8 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
851 .type = dma_debug_sg, 1073 .type = dma_debug_sg,
852 .dev = dev, 1074 .dev = dev,
853 .paddr = sg_phys(s), 1075 .paddr = sg_phys(s),
854 .dev_addr = s->dma_address, 1076 .dev_addr = sg_dma_address(s),
855 .size = s->length, 1077 .size = sg_dma_len(s),
856 .direction = dir, 1078 .direction = dir,
857 .sg_call_ents = 0, 1079 .sg_call_ents = 0,
858 }; 1080 };
@@ -860,14 +1082,9 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
860 if (mapped_ents && i >= mapped_ents) 1082 if (mapped_ents && i >= mapped_ents)
861 break; 1083 break;
862 1084
863 if (mapped_ents == 0) { 1085 if (!i) {
864 struct hash_bucket *bucket;
865 ref.sg_call_ents = nelems; 1086 ref.sg_call_ents = nelems;
866 bucket = get_hash_bucket(&ref, &flags); 1087 mapped_ents = get_nr_mapped_entries(dev, s);
867 entry = hash_bucket_find(bucket, &ref);
868 if (entry)
869 mapped_ents = entry->sg_mapped_ents;
870 put_hash_bucket(bucket, &flags);
871 } 1088 }
872 1089
873 check_unmap(&ref); 1090 check_unmap(&ref);
@@ -969,14 +1186,20 @@ void debug_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
969 int nelems, int direction) 1186 int nelems, int direction)
970{ 1187{
971 struct scatterlist *s; 1188 struct scatterlist *s;
972 int i; 1189 int mapped_ents = 0, i;
973 1190
974 if (unlikely(global_disable)) 1191 if (unlikely(global_disable))
975 return; 1192 return;
976 1193
977 for_each_sg(sg, s, nelems, i) { 1194 for_each_sg(sg, s, nelems, i) {
978 check_sync(dev, s->dma_address, s->dma_length, 0, 1195 if (!i)
979 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);
980 } 1203 }
981} 1204}
982EXPORT_SYMBOL(debug_dma_sync_sg_for_cpu); 1205EXPORT_SYMBOL(debug_dma_sync_sg_for_cpu);
@@ -985,15 +1208,39 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
985 int nelems, int direction) 1208 int nelems, int direction)
986{ 1209{
987 struct scatterlist *s; 1210 struct scatterlist *s;
988 int i; 1211 int mapped_ents = 0, i;
989 1212
990 if (unlikely(global_disable)) 1213 if (unlikely(global_disable))
991 return; 1214 return;
992 1215
993 for_each_sg(sg, s, nelems, i) { 1216 for_each_sg(sg, s, nelems, i) {
994 check_sync(dev, s->dma_address, s->dma_length, 0, 1217 if (!i)
995 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);
996 } 1225 }
997} 1226}
998EXPORT_SYMBOL(debug_dma_sync_sg_for_device); 1227EXPORT_SYMBOL(debug_dma_sync_sg_for_device);
999 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);