diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2009-05-22 11:16:04 -0400 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2009-05-28 11:09:07 -0400 |
commit | ed888aef427365d19f887c271a3a906d16422d24 (patch) | |
tree | 31788a63f76e73e12ea5ef7f2374cd42a1b24846 /lib | |
parent | 41fb454ebe6024f5c1e3b3cbc0abc0da762e7b51 (diff) |
dma-debug: re-add dma memory leak detection
This is basically a revert of commit 314eeac9 but now in a
fixed version.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dma-debug.c | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c index cdd205d6bf7c..e47e1a08c337 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c | |||
@@ -105,6 +105,11 @@ static const char *type2name[4] = { "single", "page", | |||
105 | static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE", | 105 | static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE", |
106 | "DMA_FROM_DEVICE", "DMA_NONE" }; | 106 | "DMA_FROM_DEVICE", "DMA_NONE" }; |
107 | 107 | ||
108 | /* little merge helper - remove it after the merge window */ | ||
109 | #ifndef BUS_NOTIFY_UNBOUND_DRIVER | ||
110 | #define BUS_NOTIFY_UNBOUND_DRIVER 0x0005 | ||
111 | #endif | ||
112 | |||
108 | /* | 113 | /* |
109 | * The access to some variables in this macro is racy. We can't use atomic_t | 114 | * The access to some variables in this macro is racy. We can't use atomic_t |
110 | * here because all these variables are exported to debugfs. Some of them even | 115 | * here because all these variables are exported to debugfs. Some of them even |
@@ -458,9 +463,60 @@ out_err: | |||
458 | return -ENOMEM; | 463 | return -ENOMEM; |
459 | } | 464 | } |
460 | 465 | ||
466 | static int device_dma_allocations(struct device *dev) | ||
467 | { | ||
468 | struct dma_debug_entry *entry; | ||
469 | unsigned long flags; | ||
470 | int count = 0, i; | ||
471 | |||
472 | for (i = 0; i < HASH_SIZE; ++i) { | ||
473 | spin_lock_irqsave(&dma_entry_hash[i].lock, flags); | ||
474 | list_for_each_entry(entry, &dma_entry_hash[i].list, list) { | ||
475 | if (entry->dev == dev) | ||
476 | count += 1; | ||
477 | } | ||
478 | spin_unlock_irqrestore(&dma_entry_hash[i].lock, flags); | ||
479 | } | ||
480 | |||
481 | return count; | ||
482 | } | ||
483 | |||
484 | static int dma_debug_device_change(struct notifier_block *nb, | ||
485 | unsigned long action, void *data) | ||
486 | { | ||
487 | struct device *dev = data; | ||
488 | int count; | ||
489 | |||
490 | |||
491 | switch (action) { | ||
492 | case BUS_NOTIFY_UNBOUND_DRIVER: | ||
493 | count = device_dma_allocations(dev); | ||
494 | if (count == 0) | ||
495 | break; | ||
496 | err_printk(dev, NULL, "DMA-API: device driver has pending " | ||
497 | "DMA allocations while released from device " | ||
498 | "[count=%d]\n", count); | ||
499 | break; | ||
500 | default: | ||
501 | break; | ||
502 | } | ||
503 | |||
504 | return 0; | ||
505 | } | ||
506 | |||
461 | void dma_debug_add_bus(struct bus_type *bus) | 507 | void dma_debug_add_bus(struct bus_type *bus) |
462 | { | 508 | { |
463 | /* FIXME: register notifier */ | 509 | struct notifier_block *nb; |
510 | |||
511 | nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); | ||
512 | if (nb == NULL) { | ||
513 | printk(KERN_ERR "dma_debug_add_bus: out of memory\n"); | ||
514 | return; | ||
515 | } | ||
516 | |||
517 | nb->notifier_call = dma_debug_device_change; | ||
518 | |||
519 | bus_register_notifier(bus, nb); | ||
464 | } | 520 | } |
465 | 521 | ||
466 | /* | 522 | /* |