diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2013-04-09 15:29:20 +0200 | 
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2013-04-09 15:29:43 +0200 | 
| commit | 44c0d2377539fafd1023ec7e16765b71c7f4fbce (patch) | |
| tree | 49065c2af83c723f150bf636939790ad3108a897 /lib/dma-debug.c | |
| parent | 8024206dbf4e0701f0cdf259a122ea23db3a7a16 (diff) | |
| parent | 07961ac7c0ee8b546658717034fe692fd12eefa9 (diff) | |
| download | olio-linux-3.10-44c0d2377539fafd1023ec7e16765b71c7f4fbce.tar.xz olio-linux-3.10-44c0d2377539fafd1023ec7e16765b71c7f4fbce.zip  | |
Merge tag 'v3.9-rc5' into next/cleanup
This is a dependency for the mxs/cleanup branch.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'lib/dma-debug.c')
| -rw-r--r-- | lib/dma-debug.c | 45 | 
1 files changed, 31 insertions, 14 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c index 5e396accd3d..d87a17a819d 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -862,17 +862,21 @@ static void check_unmap(struct dma_debug_entry *ref)  	entry = bucket_find_exact(bucket, ref);  	if (!entry) { +		/* must drop lock before calling dma_mapping_error */ +		put_hash_bucket(bucket, &flags); +  		if (dma_mapping_error(ref->dev, ref->dev_addr)) {  			err_printk(ref->dev, NULL, -				   "DMA-API: device driver tries " -				   "to free an invalid DMA memory address\n"); -			return; +				   "DMA-API: device driver tries to free an " +				   "invalid DMA memory address\n"); +		} else { +			err_printk(ref->dev, NULL, +				   "DMA-API: device driver tries to free DMA " +				   "memory it has not allocated [device " +				   "address=0x%016llx] [size=%llu bytes]\n", +				   ref->dev_addr, ref->size);  		} -		err_printk(ref->dev, NULL, "DMA-API: device driver tries " -			   "to free DMA memory it has not allocated " -			   "[device address=0x%016llx] [size=%llu bytes]\n", -			   ref->dev_addr, ref->size); -		goto out; +		return;  	}  	if (ref->size != entry->size) { @@ -936,7 +940,6 @@ static void check_unmap(struct dma_debug_entry *ref)  	hash_bucket_del(entry);  	dma_entry_free(entry); -out:  	put_hash_bucket(bucket, &flags);  } @@ -1082,13 +1085,27 @@ void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)  	ref.dev = dev;  	ref.dev_addr = dma_addr;  	bucket = get_hash_bucket(&ref, &flags); -	entry = bucket_find_exact(bucket, &ref); -	if (!entry) -		goto out; +	list_for_each_entry(entry, &bucket->list, list) { +		if (!exact_match(&ref, entry)) +			continue; + +		/* +		 * The same physical address can be mapped multiple +		 * times. Without a hardware IOMMU this results in the +		 * same device addresses being put into the dma-debug +		 * hash multiple times too. This can result in false +		 * positives being reported. Therefore we implement a +		 * best-fit algorithm here which updates the first entry +		 * from the hash which fits the reference value and is +		 * not currently listed as being checked. +		 */ +		if (entry->map_err_type == MAP_ERR_NOT_CHECKED) { +			entry->map_err_type = MAP_ERR_CHECKED; +			break; +		} +	} -	entry->map_err_type = MAP_ERR_CHECKED; -out:  	put_hash_bucket(bucket, &flags);  }  EXPORT_SYMBOL(debug_dma_mapping_error);  |