aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShuah Khan <shuah.khan@hp.com>2012-10-08 13:08:06 -0400
committerJoerg Roedel <joerg.roedel@amd.com>2012-10-24 11:06:43 -0400
commit6c9c6d6301287e369a754d628230fa6e50cdb74b (patch)
treece47f4a8f5005c663c2686ec00d0ba272ace598d
parent6f0c0580b70c89094b3422ba81118c7b959c7556 (diff)
dma-debug: New interfaces to debug dma mapping errors
Add dma-debug interface debug_dma_mapping_error() to debug drivers that fail to check dma mapping errors on addresses returned by dma_map_single() and dma_map_page() interfaces. This interface clears a flag set by debug_dma_map_page() to indicate that dma_mapping_error() has been called by the driver. When driver does unmap, debug_dma_unmap() checks the flag and if this flag is still set, prints warning message that includes call trace that leads up to the unmap. This interface can be called from dma_mapping_error() routines to enable dma mapping error check debugging. Tested: Intel iommu and swiotlb (iommu=soft) on x86-64 with CONFIG_DMA_API_DEBUG enabled and disabled. Signed-off-by: Shuah Khan <shuah.khan@hp.com> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
-rw-r--r--Documentation/DMA-API.txt12
-rw-r--r--arch/x86/include/asm/dma-mapping.h1
-rw-r--r--include/linux/dma-debug.h7
-rw-r--r--lib/dma-debug.c71
4 files changed, 87 insertions, 4 deletions
diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
index 66bd97a95f10..78a6c569d204 100644
--- a/Documentation/DMA-API.txt
+++ b/Documentation/DMA-API.txt
@@ -678,3 +678,15 @@ out of dma_debug_entries. These entries are preallocated at boot. The number
678of preallocated entries is defined per architecture. If it is too low for you 678of preallocated entries is defined per architecture. If it is too low for you
679boot with 'dma_debug_entries=<your_desired_number>' to overwrite the 679boot with 'dma_debug_entries=<your_desired_number>' to overwrite the
680architectural default. 680architectural default.
681
682void debug_dmap_mapping_error(struct device *dev, dma_addr_t dma_addr);
683
684dma-debug interface debug_dma_mapping_error() to debug drivers that fail
685to check dma mapping errors on addresses returned by dma_map_single() and
686dma_map_page() interfaces. This interface clears a flag set by
687debug_dma_map_page() to indicate that dma_mapping_error() has been called by
688the driver. When driver does unmap, debug_dma_unmap() checks the flag and if
689this flag is still set, prints warning message that includes call trace that
690leads up to the unmap. This interface can be called from dma_mapping_error()
691routines to enable dma mapping error check debugging.
692
diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h
index f7b4c7903e7e..808dae63eeea 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -47,6 +47,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
47static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) 47static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
48{ 48{
49 struct dma_map_ops *ops = get_dma_ops(dev); 49 struct dma_map_ops *ops = get_dma_ops(dev);
50 debug_dma_mapping_error(dev, dma_addr);
50 if (ops->mapping_error) 51 if (ops->mapping_error)
51 return ops->mapping_error(dev, dma_addr); 52 return ops->mapping_error(dev, dma_addr);
52 53
diff --git a/include/linux/dma-debug.h b/include/linux/dma-debug.h
index 171ad8aedc83..fc0e34ce038f 100644
--- a/include/linux/dma-debug.h
+++ b/include/linux/dma-debug.h
@@ -39,6 +39,8 @@ extern void debug_dma_map_page(struct device *dev, struct page *page,
39 int direction, dma_addr_t dma_addr, 39 int direction, dma_addr_t dma_addr,
40 bool map_single); 40 bool map_single);
41 41
42extern void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
43
42extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, 44extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
43 size_t size, int direction, bool map_single); 45 size_t size, int direction, bool map_single);
44 46
@@ -105,6 +107,11 @@ static inline void debug_dma_map_page(struct device *dev, struct page *page,
105{ 107{
106} 108}
107 109
110static inline void debug_dma_mapping_error(struct device *dev,
111 dma_addr_t dma_addr)
112{
113}
114
108static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, 115static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
109 size_t size, int direction, 116 size_t size, int direction,
110 bool map_single) 117 bool map_single)
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index d84beb994f36..59f4a1a8187d 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -45,6 +45,12 @@ enum {
45 dma_debug_coherent, 45 dma_debug_coherent,
46}; 46};
47 47
48enum map_err_types {
49 MAP_ERR_CHECK_NOT_APPLICABLE,
50 MAP_ERR_NOT_CHECKED,
51 MAP_ERR_CHECKED,
52};
53
48#define DMA_DEBUG_STACKTRACE_ENTRIES 5 54#define DMA_DEBUG_STACKTRACE_ENTRIES 5
49 55
50struct dma_debug_entry { 56struct dma_debug_entry {
@@ -57,6 +63,7 @@ struct dma_debug_entry {
57 int direction; 63 int direction;
58 int sg_call_ents; 64 int sg_call_ents;
59 int sg_mapped_ents; 65 int sg_mapped_ents;
66 enum map_err_types map_err_type;
60#ifdef CONFIG_STACKTRACE 67#ifdef CONFIG_STACKTRACE
61 struct stack_trace stacktrace; 68 struct stack_trace stacktrace;
62 unsigned long st_entries[DMA_DEBUG_STACKTRACE_ENTRIES]; 69 unsigned long st_entries[DMA_DEBUG_STACKTRACE_ENTRIES];
@@ -114,6 +121,12 @@ static struct device_driver *current_driver __read_mostly;
114 121
115static DEFINE_RWLOCK(driver_name_lock); 122static DEFINE_RWLOCK(driver_name_lock);
116 123
124static const char *const maperr2str[] = {
125 [MAP_ERR_CHECK_NOT_APPLICABLE] = "dma map error check not applicable",
126 [MAP_ERR_NOT_CHECKED] = "dma map error not checked",
127 [MAP_ERR_CHECKED] = "dma map error checked",
128};
129
117static const char *type2name[4] = { "single", "page", 130static const char *type2name[4] = { "single", "page",
118 "scather-gather", "coherent" }; 131 "scather-gather", "coherent" };
119 132
@@ -376,11 +389,12 @@ void debug_dma_dump_mappings(struct device *dev)
376 list_for_each_entry(entry, &bucket->list, list) { 389 list_for_each_entry(entry, &bucket->list, list) {
377 if (!dev || dev == entry->dev) { 390 if (!dev || dev == entry->dev) {
378 dev_info(entry->dev, 391 dev_info(entry->dev,
379 "%s idx %d P=%Lx D=%Lx L=%Lx %s\n", 392 "%s idx %d P=%Lx D=%Lx L=%Lx %s %s\n",
380 type2name[entry->type], idx, 393 type2name[entry->type], idx,
381 (unsigned long long)entry->paddr, 394 (unsigned long long)entry->paddr,
382 entry->dev_addr, entry->size, 395 entry->dev_addr, entry->size,
383 dir2name[entry->direction]); 396 dir2name[entry->direction],
397 maperr2str[entry->map_err_type]);
384 } 398 }
385 } 399 }
386 400
@@ -838,13 +852,28 @@ static __init int dma_debug_entries_cmdline(char *str)
838__setup("dma_debug=", dma_debug_cmdline); 852__setup("dma_debug=", dma_debug_cmdline);
839__setup("dma_debug_entries=", dma_debug_entries_cmdline); 853__setup("dma_debug_entries=", dma_debug_entries_cmdline);
840 854
855/* Calling dma_mapping_error() from dma-debug api will result in calling
856 debug_dma_mapping_error() - need internal mapping error routine to
857 avoid debug checks */
858#ifndef DMA_ERROR_CODE
859#define DMA_ERROR_CODE 0
860#endif
861static inline int has_mapping_error(struct device *dev, dma_addr_t dma_addr)
862{
863 const struct dma_map_ops *ops = get_dma_ops(dev);
864 if (ops->mapping_error)
865 return ops->mapping_error(dev, dma_addr);
866
867 return (dma_addr == DMA_ERROR_CODE);
868}
869
841static void check_unmap(struct dma_debug_entry *ref) 870static void check_unmap(struct dma_debug_entry *ref)
842{ 871{
843 struct dma_debug_entry *entry; 872 struct dma_debug_entry *entry;
844 struct hash_bucket *bucket; 873 struct hash_bucket *bucket;
845 unsigned long flags; 874 unsigned long flags;
846 875
847 if (dma_mapping_error(ref->dev, ref->dev_addr)) { 876 if (unlikely(has_mapping_error(ref->dev, ref->dev_addr))) {
848 err_printk(ref->dev, NULL, "DMA-API: device driver tries " 877 err_printk(ref->dev, NULL, "DMA-API: device driver tries "
849 "to free an invalid DMA memory address\n"); 878 "to free an invalid DMA memory address\n");
850 return; 879 return;
@@ -910,6 +939,15 @@ static void check_unmap(struct dma_debug_entry *ref)
910 dir2name[ref->direction]); 939 dir2name[ref->direction]);
911 } 940 }
912 941
942 if (entry->map_err_type == MAP_ERR_NOT_CHECKED) {
943 err_printk(ref->dev, entry,
944 "DMA-API: device driver failed to check map error"
945 "[device address=0x%016llx] [size=%llu bytes] "
946 "[mapped as %s]",
947 ref->dev_addr, ref->size,
948 type2name[entry->type]);
949 }
950
913 hash_bucket_del(entry); 951 hash_bucket_del(entry);
914 dma_entry_free(entry); 952 dma_entry_free(entry);
915 953
@@ -1017,7 +1055,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
1017 if (unlikely(global_disable)) 1055 if (unlikely(global_disable))
1018 return; 1056 return;
1019 1057
1020 if (unlikely(dma_mapping_error(dev, dma_addr))) 1058 if (unlikely(has_mapping_error(dev, dma_addr)))
1021 return; 1059 return;
1022 1060
1023 entry = dma_entry_alloc(); 1061 entry = dma_entry_alloc();
@@ -1030,6 +1068,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
1030 entry->dev_addr = dma_addr; 1068 entry->dev_addr = dma_addr;
1031 entry->size = size; 1069 entry->size = size;
1032 entry->direction = direction; 1070 entry->direction = direction;
1071 entry->map_err_type = MAP_ERR_NOT_CHECKED;
1033 1072
1034 if (map_single) 1073 if (map_single)
1035 entry->type = dma_debug_single; 1074 entry->type = dma_debug_single;
@@ -1045,6 +1084,30 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
1045} 1084}
1046EXPORT_SYMBOL(debug_dma_map_page); 1085EXPORT_SYMBOL(debug_dma_map_page);
1047 1086
1087void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
1088{
1089 struct dma_debug_entry ref;
1090 struct dma_debug_entry *entry;
1091 struct hash_bucket *bucket;
1092 unsigned long flags;
1093
1094 if (unlikely(global_disable))
1095 return;
1096
1097 ref.dev = dev;
1098 ref.dev_addr = dma_addr;
1099 bucket = get_hash_bucket(&ref, &flags);
1100 entry = bucket_find_exact(bucket, &ref);
1101
1102 if (!entry)
1103 goto out;
1104
1105 entry->map_err_type = MAP_ERR_CHECKED;
1106out:
1107 put_hash_bucket(bucket, &flags);
1108}
1109EXPORT_SYMBOL(debug_dma_mapping_error);
1110
1048void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, 1111void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
1049 size_t size, int direction, bool map_single) 1112 size_t size, int direction, bool map_single)
1050{ 1113{