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 | } |
