aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dma-debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dma-debug.c')
-rw-r--r--lib/dma-debug.c65
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
44enum { 49enum {
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;
127static u32 nr_total_entries; 132static u32 nr_total_entries;
128 133
129/* number of preallocated entries requested by kernel cmdline */ 134/* number of preallocated entries requested by kernel cmdline */
130static u32 req_entries; 135static 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 */
133static struct dentry *dma_debug_dent __read_mostly; 138static 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}
442EXPORT_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}
751EXPORT_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/* 1010static int dma_debug_init(void)
1008 * Let the architectures decide how many entries should be preallocated.
1009 */
1010void 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}
1046core_initcall(dma_debug_init);
1048 1047
1049static __init int dma_debug_cmdline(char *str) 1048static __init int dma_debug_cmdline(char *str)
1050{ 1049{
@@ -1061,16 +1060,10 @@ static __init int dma_debug_cmdline(char *str)
1061 1060
1062static __init int dma_debug_entries_cmdline(char *str) 1061static __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
1289static 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
1296void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, 1315void 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}