diff options
Diffstat (limited to 'lib/dma-debug.c')
-rw-r--r-- | lib/dma-debug.c | 65 |
1 files changed, 43 insertions, 22 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c index 7f5cdc1e6b29..c007d25bee09 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c | |||
@@ -41,6 +41,11 @@ | |||
41 | #define HASH_FN_SHIFT 13 | 41 | #define HASH_FN_SHIFT 13 |
42 | #define HASH_FN_MASK (HASH_SIZE - 1) | 42 | #define HASH_FN_MASK (HASH_SIZE - 1) |
43 | 43 | ||
44 | /* allow architectures to override this if absolutely required */ | ||
45 | #ifndef PREALLOC_DMA_DEBUG_ENTRIES | ||
46 | #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) | ||
47 | #endif | ||
48 | |||
44 | enum { | 49 | enum { |
45 | dma_debug_single, | 50 | dma_debug_single, |
46 | dma_debug_page, | 51 | dma_debug_page, |
@@ -127,7 +132,7 @@ static u32 min_free_entries; | |||
127 | static u32 nr_total_entries; | 132 | static u32 nr_total_entries; |
128 | 133 | ||
129 | /* number of preallocated entries requested by kernel cmdline */ | 134 | /* number of preallocated entries requested by kernel cmdline */ |
130 | static u32 req_entries; | 135 | static u32 nr_prealloc_entries = PREALLOC_DMA_DEBUG_ENTRIES; |
131 | 136 | ||
132 | /* debugfs dentry's for the stuff above */ | 137 | /* debugfs dentry's for the stuff above */ |
133 | static struct dentry *dma_debug_dent __read_mostly; | 138 | static struct dentry *dma_debug_dent __read_mostly; |
@@ -439,7 +444,6 @@ void debug_dma_dump_mappings(struct device *dev) | |||
439 | spin_unlock_irqrestore(&bucket->lock, flags); | 444 | spin_unlock_irqrestore(&bucket->lock, flags); |
440 | } | 445 | } |
441 | } | 446 | } |
442 | EXPORT_SYMBOL(debug_dma_dump_mappings); | ||
443 | 447 | ||
444 | /* | 448 | /* |
445 | * For each mapping (initial cacheline in the case of | 449 | * For each mapping (initial cacheline in the case of |
@@ -748,7 +752,6 @@ int dma_debug_resize_entries(u32 num_entries) | |||
748 | 752 | ||
749 | return ret; | 753 | return ret; |
750 | } | 754 | } |
751 | EXPORT_SYMBOL(dma_debug_resize_entries); | ||
752 | 755 | ||
753 | /* | 756 | /* |
754 | * DMA-API debugging init code | 757 | * DMA-API debugging init code |
@@ -1004,10 +1007,7 @@ void dma_debug_add_bus(struct bus_type *bus) | |||
1004 | bus_register_notifier(bus, nb); | 1007 | bus_register_notifier(bus, nb); |
1005 | } | 1008 | } |
1006 | 1009 | ||
1007 | /* | 1010 | static int dma_debug_init(void) |
1008 | * Let the architectures decide how many entries should be preallocated. | ||
1009 | */ | ||
1010 | void dma_debug_init(u32 num_entries) | ||
1011 | { | 1011 | { |
1012 | int i; | 1012 | int i; |
1013 | 1013 | ||
@@ -1015,7 +1015,7 @@ void dma_debug_init(u32 num_entries) | |||
1015 | * called to set dma_debug_initialized | 1015 | * called to set dma_debug_initialized |
1016 | */ | 1016 | */ |
1017 | if (global_disable) | 1017 | if (global_disable) |
1018 | return; | 1018 | return 0; |
1019 | 1019 | ||
1020 | for (i = 0; i < HASH_SIZE; ++i) { | 1020 | for (i = 0; i < HASH_SIZE; ++i) { |
1021 | INIT_LIST_HEAD(&dma_entry_hash[i].list); | 1021 | INIT_LIST_HEAD(&dma_entry_hash[i].list); |
@@ -1026,17 +1026,14 @@ void dma_debug_init(u32 num_entries) | |||
1026 | pr_err("DMA-API: error creating debugfs entries - disabling\n"); | 1026 | pr_err("DMA-API: error creating debugfs entries - disabling\n"); |
1027 | global_disable = true; | 1027 | global_disable = true; |
1028 | 1028 | ||
1029 | return; | 1029 | return 0; |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | if (req_entries) | 1032 | if (prealloc_memory(nr_prealloc_entries) != 0) { |
1033 | num_entries = req_entries; | ||
1034 | |||
1035 | if (prealloc_memory(num_entries) != 0) { | ||
1036 | pr_err("DMA-API: debugging out of memory error - disabled\n"); | 1033 | pr_err("DMA-API: debugging out of memory error - disabled\n"); |
1037 | global_disable = true; | 1034 | global_disable = true; |
1038 | 1035 | ||
1039 | return; | 1036 | return 0; |
1040 | } | 1037 | } |
1041 | 1038 | ||
1042 | nr_total_entries = num_free_entries; | 1039 | nr_total_entries = num_free_entries; |
@@ -1044,7 +1041,9 @@ void dma_debug_init(u32 num_entries) | |||
1044 | dma_debug_initialized = true; | 1041 | dma_debug_initialized = true; |
1045 | 1042 | ||
1046 | pr_info("DMA-API: debugging enabled by kernel config\n"); | 1043 | pr_info("DMA-API: debugging enabled by kernel config\n"); |
1044 | return 0; | ||
1047 | } | 1045 | } |
1046 | core_initcall(dma_debug_init); | ||
1048 | 1047 | ||
1049 | static __init int dma_debug_cmdline(char *str) | 1048 | static __init int dma_debug_cmdline(char *str) |
1050 | { | 1049 | { |
@@ -1061,16 +1060,10 @@ static __init int dma_debug_cmdline(char *str) | |||
1061 | 1060 | ||
1062 | static __init int dma_debug_entries_cmdline(char *str) | 1061 | static __init int dma_debug_entries_cmdline(char *str) |
1063 | { | 1062 | { |
1064 | int res; | ||
1065 | |||
1066 | if (!str) | 1063 | if (!str) |
1067 | return -EINVAL; | 1064 | return -EINVAL; |
1068 | 1065 | if (!get_option(&str, &nr_prealloc_entries)) | |
1069 | res = get_option(&str, &req_entries); | 1066 | nr_prealloc_entries = PREALLOC_DMA_DEBUG_ENTRIES; |
1070 | |||
1071 | if (!res) | ||
1072 | req_entries = 0; | ||
1073 | |||
1074 | return 0; | 1067 | return 0; |
1075 | } | 1068 | } |
1076 | 1069 | ||
@@ -1293,6 +1286,32 @@ out: | |||
1293 | put_hash_bucket(bucket, &flags); | 1286 | put_hash_bucket(bucket, &flags); |
1294 | } | 1287 | } |
1295 | 1288 | ||
1289 | static void check_sg_segment(struct device *dev, struct scatterlist *sg) | ||
1290 | { | ||
1291 | #ifdef CONFIG_DMA_API_DEBUG_SG | ||
1292 | unsigned int max_seg = dma_get_max_seg_size(dev); | ||
1293 | u64 start, end, boundary = dma_get_seg_boundary(dev); | ||
1294 | |||
1295 | /* | ||
1296 | * Either the driver forgot to set dma_parms appropriately, or | ||
1297 | * whoever generated the list forgot to check them. | ||
1298 | */ | ||
1299 | if (sg->length > max_seg) | ||
1300 | err_printk(dev, NULL, "DMA-API: mapping sg segment longer than device claims to support [len=%u] [max=%u]\n", | ||
1301 | sg->length, max_seg); | ||
1302 | /* | ||
1303 | * In some cases this could potentially be the DMA API | ||
1304 | * implementation's fault, but it would usually imply that | ||
1305 | * the scatterlist was built inappropriately to begin with. | ||
1306 | */ | ||
1307 | start = sg_dma_address(sg); | ||
1308 | end = start + sg_dma_len(sg) - 1; | ||
1309 | if ((start ^ end) & ~boundary) | ||
1310 | err_printk(dev, NULL, "DMA-API: mapping sg segment across boundary [start=0x%016llx] [end=0x%016llx] [boundary=0x%016llx]\n", | ||
1311 | start, end, boundary); | ||
1312 | #endif | ||
1313 | } | ||
1314 | |||
1296 | void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, | 1315 | void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, |
1297 | size_t size, int direction, dma_addr_t dma_addr, | 1316 | size_t size, int direction, dma_addr_t dma_addr, |
1298 | bool map_single) | 1317 | bool map_single) |
@@ -1423,6 +1442,8 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, | |||
1423 | check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s)); | 1442 | check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s)); |
1424 | } | 1443 | } |
1425 | 1444 | ||
1445 | check_sg_segment(dev, s); | ||
1446 | |||
1426 | add_dma_entry(entry); | 1447 | add_dma_entry(entry); |
1427 | } | 1448 | } |
1428 | } | 1449 | } |