diff options
Diffstat (limited to 'lib')
| -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 | { |
