diff options
Diffstat (limited to 'lib/dma-debug.c')
-rw-r--r-- | lib/dma-debug.c | 43 |
1 files changed, 39 insertions, 4 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c index f49ab22643b7..77053d9ef513 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c | |||
@@ -242,15 +242,50 @@ static void put_hash_bucket(struct hash_bucket *bucket, | |||
242 | static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket, | 242 | static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket, |
243 | struct dma_debug_entry *ref) | 243 | struct dma_debug_entry *ref) |
244 | { | 244 | { |
245 | struct dma_debug_entry *entry; | 245 | struct dma_debug_entry *entry, *ret = NULL; |
246 | int matches = 0, match_lvl, last_lvl = 0; | ||
246 | 247 | ||
247 | list_for_each_entry(entry, &bucket->list, list) { | 248 | list_for_each_entry(entry, &bucket->list, list) { |
248 | if ((entry->dev_addr == ref->dev_addr) && | 249 | if ((entry->dev_addr != ref->dev_addr) || |
249 | (entry->dev == ref->dev)) | 250 | (entry->dev != ref->dev)) |
251 | continue; | ||
252 | |||
253 | /* | ||
254 | * Some drivers map the same physical address multiple | ||
255 | * times. Without a hardware IOMMU this results in the | ||
256 | * same device addresses being put into the dma-debug | ||
257 | * hash multiple times too. This can result in false | ||
258 | * positives being reported. Therfore we implement a | ||
259 | * best-fit algorithm here which returns the entry from | ||
260 | * the hash which fits best to the reference value | ||
261 | * instead of the first-fit. | ||
262 | */ | ||
263 | matches += 1; | ||
264 | match_lvl = 0; | ||
265 | entry->size == ref->size ? ++match_lvl : match_lvl; | ||
266 | entry->type == ref->type ? ++match_lvl : match_lvl; | ||
267 | entry->direction == ref->direction ? ++match_lvl : match_lvl; | ||
268 | |||
269 | if (match_lvl == 3) { | ||
270 | /* perfect-fit - return the result */ | ||
250 | return entry; | 271 | return entry; |
272 | } else if (match_lvl > last_lvl) { | ||
273 | /* | ||
274 | * We found an entry that fits better then the | ||
275 | * previous one | ||
276 | */ | ||
277 | last_lvl = match_lvl; | ||
278 | ret = entry; | ||
279 | } | ||
251 | } | 280 | } |
252 | 281 | ||
253 | return NULL; | 282 | /* |
283 | * If we have multiple matches but no perfect-fit, just return | ||
284 | * NULL. | ||
285 | */ | ||
286 | ret = (matches == 1) ? ret : NULL; | ||
287 | |||
288 | return ret; | ||
254 | } | 289 | } |
255 | 290 | ||
256 | /* | 291 | /* |