diff options
Diffstat (limited to 'lib/dma-debug.c')
-rw-r--r-- | lib/dma-debug.c | 66 |
1 files changed, 57 insertions, 9 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c index d84beb994f36..5e396accd3d0 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 | ||
48 | enum 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 | ||
50 | struct dma_debug_entry { | 56 | struct 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 | ||
115 | static DEFINE_RWLOCK(driver_name_lock); | 122 | static DEFINE_RWLOCK(driver_name_lock); |
116 | 123 | ||
124 | static 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 | |||
117 | static const char *type2name[4] = { "single", "page", | 130 | static 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 | ||
@@ -844,16 +858,16 @@ static void check_unmap(struct dma_debug_entry *ref) | |||
844 | struct hash_bucket *bucket; | 858 | struct hash_bucket *bucket; |
845 | unsigned long flags; | 859 | unsigned long flags; |
846 | 860 | ||
847 | if (dma_mapping_error(ref->dev, ref->dev_addr)) { | ||
848 | err_printk(ref->dev, NULL, "DMA-API: device driver tries " | ||
849 | "to free an invalid DMA memory address\n"); | ||
850 | return; | ||
851 | } | ||
852 | |||
853 | bucket = get_hash_bucket(ref, &flags); | 861 | bucket = get_hash_bucket(ref, &flags); |
854 | entry = bucket_find_exact(bucket, ref); | 862 | entry = bucket_find_exact(bucket, ref); |
855 | 863 | ||
856 | if (!entry) { | 864 | if (!entry) { |
865 | if (dma_mapping_error(ref->dev, ref->dev_addr)) { | ||
866 | err_printk(ref->dev, NULL, | ||
867 | "DMA-API: device driver tries " | ||
868 | "to free an invalid DMA memory address\n"); | ||
869 | return; | ||
870 | } | ||
857 | err_printk(ref->dev, NULL, "DMA-API: device driver tries " | 871 | err_printk(ref->dev, NULL, "DMA-API: device driver tries " |
858 | "to free DMA memory it has not allocated " | 872 | "to free DMA memory it has not allocated " |
859 | "[device address=0x%016llx] [size=%llu bytes]\n", | 873 | "[device address=0x%016llx] [size=%llu bytes]\n", |
@@ -910,6 +924,15 @@ static void check_unmap(struct dma_debug_entry *ref) | |||
910 | dir2name[ref->direction]); | 924 | dir2name[ref->direction]); |
911 | } | 925 | } |
912 | 926 | ||
927 | if (entry->map_err_type == MAP_ERR_NOT_CHECKED) { | ||
928 | err_printk(ref->dev, entry, | ||
929 | "DMA-API: device driver failed to check map error" | ||
930 | "[device address=0x%016llx] [size=%llu bytes] " | ||
931 | "[mapped as %s]", | ||
932 | ref->dev_addr, ref->size, | ||
933 | type2name[entry->type]); | ||
934 | } | ||
935 | |||
913 | hash_bucket_del(entry); | 936 | hash_bucket_del(entry); |
914 | dma_entry_free(entry); | 937 | dma_entry_free(entry); |
915 | 938 | ||
@@ -1017,7 +1040,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, | |||
1017 | if (unlikely(global_disable)) | 1040 | if (unlikely(global_disable)) |
1018 | return; | 1041 | return; |
1019 | 1042 | ||
1020 | if (unlikely(dma_mapping_error(dev, dma_addr))) | 1043 | if (dma_mapping_error(dev, dma_addr)) |
1021 | return; | 1044 | return; |
1022 | 1045 | ||
1023 | entry = dma_entry_alloc(); | 1046 | entry = dma_entry_alloc(); |
@@ -1030,6 +1053,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, | |||
1030 | entry->dev_addr = dma_addr; | 1053 | entry->dev_addr = dma_addr; |
1031 | entry->size = size; | 1054 | entry->size = size; |
1032 | entry->direction = direction; | 1055 | entry->direction = direction; |
1056 | entry->map_err_type = MAP_ERR_NOT_CHECKED; | ||
1033 | 1057 | ||
1034 | if (map_single) | 1058 | if (map_single) |
1035 | entry->type = dma_debug_single; | 1059 | entry->type = dma_debug_single; |
@@ -1045,6 +1069,30 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, | |||
1045 | } | 1069 | } |
1046 | EXPORT_SYMBOL(debug_dma_map_page); | 1070 | EXPORT_SYMBOL(debug_dma_map_page); |
1047 | 1071 | ||
1072 | void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) | ||
1073 | { | ||
1074 | struct dma_debug_entry ref; | ||
1075 | struct dma_debug_entry *entry; | ||
1076 | struct hash_bucket *bucket; | ||
1077 | unsigned long flags; | ||
1078 | |||
1079 | if (unlikely(global_disable)) | ||
1080 | return; | ||
1081 | |||
1082 | ref.dev = dev; | ||
1083 | ref.dev_addr = dma_addr; | ||
1084 | bucket = get_hash_bucket(&ref, &flags); | ||
1085 | entry = bucket_find_exact(bucket, &ref); | ||
1086 | |||
1087 | if (!entry) | ||
1088 | goto out; | ||
1089 | |||
1090 | entry->map_err_type = MAP_ERR_CHECKED; | ||
1091 | out: | ||
1092 | put_hash_bucket(bucket, &flags); | ||
1093 | } | ||
1094 | EXPORT_SYMBOL(debug_dma_mapping_error); | ||
1095 | |||
1048 | void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, | 1096 | void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, |
1049 | size_t size, int direction, bool map_single) | 1097 | size_t size, int direction, bool map_single) |
1050 | { | 1098 | { |