diff --git a/[refs] b/[refs] index 7da6bcb2eaf3..e96c6ccb4151 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 88f3907f6f447899544beadf491dccb32015dacb +refs/heads/master: 2e507d849f1834d3fe9aae71b7aabf4c2a3827b8 diff --git a/trunk/lib/dma-debug.c b/trunk/lib/dma-debug.c index 1abed176d35a..c01f64780caf 100644 --- a/trunk/lib/dma-debug.c +++ b/trunk/lib/dma-debug.c @@ -99,17 +99,21 @@ static struct dentry *show_num_errors_dent __read_mostly; static struct dentry *num_free_entries_dent __read_mostly; static struct dentry *min_free_entries_dent __read_mostly; +/* per-driver filter related state */ + +#define NAME_MAX_LEN 64 + +static char current_driver_name[NAME_MAX_LEN] __read_mostly; +static struct device_driver *current_driver __read_mostly; + +static DEFINE_RWLOCK(driver_name_lock); + static const char *type2name[4] = { "single", "page", "scather-gather", "coherent" }; static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE", "DMA_FROM_DEVICE", "DMA_NONE" }; -/* little merge helper - remove it after the merge window */ -#ifndef BUS_NOTIFY_UNBOUND_DRIVER -#define BUS_NOTIFY_UNBOUND_DRIVER 0x0005 -#endif - /* * The access to some variables in this macro is racy. We can't use atomic_t * here because all these variables are exported to debugfs. Some of them even @@ -133,9 +137,47 @@ static inline void dump_entry_trace(struct dma_debug_entry *entry) #endif } +static bool driver_filter(struct device *dev) +{ + /* driver filter off */ + if (likely(!current_driver_name[0])) + return true; + + /* driver filter on and initialized */ + if (current_driver && dev->driver == current_driver) + return true; + + /* driver filter on but not yet initialized */ + if (!current_driver && current_driver_name[0]) { + struct device_driver *drv = get_driver(dev->driver); + unsigned long flags; + bool ret = false; + + if (!drv) + return false; + + /* lock to protect against change of current_driver_name */ + read_lock_irqsave(&driver_name_lock, flags); + + if (drv->name && + strncmp(current_driver_name, drv->name, 63) == 0) { + current_driver = drv; + ret = true; + } + + read_unlock_irqrestore(&driver_name_lock, flags); + put_driver(drv); + + return ret; + } + + return false; +} + #define err_printk(dev, entry, format, arg...) do { \ error_count += 1; \ - if (show_all_errors || show_num_errors > 0) { \ + if (driver_filter(dev) && \ + (show_all_errors || show_num_errors > 0)) { \ WARN(1, "%s %s: " format, \ dev_driver_string(dev), \ dev_name(dev) , ## arg); \ @@ -463,60 +505,9 @@ static int dma_debug_fs_init(void) return -ENOMEM; } -static int device_dma_allocations(struct device *dev) -{ - struct dma_debug_entry *entry; - unsigned long flags; - int count = 0, i; - - for (i = 0; i < HASH_SIZE; ++i) { - spin_lock_irqsave(&dma_entry_hash[i].lock, flags); - list_for_each_entry(entry, &dma_entry_hash[i].list, list) { - if (entry->dev == dev) - count += 1; - } - spin_unlock_irqrestore(&dma_entry_hash[i].lock, flags); - } - - return count; -} - -static int dma_debug_device_change(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct device *dev = data; - int count; - - - switch (action) { - case BUS_NOTIFY_UNBOUND_DRIVER: - count = device_dma_allocations(dev); - if (count == 0) - break; - err_printk(dev, NULL, "DMA-API: device driver has pending " - "DMA allocations while released from device " - "[count=%d]\n", count); - break; - default: - break; - } - - return 0; -} - void dma_debug_add_bus(struct bus_type *bus) { - struct notifier_block *nb; - - nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); - if (nb == NULL) { - printk(KERN_ERR "dma_debug_add_bus: out of memory\n"); - return; - } - - nb->notifier_call = dma_debug_device_change; - - bus_register_notifier(bus, nb); + /* FIXME: register notifier */ } /* @@ -839,15 +830,15 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, entry->type = dma_debug_sg; entry->dev = dev; entry->paddr = sg_phys(s); - entry->size = sg_dma_len(s); - entry->dev_addr = sg_dma_address(s); + entry->size = s->length; + entry->dev_addr = s->dma_address; entry->direction = direction; entry->sg_call_ents = nents; entry->sg_mapped_ents = mapped_ents; if (!PageHighMem(sg_page(s))) { check_for_stack(dev, sg_virt(s)); - check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s)); + check_for_illegal_area(dev, sg_virt(s), s->length); } add_dma_entry(entry); @@ -855,32 +846,13 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, } EXPORT_SYMBOL(debug_dma_map_sg); -static int get_nr_mapped_entries(struct device *dev, struct scatterlist *s) -{ - struct dma_debug_entry *entry; - struct hash_bucket *bucket; - unsigned long flags; - int mapped_ents = 0; - struct dma_debug_entry ref; - - ref.dev = dev; - ref.dev_addr = sg_dma_address(s); - ref.size = sg_dma_len(s), - - bucket = get_hash_bucket(&ref, &flags); - entry = hash_bucket_find(bucket, &ref); - if (entry) - mapped_ents = entry->sg_mapped_ents; - put_hash_bucket(bucket, &flags); - - return mapped_ents; -} - void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, int nelems, int dir) { + struct dma_debug_entry *entry; struct scatterlist *s; int mapped_ents = 0, i; + unsigned long flags; if (unlikely(global_disable)) return; @@ -891,8 +863,8 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, .type = dma_debug_sg, .dev = dev, .paddr = sg_phys(s), - .dev_addr = sg_dma_address(s), - .size = sg_dma_len(s), + .dev_addr = s->dma_address, + .size = s->length, .direction = dir, .sg_call_ents = 0, }; @@ -900,9 +872,14 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, if (mapped_ents && i >= mapped_ents) break; - if (!i) { + if (mapped_ents == 0) { + struct hash_bucket *bucket; ref.sg_call_ents = nelems; - mapped_ents = get_nr_mapped_entries(dev, s); + bucket = get_hash_bucket(&ref, &flags); + entry = hash_bucket_find(bucket, &ref); + if (entry) + mapped_ents = entry->sg_mapped_ents; + put_hash_bucket(bucket, &flags); } check_unmap(&ref); @@ -1004,20 +981,14 @@ void debug_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, int direction) { struct scatterlist *s; - int mapped_ents = 0, i; + int i; if (unlikely(global_disable)) return; for_each_sg(sg, s, nelems, i) { - if (!i) - mapped_ents = get_nr_mapped_entries(dev, s); - - if (i >= mapped_ents) - break; - - check_sync(dev, sg_dma_address(s), sg_dma_len(s), 0, - direction, true); + check_sync(dev, s->dma_address, s->dma_length, 0, + direction, true); } } EXPORT_SYMBOL(debug_dma_sync_sg_for_cpu); @@ -1026,20 +997,14 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, int direction) { struct scatterlist *s; - int mapped_ents = 0, i; + int i; if (unlikely(global_disable)) return; for_each_sg(sg, s, nelems, i) { - if (!i) - mapped_ents = get_nr_mapped_entries(dev, s); - - if (i >= mapped_ents) - break; - - check_sync(dev, sg_dma_address(s), sg_dma_len(s), 0, - direction, false); + check_sync(dev, s->dma_address, s->dma_length, 0, + direction, false); } } EXPORT_SYMBOL(debug_dma_sync_sg_for_device);