aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/dma-debug.h7
-rw-r--r--lib/dma-debug.c72
2 files changed, 73 insertions, 6 deletions
diff --git a/include/linux/dma-debug.h b/include/linux/dma-debug.h
index 28d53cb7b5a2..171ad8aedc83 100644
--- a/include/linux/dma-debug.h
+++ b/include/linux/dma-debug.h
@@ -32,6 +32,8 @@ extern void dma_debug_add_bus(struct bus_type *bus);
32 32
33extern void dma_debug_init(u32 num_entries); 33extern void dma_debug_init(u32 num_entries);
34 34
35extern int dma_debug_resize_entries(u32 num_entries);
36
35extern void debug_dma_map_page(struct device *dev, struct page *page, 37extern void debug_dma_map_page(struct device *dev, struct page *page,
36 size_t offset, size_t size, 38 size_t offset, size_t size,
37 int direction, dma_addr_t dma_addr, 39 int direction, dma_addr_t dma_addr,
@@ -91,6 +93,11 @@ static inline void dma_debug_init(u32 num_entries)
91{ 93{
92} 94}
93 95
96static inline int dma_debug_resize_entries(u32 num_entries)
97{
98 return 0;
99}
100
94static inline void debug_dma_map_page(struct device *dev, struct page *page, 101static inline void debug_dma_map_page(struct device *dev, struct page *page,
95 size_t offset, size_t size, 102 size_t offset, size_t size,
96 int direction, dma_addr_t dma_addr, 103 int direction, dma_addr_t dma_addr,
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index d3da7edc034f..5d61019330cd 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -85,6 +85,7 @@ static u32 show_num_errors = 1;
85 85
86static u32 num_free_entries; 86static u32 num_free_entries;
87static u32 min_free_entries; 87static u32 min_free_entries;
88static u32 nr_total_entries;
88 89
89/* number of preallocated entries requested by kernel cmdline */ 90/* number of preallocated entries requested by kernel cmdline */
90static u32 req_entries; 91static u32 req_entries;
@@ -257,6 +258,21 @@ static void add_dma_entry(struct dma_debug_entry *entry)
257 put_hash_bucket(bucket, &flags); 258 put_hash_bucket(bucket, &flags);
258} 259}
259 260
261static struct dma_debug_entry *__dma_entry_alloc(void)
262{
263 struct dma_debug_entry *entry;
264
265 entry = list_entry(free_entries.next, struct dma_debug_entry, list);
266 list_del(&entry->list);
267 memset(entry, 0, sizeof(*entry));
268
269 num_free_entries -= 1;
270 if (num_free_entries < min_free_entries)
271 min_free_entries = num_free_entries;
272
273 return entry;
274}
275
260/* struct dma_entry allocator 276/* struct dma_entry allocator
261 * 277 *
262 * The next two functions implement the allocator for 278 * The next two functions implement the allocator for
@@ -276,9 +292,7 @@ static struct dma_debug_entry *dma_entry_alloc(void)
276 goto out; 292 goto out;
277 } 293 }
278 294
279 entry = list_entry(free_entries.next, struct dma_debug_entry, list); 295 entry = __dma_entry_alloc();
280 list_del(&entry->list);
281 memset(entry, 0, sizeof(*entry));
282 296
283#ifdef CONFIG_STACKTRACE 297#ifdef CONFIG_STACKTRACE
284 entry->stacktrace.max_entries = DMA_DEBUG_STACKTRACE_ENTRIES; 298 entry->stacktrace.max_entries = DMA_DEBUG_STACKTRACE_ENTRIES;
@@ -286,9 +300,6 @@ static struct dma_debug_entry *dma_entry_alloc(void)
286 entry->stacktrace.skip = 2; 300 entry->stacktrace.skip = 2;
287 save_stack_trace(&entry->stacktrace); 301 save_stack_trace(&entry->stacktrace);
288#endif 302#endif
289 num_free_entries -= 1;
290 if (num_free_entries < min_free_entries)
291 min_free_entries = num_free_entries;
292 303
293out: 304out:
294 spin_unlock_irqrestore(&free_entries_lock, flags); 305 spin_unlock_irqrestore(&free_entries_lock, flags);
@@ -310,6 +321,53 @@ static void dma_entry_free(struct dma_debug_entry *entry)
310 spin_unlock_irqrestore(&free_entries_lock, flags); 321 spin_unlock_irqrestore(&free_entries_lock, flags);
311} 322}
312 323
324int dma_debug_resize_entries(u32 num_entries)
325{
326 int i, delta, ret = 0;
327 unsigned long flags;
328 struct dma_debug_entry *entry;
329 LIST_HEAD(tmp);
330
331 spin_lock_irqsave(&free_entries_lock, flags);
332
333 if (nr_total_entries < num_entries) {
334 delta = num_entries - nr_total_entries;
335
336 spin_unlock_irqrestore(&free_entries_lock, flags);
337
338 for (i = 0; i < delta; i++) {
339 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
340 if (!entry)
341 break;
342
343 list_add_tail(&entry->list, &tmp);
344 }
345
346 spin_lock_irqsave(&free_entries_lock, flags);
347
348 list_splice(&tmp, &free_entries);
349 nr_total_entries += i;
350 num_free_entries += i;
351 } else {
352 delta = nr_total_entries - num_entries;
353
354 for (i = 0; i < delta && !list_empty(&free_entries); i++) {
355 entry = __dma_entry_alloc();
356 kfree(entry);
357 }
358
359 nr_total_entries -= i;
360 }
361
362 if (nr_total_entries != num_entries)
363 ret = 1;
364
365 spin_unlock_irqrestore(&free_entries_lock, flags);
366
367 return ret;
368}
369EXPORT_SYMBOL(dma_debug_resize_entries);
370
313/* 371/*
314 * DMA-API debugging init code 372 * DMA-API debugging init code
315 * 373 *
@@ -490,6 +548,8 @@ void dma_debug_init(u32 num_entries)
490 return; 548 return;
491 } 549 }
492 550
551 nr_total_entries = num_free_entries;
552
493 printk(KERN_INFO "DMA-API: debugging enabled by kernel config\n"); 553 printk(KERN_INFO "DMA-API: debugging enabled by kernel config\n");
494} 554}
495 555