diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dma-debug.c | 68 |
1 files changed, 61 insertions, 7 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c index db07bfd9298..79700fa2dfc 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c | |||
@@ -62,6 +62,8 @@ struct dma_debug_entry { | |||
62 | #endif | 62 | #endif |
63 | }; | 63 | }; |
64 | 64 | ||
65 | typedef bool (*match_fn)(struct dma_debug_entry *, struct dma_debug_entry *); | ||
66 | |||
65 | struct hash_bucket { | 67 | struct hash_bucket { |
66 | struct list_head list; | 68 | struct list_head list; |
67 | spinlock_t lock; | 69 | spinlock_t lock; |
@@ -240,18 +242,37 @@ static void put_hash_bucket(struct hash_bucket *bucket, | |||
240 | spin_unlock_irqrestore(&bucket->lock, __flags); | 242 | spin_unlock_irqrestore(&bucket->lock, __flags); |
241 | } | 243 | } |
242 | 244 | ||
245 | static bool exact_match(struct dma_debug_entry *a, struct dma_debug_entry *b) | ||
246 | { | ||
247 | return ((a->dev_addr == a->dev_addr) && | ||
248 | (a->dev == b->dev)) ? true : false; | ||
249 | } | ||
250 | |||
251 | static bool containing_match(struct dma_debug_entry *a, | ||
252 | struct dma_debug_entry *b) | ||
253 | { | ||
254 | if (a->dev != b->dev) | ||
255 | return false; | ||
256 | |||
257 | if ((b->dev_addr <= a->dev_addr) && | ||
258 | ((b->dev_addr + b->size) >= (a->dev_addr + a->size))) | ||
259 | return true; | ||
260 | |||
261 | return false; | ||
262 | } | ||
263 | |||
243 | /* | 264 | /* |
244 | * Search a given entry in the hash bucket list | 265 | * Search a given entry in the hash bucket list |
245 | */ | 266 | */ |
246 | static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket, | 267 | static struct dma_debug_entry *__hash_bucket_find(struct hash_bucket *bucket, |
247 | struct dma_debug_entry *ref) | 268 | struct dma_debug_entry *ref, |
269 | match_fn match) | ||
248 | { | 270 | { |
249 | struct dma_debug_entry *entry, *ret = NULL; | 271 | struct dma_debug_entry *entry, *ret = NULL; |
250 | int matches = 0, match_lvl, last_lvl = 0; | 272 | int matches = 0, match_lvl, last_lvl = 0; |
251 | 273 | ||
252 | list_for_each_entry(entry, &bucket->list, list) { | 274 | list_for_each_entry(entry, &bucket->list, list) { |
253 | if ((entry->dev_addr != ref->dev_addr) || | 275 | if (!match(ref, entry)) |
254 | (entry->dev != ref->dev)) | ||
255 | continue; | 276 | continue; |
256 | 277 | ||
257 | /* | 278 | /* |
@@ -293,6 +314,39 @@ static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket, | |||
293 | return ret; | 314 | return ret; |
294 | } | 315 | } |
295 | 316 | ||
317 | static struct dma_debug_entry *bucket_find_exact(struct hash_bucket *bucket, | ||
318 | struct dma_debug_entry *ref) | ||
319 | { | ||
320 | return __hash_bucket_find(bucket, ref, exact_match); | ||
321 | } | ||
322 | |||
323 | static struct dma_debug_entry *bucket_find_contain(struct hash_bucket **bucket, | ||
324 | struct dma_debug_entry *ref, | ||
325 | unsigned long *flags) | ||
326 | { | ||
327 | |||
328 | unsigned int max_range = dma_get_max_seg_size(ref->dev); | ||
329 | struct dma_debug_entry *entry, index = *ref; | ||
330 | unsigned int range = 0; | ||
331 | |||
332 | while (range <= max_range) { | ||
333 | entry = __hash_bucket_find(*bucket, &index, containing_match); | ||
334 | |||
335 | if (entry) | ||
336 | return entry; | ||
337 | |||
338 | /* | ||
339 | * Nothing found, go back a hash bucket | ||
340 | */ | ||
341 | put_hash_bucket(*bucket, flags); | ||
342 | range += (1 << HASH_FN_SHIFT); | ||
343 | index.dev_addr -= (1 << HASH_FN_SHIFT); | ||
344 | *bucket = get_hash_bucket(&index, flags); | ||
345 | } | ||
346 | |||
347 | return NULL; | ||
348 | } | ||
349 | |||
296 | /* | 350 | /* |
297 | * Add an entry to a hash bucket | 351 | * Add an entry to a hash bucket |
298 | */ | 352 | */ |
@@ -802,7 +856,7 @@ static void check_unmap(struct dma_debug_entry *ref) | |||
802 | } | 856 | } |
803 | 857 | ||
804 | bucket = get_hash_bucket(ref, &flags); | 858 | bucket = get_hash_bucket(ref, &flags); |
805 | entry = hash_bucket_find(bucket, ref); | 859 | entry = bucket_find_exact(bucket, ref); |
806 | 860 | ||
807 | if (!entry) { | 861 | if (!entry) { |
808 | err_printk(ref->dev, NULL, "DMA-API: device driver tries " | 862 | err_printk(ref->dev, NULL, "DMA-API: device driver tries " |
@@ -902,7 +956,7 @@ static void check_sync(struct device *dev, | |||
902 | 956 | ||
903 | bucket = get_hash_bucket(ref, &flags); | 957 | bucket = get_hash_bucket(ref, &flags); |
904 | 958 | ||
905 | entry = hash_bucket_find(bucket, ref); | 959 | entry = bucket_find_contain(&bucket, ref, &flags); |
906 | 960 | ||
907 | if (!entry) { | 961 | if (!entry) { |
908 | err_printk(dev, NULL, "DMA-API: device driver tries " | 962 | err_printk(dev, NULL, "DMA-API: device driver tries " |
@@ -1060,7 +1114,7 @@ static int get_nr_mapped_entries(struct device *dev, | |||
1060 | int mapped_ents; | 1114 | int mapped_ents; |
1061 | 1115 | ||
1062 | bucket = get_hash_bucket(ref, &flags); | 1116 | bucket = get_hash_bucket(ref, &flags); |
1063 | entry = hash_bucket_find(bucket, ref); | 1117 | entry = bucket_find_exact(bucket, ref); |
1064 | mapped_ents = 0; | 1118 | mapped_ents = 0; |
1065 | 1119 | ||
1066 | if (entry) | 1120 | if (entry) |