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 @@  #define HASH_FN_SHIFT   13  #define HASH_FN_MASK    (HASH_SIZE - 1) +/* allow architectures to override this if absolutely required */ +#ifndef PREALLOC_DMA_DEBUG_ENTRIES +#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) +#endif +  enum {  	dma_debug_single,  	dma_debug_page, @@ -127,7 +132,7 @@ static u32 min_free_entries;  static u32 nr_total_entries;  /* number of preallocated entries requested by kernel cmdline */ -static u32 req_entries; +static u32 nr_prealloc_entries = PREALLOC_DMA_DEBUG_ENTRIES;  /* debugfs dentry's for the stuff above */  static struct dentry *dma_debug_dent        __read_mostly; @@ -439,7 +444,6 @@ void debug_dma_dump_mappings(struct device *dev)  		spin_unlock_irqrestore(&bucket->lock, flags);  	}  } -EXPORT_SYMBOL(debug_dma_dump_mappings);  /*   * For each mapping (initial cacheline in the case of @@ -748,7 +752,6 @@ int dma_debug_resize_entries(u32 num_entries)  	return ret;  } -EXPORT_SYMBOL(dma_debug_resize_entries);  /*   * DMA-API debugging init code @@ -1004,10 +1007,7 @@ void dma_debug_add_bus(struct bus_type *bus)  	bus_register_notifier(bus, nb);  } -/* - * Let the architectures decide how many entries should be preallocated. - */ -void dma_debug_init(u32 num_entries) +static int dma_debug_init(void)  {  	int i; @@ -1015,7 +1015,7 @@ void dma_debug_init(u32 num_entries)  	 * called to set dma_debug_initialized  	 */  	if (global_disable) -		return; +		return 0;  	for (i = 0; i < HASH_SIZE; ++i) {  		INIT_LIST_HEAD(&dma_entry_hash[i].list); @@ -1026,17 +1026,14 @@ void dma_debug_init(u32 num_entries)  		pr_err("DMA-API: error creating debugfs entries - disabling\n");  		global_disable = true; -		return; +		return 0;  	} -	if (req_entries) -		num_entries = req_entries; - -	if (prealloc_memory(num_entries) != 0) { +	if (prealloc_memory(nr_prealloc_entries) != 0) {  		pr_err("DMA-API: debugging out of memory error - disabled\n");  		global_disable = true; -		return; +		return 0;  	}  	nr_total_entries = num_free_entries; @@ -1044,7 +1041,9 @@ void dma_debug_init(u32 num_entries)  	dma_debug_initialized = true;  	pr_info("DMA-API: debugging enabled by kernel config\n"); +	return 0;  } +core_initcall(dma_debug_init);  static __init int dma_debug_cmdline(char *str)  { @@ -1061,16 +1060,10 @@ static __init int dma_debug_cmdline(char *str)  static __init int dma_debug_entries_cmdline(char *str)  { -	int res; -  	if (!str)  		return -EINVAL; - -	res = get_option(&str, &req_entries); - -	if (!res) -		req_entries = 0; - +	if (!get_option(&str, &nr_prealloc_entries)) +		nr_prealloc_entries = PREALLOC_DMA_DEBUG_ENTRIES;  	return 0;  } @@ -1293,6 +1286,32 @@ out:  	put_hash_bucket(bucket, &flags);  } +static void check_sg_segment(struct device *dev, struct scatterlist *sg) +{ +#ifdef CONFIG_DMA_API_DEBUG_SG +	unsigned int max_seg = dma_get_max_seg_size(dev); +	u64 start, end, boundary = dma_get_seg_boundary(dev); + +	/* +	 * Either the driver forgot to set dma_parms appropriately, or +	 * whoever generated the list forgot to check them. +	 */ +	if (sg->length > max_seg) +		err_printk(dev, NULL, "DMA-API: mapping sg segment longer than device claims to support [len=%u] [max=%u]\n", +			   sg->length, max_seg); +	/* +	 * In some cases this could potentially be the DMA API +	 * implementation's fault, but it would usually imply that +	 * the scatterlist was built inappropriately to begin with. +	 */ +	start = sg_dma_address(sg); +	end = start + sg_dma_len(sg) - 1; +	if ((start ^ end) & ~boundary) +		err_printk(dev, NULL, "DMA-API: mapping sg segment across boundary [start=0x%016llx] [end=0x%016llx] [boundary=0x%016llx]\n", +			   start, end, boundary); +#endif +} +  void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,  			size_t size, int direction, dma_addr_t dma_addr,  			bool map_single) @@ -1423,6 +1442,8 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,  			check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s));  		} +		check_sg_segment(dev, s); +  		add_dma_entry(entry);  	}  } | 
