Loading arch/arm/common/dmabounce.c +86 −79 Original line number Diff line number Diff line Loading @@ -33,8 +33,8 @@ #include <asm/cacheflush.h> #undef DEBUG #undef STATS #ifdef STATS #define DO_STATS(X) do { X ; } while (0) #else Loading @@ -52,26 +52,31 @@ struct safe_buffer { int direction; /* safe buffer info */ struct dma_pool *pool; struct dmabounce_pool *pool; void *safe; dma_addr_t safe_dma_addr; }; struct dmabounce_pool { unsigned long size; struct dma_pool *pool; #ifdef STATS unsigned long allocs; #endif }; struct dmabounce_device_info { struct list_head node; struct device *dev; struct dma_pool *small_buffer_pool; struct dma_pool *large_buffer_pool; struct list_head safe_buffers; unsigned long small_buffer_size, large_buffer_size; #ifdef STATS unsigned long sbp_allocs; unsigned long lbp_allocs; unsigned long total_allocs; unsigned long map_op_count; unsigned long bounce_count; #endif struct dmabounce_pool small; struct dmabounce_pool large; }; static LIST_HEAD(dmabounce_devs); Loading @@ -82,9 +87,9 @@ static void print_alloc_stats(struct dmabounce_device_info *device_info) printk(KERN_INFO "%s: dmabounce: sbp: %lu, lbp: %lu, other: %lu, total: %lu\n", device_info->dev->bus_id, device_info->sbp_allocs, device_info->lbp_allocs, device_info->total_allocs - device_info->sbp_allocs - device_info->lbp_allocs, device_info->small.allocs, device_info->large.allocs, device_info->total_allocs - device_info->small.allocs - device_info->large.allocs, device_info->total_allocs); } #endif Loading @@ -109,15 +114,19 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr, size_t size, enum dma_data_direction dir) { struct safe_buffer *buf; struct dma_pool *pool; struct dmabounce_pool *pool; struct device *dev = device_info->dev; void *safe; dma_addr_t safe_dma_addr; dev_dbg(dev, "%s(ptr=%p, size=%d, dir=%d)\n", __func__, ptr, size, dir); DO_STATS ( device_info->total_allocs++ ); if (size <= device_info->small.size) { pool = &device_info->small; } else if (size <= device_info->large.size) { pool = &device_info->large; } else { pool = NULL; } buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC); if (buf == NULL) { Loading @@ -125,23 +134,21 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr, return NULL; } if (size <= device_info->small_buffer_size) { pool = device_info->small_buffer_pool; safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); DO_STATS ( device_info->sbp_allocs++ ); } else if (size <= device_info->large_buffer_size) { pool = device_info->large_buffer_pool; safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); buf->ptr = ptr; buf->size = size; buf->direction = dir; buf->pool = pool; DO_STATS ( device_info->lbp_allocs++ ); if (pool) { buf->safe = dma_pool_alloc(pool->pool, GFP_ATOMIC, &buf->safe_dma_addr); } else { pool = NULL; safe = dma_alloc_coherent(dev, size, &safe_dma_addr, GFP_ATOMIC); buf->safe = dma_alloc_coherent(dev, size, &buf->safe_dma_addr, GFP_ATOMIC); } if (safe == NULL) { dev_warn(device_info->dev, if (buf->safe == NULL) { dev_warn(dev, "%s: could not alloc dma memory (size=%d)\n", __func__, size); kfree(buf); Loading @@ -149,17 +156,13 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr, } #ifdef STATS if (pool) pool->allocs++; device_info->total_allocs++; if (device_info->total_allocs % 1000 == 0) print_alloc_stats(device_info); #endif buf->ptr = ptr; buf->size = size; buf->direction = dir; buf->pool = pool; buf->safe = safe; buf->safe_dma_addr = safe_dma_addr; list_add(&buf->node, &device_info->safe_buffers); return buf; Loading @@ -186,7 +189,7 @@ free_safe_buffer(struct dmabounce_device_info *device_info, struct safe_buffer * list_del(&buf->node); if (buf->pool) dma_pool_free(buf->pool, buf->safe, buf->safe_dma_addr); dma_pool_free(buf->pool->pool, buf->safe, buf->safe_dma_addr); else dma_free_coherent(device_info->dev, buf->size, buf->safe, buf->safe_dma_addr); Loading @@ -197,12 +200,10 @@ free_safe_buffer(struct dmabounce_device_info *device_info, struct safe_buffer * /* ************************************************** */ #ifdef STATS static void print_map_stats(struct dmabounce_device_info *device_info) { printk(KERN_INFO "%s: dmabounce: map_op_count=%lu, bounce_count=%lu\n", device_info->dev->bus_id, dev_info(device_info->dev, "dmabounce: map_op_count=%lu, bounce_count=%lu\n", device_info->map_op_count, device_info->bounce_count); } #endif Loading Loading @@ -258,13 +259,13 @@ map_single(struct device *dev, void *ptr, size_t size, __func__, ptr, buf->safe, size); memcpy(buf->safe, ptr, size); } consistent_sync(buf->safe, size, dir); ptr = buf->safe; dma_addr = buf->safe_dma_addr; } else { consistent_sync(ptr, size, dir); } consistent_sync(ptr, size, dir); return dma_addr; } Loading @@ -278,7 +279,7 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, /* * Trying to unmap an invalid mapping */ if (dma_addr == ~0) { if (dma_mapping_error(dma_addr)) { dev_err(dev, "Trying to unmap invalid mapping\n"); return; } Loading Loading @@ -570,11 +571,25 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, local_irq_restore(flags); } static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, const char *name, unsigned long size) { pool->size = size; DO_STATS(pool->allocs = 0); pool->pool = dma_pool_create(name, dev, size, 0 /* byte alignment */, 0 /* no page-crossing issues */); return pool->pool ? 0 : -ENOMEM; } int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, unsigned long large_buffer_size) { struct dmabounce_device_info *device_info; int ret; device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC); if (!device_info) { Loading @@ -584,45 +599,31 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, return -ENOMEM; } device_info->small_buffer_pool = dma_pool_create("small_dmabounce_pool", dev, small_buffer_size, 0 /* byte alignment */, 0 /* no page-crossing issues */); if (!device_info->small_buffer_pool) { printk(KERN_ERR "dmabounce: could not allocate small DMA pool for %s\n", dev->bus_id); kfree(device_info); return -ENOMEM; ret = dmabounce_init_pool(&device_info->small, dev, "small_dmabounce_pool", small_buffer_size); if (ret) { dev_err(dev, "dmabounce: could not allocate DMA pool for %ld byte objects\n", small_buffer_size); goto err_free; } if (large_buffer_size) { device_info->large_buffer_pool = dma_pool_create("large_dmabounce_pool", dev, large_buffer_size, 0 /* byte alignment */, 0 /* no page-crossing issues */); if (!device_info->large_buffer_pool) { printk(KERN_ERR "dmabounce: could not allocate large DMA pool for %s\n", dev->bus_id); dma_pool_destroy(device_info->small_buffer_pool); return -ENOMEM; ret = dmabounce_init_pool(&device_info->large, dev, "large_dmabounce_pool", large_buffer_size); if (ret) { dev_err(dev, "dmabounce: could not allocate DMA pool for %ld byte objects\n", large_buffer_size); goto err_destroy; } } device_info->dev = dev; device_info->small_buffer_size = small_buffer_size; device_info->large_buffer_size = large_buffer_size; INIT_LIST_HEAD(&device_info->safe_buffers); #ifdef STATS device_info->sbp_allocs = 0; device_info->lbp_allocs = 0; device_info->total_allocs = 0; device_info->map_op_count = 0; device_info->bounce_count = 0; Loading @@ -634,6 +635,12 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, dev->bus_id, dev->bus->name); return 0; err_destroy: dma_pool_destroy(device_info->small.pool); err_free: kfree(device_info); return ret; } void Loading @@ -655,10 +662,10 @@ dmabounce_unregister_dev(struct device *dev) BUG(); } if (device_info->small_buffer_pool) dma_pool_destroy(device_info->small_buffer_pool); if (device_info->large_buffer_pool) dma_pool_destroy(device_info->large_buffer_pool); if (device_info->small.pool) dma_pool_destroy(device_info->small.pool); if (device_info->large.pool) dma_pool_destroy(device_info->large.pool); #ifdef STATS print_alloc_stats(device_info); Loading Loading
arch/arm/common/dmabounce.c +86 −79 Original line number Diff line number Diff line Loading @@ -33,8 +33,8 @@ #include <asm/cacheflush.h> #undef DEBUG #undef STATS #ifdef STATS #define DO_STATS(X) do { X ; } while (0) #else Loading @@ -52,26 +52,31 @@ struct safe_buffer { int direction; /* safe buffer info */ struct dma_pool *pool; struct dmabounce_pool *pool; void *safe; dma_addr_t safe_dma_addr; }; struct dmabounce_pool { unsigned long size; struct dma_pool *pool; #ifdef STATS unsigned long allocs; #endif }; struct dmabounce_device_info { struct list_head node; struct device *dev; struct dma_pool *small_buffer_pool; struct dma_pool *large_buffer_pool; struct list_head safe_buffers; unsigned long small_buffer_size, large_buffer_size; #ifdef STATS unsigned long sbp_allocs; unsigned long lbp_allocs; unsigned long total_allocs; unsigned long map_op_count; unsigned long bounce_count; #endif struct dmabounce_pool small; struct dmabounce_pool large; }; static LIST_HEAD(dmabounce_devs); Loading @@ -82,9 +87,9 @@ static void print_alloc_stats(struct dmabounce_device_info *device_info) printk(KERN_INFO "%s: dmabounce: sbp: %lu, lbp: %lu, other: %lu, total: %lu\n", device_info->dev->bus_id, device_info->sbp_allocs, device_info->lbp_allocs, device_info->total_allocs - device_info->sbp_allocs - device_info->lbp_allocs, device_info->small.allocs, device_info->large.allocs, device_info->total_allocs - device_info->small.allocs - device_info->large.allocs, device_info->total_allocs); } #endif Loading @@ -109,15 +114,19 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr, size_t size, enum dma_data_direction dir) { struct safe_buffer *buf; struct dma_pool *pool; struct dmabounce_pool *pool; struct device *dev = device_info->dev; void *safe; dma_addr_t safe_dma_addr; dev_dbg(dev, "%s(ptr=%p, size=%d, dir=%d)\n", __func__, ptr, size, dir); DO_STATS ( device_info->total_allocs++ ); if (size <= device_info->small.size) { pool = &device_info->small; } else if (size <= device_info->large.size) { pool = &device_info->large; } else { pool = NULL; } buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC); if (buf == NULL) { Loading @@ -125,23 +134,21 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr, return NULL; } if (size <= device_info->small_buffer_size) { pool = device_info->small_buffer_pool; safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); DO_STATS ( device_info->sbp_allocs++ ); } else if (size <= device_info->large_buffer_size) { pool = device_info->large_buffer_pool; safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); buf->ptr = ptr; buf->size = size; buf->direction = dir; buf->pool = pool; DO_STATS ( device_info->lbp_allocs++ ); if (pool) { buf->safe = dma_pool_alloc(pool->pool, GFP_ATOMIC, &buf->safe_dma_addr); } else { pool = NULL; safe = dma_alloc_coherent(dev, size, &safe_dma_addr, GFP_ATOMIC); buf->safe = dma_alloc_coherent(dev, size, &buf->safe_dma_addr, GFP_ATOMIC); } if (safe == NULL) { dev_warn(device_info->dev, if (buf->safe == NULL) { dev_warn(dev, "%s: could not alloc dma memory (size=%d)\n", __func__, size); kfree(buf); Loading @@ -149,17 +156,13 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr, } #ifdef STATS if (pool) pool->allocs++; device_info->total_allocs++; if (device_info->total_allocs % 1000 == 0) print_alloc_stats(device_info); #endif buf->ptr = ptr; buf->size = size; buf->direction = dir; buf->pool = pool; buf->safe = safe; buf->safe_dma_addr = safe_dma_addr; list_add(&buf->node, &device_info->safe_buffers); return buf; Loading @@ -186,7 +189,7 @@ free_safe_buffer(struct dmabounce_device_info *device_info, struct safe_buffer * list_del(&buf->node); if (buf->pool) dma_pool_free(buf->pool, buf->safe, buf->safe_dma_addr); dma_pool_free(buf->pool->pool, buf->safe, buf->safe_dma_addr); else dma_free_coherent(device_info->dev, buf->size, buf->safe, buf->safe_dma_addr); Loading @@ -197,12 +200,10 @@ free_safe_buffer(struct dmabounce_device_info *device_info, struct safe_buffer * /* ************************************************** */ #ifdef STATS static void print_map_stats(struct dmabounce_device_info *device_info) { printk(KERN_INFO "%s: dmabounce: map_op_count=%lu, bounce_count=%lu\n", device_info->dev->bus_id, dev_info(device_info->dev, "dmabounce: map_op_count=%lu, bounce_count=%lu\n", device_info->map_op_count, device_info->bounce_count); } #endif Loading Loading @@ -258,13 +259,13 @@ map_single(struct device *dev, void *ptr, size_t size, __func__, ptr, buf->safe, size); memcpy(buf->safe, ptr, size); } consistent_sync(buf->safe, size, dir); ptr = buf->safe; dma_addr = buf->safe_dma_addr; } else { consistent_sync(ptr, size, dir); } consistent_sync(ptr, size, dir); return dma_addr; } Loading @@ -278,7 +279,7 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, /* * Trying to unmap an invalid mapping */ if (dma_addr == ~0) { if (dma_mapping_error(dma_addr)) { dev_err(dev, "Trying to unmap invalid mapping\n"); return; } Loading Loading @@ -570,11 +571,25 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, local_irq_restore(flags); } static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, const char *name, unsigned long size) { pool->size = size; DO_STATS(pool->allocs = 0); pool->pool = dma_pool_create(name, dev, size, 0 /* byte alignment */, 0 /* no page-crossing issues */); return pool->pool ? 0 : -ENOMEM; } int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, unsigned long large_buffer_size) { struct dmabounce_device_info *device_info; int ret; device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC); if (!device_info) { Loading @@ -584,45 +599,31 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, return -ENOMEM; } device_info->small_buffer_pool = dma_pool_create("small_dmabounce_pool", dev, small_buffer_size, 0 /* byte alignment */, 0 /* no page-crossing issues */); if (!device_info->small_buffer_pool) { printk(KERN_ERR "dmabounce: could not allocate small DMA pool for %s\n", dev->bus_id); kfree(device_info); return -ENOMEM; ret = dmabounce_init_pool(&device_info->small, dev, "small_dmabounce_pool", small_buffer_size); if (ret) { dev_err(dev, "dmabounce: could not allocate DMA pool for %ld byte objects\n", small_buffer_size); goto err_free; } if (large_buffer_size) { device_info->large_buffer_pool = dma_pool_create("large_dmabounce_pool", dev, large_buffer_size, 0 /* byte alignment */, 0 /* no page-crossing issues */); if (!device_info->large_buffer_pool) { printk(KERN_ERR "dmabounce: could not allocate large DMA pool for %s\n", dev->bus_id); dma_pool_destroy(device_info->small_buffer_pool); return -ENOMEM; ret = dmabounce_init_pool(&device_info->large, dev, "large_dmabounce_pool", large_buffer_size); if (ret) { dev_err(dev, "dmabounce: could not allocate DMA pool for %ld byte objects\n", large_buffer_size); goto err_destroy; } } device_info->dev = dev; device_info->small_buffer_size = small_buffer_size; device_info->large_buffer_size = large_buffer_size; INIT_LIST_HEAD(&device_info->safe_buffers); #ifdef STATS device_info->sbp_allocs = 0; device_info->lbp_allocs = 0; device_info->total_allocs = 0; device_info->map_op_count = 0; device_info->bounce_count = 0; Loading @@ -634,6 +635,12 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, dev->bus_id, dev->bus->name); return 0; err_destroy: dma_pool_destroy(device_info->small.pool); err_free: kfree(device_info); return ret; } void Loading @@ -655,10 +662,10 @@ dmabounce_unregister_dev(struct device *dev) BUG(); } if (device_info->small_buffer_pool) dma_pool_destroy(device_info->small_buffer_pool); if (device_info->large_buffer_pool) dma_pool_destroy(device_info->large_buffer_pool); if (device_info->small.pool) dma_pool_destroy(device_info->small.pool); if (device_info->large.pool) dma_pool_destroy(device_info->large.pool); #ifdef STATS print_alloc_stats(device_info); Loading