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 | /* |
