diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-11 10:09:45 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-11 10:09:45 -0700 |
commit | 7cc4e87f912bbefa440a51856b8d076e5d1f554a (patch) | |
tree | 1b8df8683f3de37d2e8211ffa8d151f60d59af62 /arch/arm/common/dmabounce.c | |
parent | 5ba2f67afb02c5302b2898949ed6fc3b3d37dcf1 (diff) | |
parent | 69fc7eed5f56bce15b239e5110de2575a6970df4 (diff) |
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (236 commits)
[ARM] 5300/1: fixup spitz reset during boot
[ARM] 5295/1: make ZONE_DMA optional
[ARM] 5239/1: Palm Zire 72 power management support
[ARM] 5298/1: Drop desc_handle_irq()
[ARM] 5297/1: [KS8695] Fix two compile-time warnings
[ARM] 5296/1: [KS8695] Replace macro's with trailing underscores.
[ARM] pxa: allow multi-machine PCMCIA builds
[ARM] pxa: add preliminary CPUFREQ support for PXA3xx
[ARM] pxa: add missing ACCR bit definitions to pxa3xx-regs.h
[ARM] pxa: rename cpu-pxa.c to cpufreq-pxa2xx.c
[ARM] pxa/zylonite: add support for USB OHCI
[ARM] ohci-pxa27x: use ioremap() and offset for register access
[ARM] ohci-pxa27x: introduce pxa27x_clear_otgph()
[ARM] ohci-pxa27x: use platform_get_{irq,resource} for the resource
[ARM] ohci-pxa27x: move OHCI controller specific registers into the driver
[ARM] ohci-pxa27x: introduce flags to avoid direct access to OHCI registers
[ARM] pxa: move I2S register and bit definitions into pxa2xx-i2s.c
[ARM] pxa: simplify DMA register definitions
[ARM] pxa: make additional DCSR bits valid for PXA3xx
[ARM] pxa: move i2c register and bit definitions into i2c-pxa.c
...
Fixed up conflicts in
arch/arm/mach-versatile/core.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-i2s.c
manually.
Diffstat (limited to 'arch/arm/common/dmabounce.c')
-rw-r--r-- | arch/arm/common/dmabounce.c | 287 |
1 files changed, 84 insertions, 203 deletions
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index aecc6c3f908..f030f0775be 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -154,9 +154,7 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr, #endif write_lock_irqsave(&device_info->lock, flags); - list_add(&buf->node, &device_info->safe_buffers); - write_unlock_irqrestore(&device_info->lock, flags); return buf; @@ -205,8 +203,22 @@ free_safe_buffer(struct dmabounce_device_info *device_info, struct safe_buffer * /* ************************************************** */ -static inline dma_addr_t -map_single(struct device *dev, void *ptr, size_t size, +static struct safe_buffer *find_safe_buffer_dev(struct device *dev, + dma_addr_t dma_addr, const char *where) +{ + if (!dev || !dev->archdata.dmabounce) + return NULL; + if (dma_mapping_error(dev, dma_addr)) { + if (dev) + dev_err(dev, "Trying to %s invalid mapping\n", where); + else + pr_err("unknown device: Trying to %s invalid mapping\n", where); + return NULL; + } + return find_safe_buffer(dev->archdata.dmabounce, dma_addr); +} + +static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction dir) { struct dmabounce_device_info *device_info = dev->archdata.dmabounce; @@ -270,33 +282,21 @@ map_single(struct device *dev, void *ptr, size_t size, return dma_addr; } -static inline void -unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction dir) +static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, + size_t size, enum dma_data_direction dir) { - struct dmabounce_device_info *device_info = dev->archdata.dmabounce; - struct safe_buffer *buf = NULL; - - /* - * Trying to unmap an invalid mapping - */ - if (dma_mapping_error(dev, dma_addr)) { - dev_err(dev, "Trying to unmap invalid mapping\n"); - return; - } - - if (device_info) - buf = find_safe_buffer(device_info, dma_addr); + struct safe_buffer *buf = find_safe_buffer_dev(dev, dma_addr, "unmap"); if (buf) { BUG_ON(buf->size != size); + BUG_ON(buf->direction != dir); dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", __func__, buf->ptr, virt_to_dma(dev, buf->ptr), buf->safe, buf->safe_dma_addr); - DO_STATS ( device_info->bounce_count++ ); + DO_STATS(dev->archdata.dmabounce->bounce_count++); if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { void *ptr = buf->ptr; @@ -317,74 +317,7 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, dmac_clean_range(ptr, ptr + size); outer_clean_range(__pa(ptr), __pa(ptr) + size); } - free_safe_buffer(device_info, buf); - } -} - -static int sync_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction dir) -{ - struct dmabounce_device_info *device_info = dev->archdata.dmabounce; - struct safe_buffer *buf = NULL; - - if (device_info) - buf = find_safe_buffer(device_info, dma_addr); - - if (buf) { - /* - * Both of these checks from original code need to be - * commented out b/c some drivers rely on the following: - * - * 1) Drivers may map a large chunk of memory into DMA space - * but only sync a small portion of it. Good example is - * allocating a large buffer, mapping it, and then - * breaking it up into small descriptors. No point - * in syncing the whole buffer if you only have to - * touch one descriptor. - * - * 2) Buffers that are mapped as DMA_BIDIRECTIONAL are - * usually only synced in one dir at a time. - * - * See drivers/net/eepro100.c for examples of both cases. - * - * -ds - * - * BUG_ON(buf->size != size); - * BUG_ON(buf->direction != dir); - */ - - dev_dbg(dev, - "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", - __func__, buf->ptr, virt_to_dma(dev, buf->ptr), - buf->safe, buf->safe_dma_addr); - - DO_STATS ( device_info->bounce_count++ ); - - switch (dir) { - case DMA_FROM_DEVICE: - dev_dbg(dev, - "%s: copy back safe %p to unsafe %p size %d\n", - __func__, buf->safe, buf->ptr, size); - memcpy(buf->ptr, buf->safe, size); - break; - case DMA_TO_DEVICE: - dev_dbg(dev, - "%s: copy out unsafe %p to safe %p, size %d\n", - __func__,buf->ptr, buf->safe, size); - memcpy(buf->safe, buf->ptr, size); - break; - case DMA_BIDIRECTIONAL: - BUG(); /* is this allowed? what does it mean? */ - default: - BUG(); - } - /* - * No need to sync the safe buffer - it was allocated - * via the coherent allocators. - */ - return 0; - } else { - return 1; + free_safe_buffer(dev->archdata.dmabounce, buf); } } @@ -396,21 +329,29 @@ static int sync_single(struct device *dev, dma_addr_t dma_addr, size_t size, * substitute the safe buffer for the unsafe one. * (basically move the buffer from an unsafe area to a safe one) */ -dma_addr_t -dma_map_single(struct device *dev, void *ptr, size_t size, +dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction dir) { - dma_addr_t dma_addr; - dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", __func__, ptr, size, dir); - BUG_ON(dir == DMA_NONE); + BUG_ON(!valid_dma_direction(dir)); - dma_addr = map_single(dev, ptr, size, dir); + return map_single(dev, ptr, size, dir); +} +EXPORT_SYMBOL(dma_map_single); - return dma_addr; +dma_addr_t dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction dir) +{ + dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n", + __func__, page, offset, size, dir); + + BUG_ON(!valid_dma_direction(dir)); + + return map_single(dev, page_address(page) + offset, size, dir); } +EXPORT_SYMBOL(dma_map_page); /* * see if a mapped address was really a "safe" buffer and if so, copy @@ -419,126 +360,76 @@ dma_map_single(struct device *dev, void *ptr, size_t size, * should be) */ -void -dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction dir) +void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction dir) { dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", __func__, (void *) dma_addr, size, dir); - BUG_ON(dir == DMA_NONE); - unmap_single(dev, dma_addr, size, dir); } +EXPORT_SYMBOL(dma_unmap_single); -int -dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction dir) +int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr, + unsigned long off, size_t sz, enum dma_data_direction dir) { - int i; - - dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", - __func__, sg, nents, dir); - - BUG_ON(dir == DMA_NONE); - - for (i = 0; i < nents; i++, sg++) { - struct page *page = sg_page(sg); - unsigned int offset = sg->offset; - unsigned int length = sg->length; - void *ptr = page_address(page) + offset; + struct safe_buffer *buf; - sg->dma_address = - map_single(dev, ptr, length, dir); - } + dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n", + __func__, addr, off, sz, dir); - return nents; -} - -void -dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction dir) -{ - int i; + buf = find_safe_buffer_dev(dev, addr, __func__); + if (!buf) + return 1; - dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", - __func__, sg, nents, dir); + BUG_ON(buf->direction != dir); - BUG_ON(dir == DMA_NONE); + dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", + __func__, buf->ptr, virt_to_dma(dev, buf->ptr), + buf->safe, buf->safe_dma_addr); - for (i = 0; i < nents; i++, sg++) { - dma_addr_t dma_addr = sg->dma_address; - unsigned int length = sg->length; + DO_STATS(dev->archdata.dmabounce->bounce_count++); - unmap_single(dev, dma_addr, length, dir); + if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { + dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n", + __func__, buf->safe + off, buf->ptr + off, sz); + memcpy(buf->ptr + off, buf->safe + off, sz); } + return 0; } +EXPORT_SYMBOL(dmabounce_sync_for_cpu); -void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_addr, - unsigned long offset, size_t size, - enum dma_data_direction dir) -{ - dev_dbg(dev, "%s(dma=%#x,off=%#lx,size=%zx,dir=%x)\n", - __func__, dma_addr, offset, size, dir); - - if (sync_single(dev, dma_addr, offset + size, dir)) - dma_cache_maint(dma_to_virt(dev, dma_addr) + offset, size, dir); -} -EXPORT_SYMBOL(dma_sync_single_range_for_cpu); - -void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_addr, - unsigned long offset, size_t size, - enum dma_data_direction dir) -{ - dev_dbg(dev, "%s(dma=%#x,off=%#lx,size=%zx,dir=%x)\n", - __func__, dma_addr, offset, size, dir); - - if (sync_single(dev, dma_addr, offset + size, dir)) - dma_cache_maint(dma_to_virt(dev, dma_addr) + offset, size, dir); -} -EXPORT_SYMBOL(dma_sync_single_range_for_device); - -void -dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction dir) +int dmabounce_sync_for_device(struct device *dev, dma_addr_t addr, + unsigned long off, size_t sz, enum dma_data_direction dir) { - int i; - - dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", - __func__, sg, nents, dir); - - BUG_ON(dir == DMA_NONE); + struct safe_buffer *buf; - for (i = 0; i < nents; i++, sg++) { - dma_addr_t dma_addr = sg->dma_address; - unsigned int length = sg->length; + dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n", + __func__, addr, off, sz, dir); - sync_single(dev, dma_addr, length, dir); - } -} - -void -dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction dir) -{ - int i; + buf = find_safe_buffer_dev(dev, addr, __func__); + if (!buf) + return 1; - dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", - __func__, sg, nents, dir); + BUG_ON(buf->direction != dir); - BUG_ON(dir == DMA_NONE); + dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", + __func__, buf->ptr, virt_to_dma(dev, buf->ptr), + buf->safe, buf->safe_dma_addr); - for (i = 0; i < nents; i++, sg++) { - dma_addr_t dma_addr = sg->dma_address; - unsigned int length = sg->length; + DO_STATS(dev->archdata.dmabounce->bounce_count++); - sync_single(dev, dma_addr, length, dir); + if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) { + dev_dbg(dev, "%s: copy out unsafe %p to safe %p, size %d\n", + __func__,buf->ptr + off, buf->safe + off, sz); + memcpy(buf->safe + off, buf->ptr + off, sz); } + return 0; } +EXPORT_SYMBOL(dmabounce_sync_for_device); -static int -dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, const char *name, - unsigned long size) +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); @@ -549,9 +440,8 @@ dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, const char return pool->pool ? 0 : -ENOMEM; } -int -dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, - unsigned long large_buffer_size) +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; @@ -607,9 +497,9 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, kfree(device_info); return ret; } +EXPORT_SYMBOL(dmabounce_register_dev); -void -dmabounce_unregister_dev(struct device *dev) +void dmabounce_unregister_dev(struct device *dev) { struct dmabounce_device_info *device_info = dev->archdata.dmabounce; @@ -642,15 +532,6 @@ dmabounce_unregister_dev(struct device *dev) dev_info(dev, "dmabounce: device unregistered\n"); } - - -EXPORT_SYMBOL(dma_map_single); -EXPORT_SYMBOL(dma_unmap_single); -EXPORT_SYMBOL(dma_map_sg); -EXPORT_SYMBOL(dma_unmap_sg); -EXPORT_SYMBOL(dma_sync_sg_for_cpu); -EXPORT_SYMBOL(dma_sync_sg_for_device); -EXPORT_SYMBOL(dmabounce_register_dev); EXPORT_SYMBOL(dmabounce_unregister_dev); MODULE_AUTHOR("Christopher Hoover <ch@hpl.hp.com>, Deepak Saxena <dsaxena@plexity.net>"); |