From 178783622ce0fd629fad21b33b8f8f56b64c5e45 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 3 Jul 2011 23:24:21 +0100 Subject: ARM: dmabounce: fix map_single() error return value When map_single() is unable to obtain a safe buffer, we must return the dma_addr_t error value, which is ~0 rather than 0. Signed-off-by: Russell King --- arch/arm/common/dmabounce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/common/dmabounce.c') diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index e5681636626f..841df7d21c2f 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -255,7 +255,7 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, if (buf == 0) { dev_err(dev, "%s: unable to map unsafe buffer %p!\n", __func__, ptr); - return 0; + return ~0; } dev_dbg(dev, -- cgit v1.2.3 From 8021a4a048a85906302bd0236f3d125473be65b1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 3 Jul 2011 16:13:58 +0100 Subject: ARM: dma-mapping: define dma_(un)?map_single in terms of dma_(un)?map_page Use dma_map_page()/dma_unmap_page() internals to handle dma_map_single() and dma_unmap_single(). Signed-off-by: Russell King --- arch/arm/common/dmabounce.c | 28 ---------------------------- 1 file changed, 28 deletions(-) (limited to 'arch/arm/common/dmabounce.c') diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 841df7d21c2f..8a0588b007e4 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -328,34 +328,6 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, * 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, - enum dma_data_direction dir) -{ - dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", - __func__, ptr, size, dir); - - BUG_ON(!valid_dma_direction(dir)); - - return map_single(dev, ptr, size, dir); -} -EXPORT_SYMBOL(__dma_map_single); - -/* - * see if a mapped address was really a "safe" buffer and if so, copy - * the data from the safe buffer back to the unsafe buffer and free up - * the safe buffer. (basically return things back to the way they - * should be) - */ -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); - - unmap_single(dev, dma_addr, size, dir); -} -EXPORT_SYMBOL(__dma_unmap_single); - dma_addr_t __dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { -- cgit v1.2.3 From 71695dd8b9eacfcda1b548a5b1780d34213ad654 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 3 Jul 2011 19:46:39 +0100 Subject: ARM: dmabounce: avoid needless valid_dma_direction() check This check is done at the DMA API level, so there's no point repeating it here. Signed-off-by: Russell King --- arch/arm/common/dmabounce.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/arm/common/dmabounce.c') diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 8a0588b007e4..3e0fa1548582 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -334,8 +334,6 @@ dma_addr_t __dma_map_page(struct device *dev, struct page *page, dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n", __func__, page, offset, size, dir); - BUG_ON(!valid_dma_direction(dir)); - if (PageHighMem(page)) { dev_err(dev, "DMA buffer bouncing of HIGHMEM pages " "is not supported\n"); -- cgit v1.2.3 From 23bc9873ba60ee661d8e9f3a6b22fc3bcc4b7015 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 3 Jul 2011 22:28:32 +0100 Subject: ARM: dmabounce: separate out decision to bounce Move the decision to perform DMA bouncing out of map_single() into its own stand-alone function. Signed-off-by: Russell King --- arch/arm/common/dmabounce.c | 46 +++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) (limited to 'arch/arm/common/dmabounce.c') diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 3e0fa1548582..643e1d660677 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -219,36 +219,46 @@ static struct safe_buffer *find_safe_buffer_dev(struct device *dev, 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) +static int needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) { - struct dmabounce_device_info *device_info = dev->archdata.dmabounce; - dma_addr_t dma_addr; - int needs_bounce = 0; - - if (device_info) - DO_STATS ( device_info->map_op_count++ ); - - dma_addr = virt_to_dma(dev, ptr); + if (!dev || !dev->archdata.dmabounce) + return 0; if (dev->dma_mask) { - unsigned long mask = *dev->dma_mask; - unsigned long limit; + unsigned long limit, mask = *dev->dma_mask; limit = (mask + 1) & ~mask; if (limit && size > limit) { dev_err(dev, "DMA mapping too big (requested %#x " "mask %#Lx)\n", size, *dev->dma_mask); - return ~0; + return -E2BIG; } - /* - * Figure out if we need to bounce from the DMA mask. - */ - needs_bounce = (dma_addr | (dma_addr + size - 1)) & ~mask; + /* Figure out if we need to bounce from the DMA mask. */ + if ((dma_addr | (dma_addr + size - 1)) & ~mask) + return 1; } - if (device_info && (needs_bounce || dma_needs_bounce(dev, dma_addr, size))) { + return dma_needs_bounce(dev, dma_addr, size) ? 1 : 0; +} + +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; + dma_addr_t dma_addr; + int ret; + + if (device_info) + DO_STATS ( device_info->map_op_count++ ); + + dma_addr = virt_to_dma(dev, ptr); + + ret = needs_bounce(dev, dma_addr, size); + if (ret < 0) + return ~0; + + if (ret > 0) { struct safe_buffer *buf; buf = alloc_safe_buffer(device_info, ptr, size, dir); -- cgit v1.2.3 From dd3641fc3cf6d10b7cf4e266c2f651517779e727 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 3 Jul 2011 22:39:43 +0100 Subject: ARM: dmabounce: move decision for bouncing into __dma_map_page() Move the decision whether to bounce into __dma_map_page(), before the check for high pages. This avoids triggering the high page check for devices which aren't using dmabounce. Fix the unmap path to cope too. Signed-off-by: Russell King --- arch/arm/common/dmabounce.c | 124 +++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 66 deletions(-) (limited to 'arch/arm/common/dmabounce.c') diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 643e1d660677..6ae292cc43bf 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -246,88 +246,58 @@ 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; - dma_addr_t dma_addr; - int ret; + struct safe_buffer *buf; if (device_info) DO_STATS ( device_info->map_op_count++ ); - dma_addr = virt_to_dma(dev, ptr); - - ret = needs_bounce(dev, dma_addr, size); - if (ret < 0) + buf = alloc_safe_buffer(device_info, ptr, size, dir); + if (buf == 0) { + dev_err(dev, "%s: unable to map unsafe buffer %p!\n", + __func__, ptr); return ~0; + } - if (ret > 0) { - struct safe_buffer *buf; - - buf = alloc_safe_buffer(device_info, ptr, size, dir); - if (buf == 0) { - dev_err(dev, "%s: unable to map unsafe buffer %p!\n", - __func__, ptr); - return ~0; - } - - 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); - - if ((dir == DMA_TO_DEVICE) || - (dir == DMA_BIDIRECTIONAL)) { - dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", - __func__, ptr, buf->safe, size); - memcpy(buf->safe, ptr, size); - } - ptr = buf->safe; + 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); - dma_addr = buf->safe_dma_addr; - } else { - /* - * We don't need to sync the DMA buffer since - * it was allocated via the coherent allocators. - */ - __dma_single_cpu_to_dev(ptr, size, dir); + if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) { + dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", + __func__, ptr, buf->safe, size); + memcpy(buf->safe, ptr, size); } - return dma_addr; + return buf->safe_dma_addr; } -static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, +static inline void unmap_single(struct device *dev, struct safe_buffer *buf, size_t size, enum dma_data_direction dir) { - struct safe_buffer *buf = find_safe_buffer_dev(dev, dma_addr, "unmap"); - - if (buf) { - BUG_ON(buf->size != size); - BUG_ON(buf->direction != dir); + 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); + 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(dev->archdata.dmabounce->bounce_count++); + DO_STATS(dev->archdata.dmabounce->bounce_count++); - if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { - void *ptr = buf->ptr; + if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { + void *ptr = buf->ptr; - dev_dbg(dev, - "%s: copy back safe %p to unsafe %p size %d\n", - __func__, buf->safe, ptr, size); - memcpy(ptr, buf->safe, size); + dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n", + __func__, buf->safe, ptr, size); + memcpy(ptr, buf->safe, size); - /* - * Since we may have written to a page cache page, - * we need to ensure that the data will be coherent - * with user mappings. - */ - __cpuc_flush_dcache_area(ptr, size); - } - free_safe_buffer(dev->archdata.dmabounce, buf); - } else { - __dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir); + /* + * Since we may have written to a page cache page, + * we need to ensure that the data will be coherent + * with user mappings. + */ + __cpuc_flush_dcache_area(ptr, size); } + free_safe_buffer(dev->archdata.dmabounce, buf); } /* ************************************************** */ @@ -341,12 +311,25 @@ static inline void unmap_single(struct device *dev, dma_addr_t 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) { + dma_addr_t dma_addr; + int ret; + dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n", __func__, page, offset, size, dir); + dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset; + + ret = needs_bounce(dev, dma_addr, size); + if (ret < 0) + return ~0; + + if (ret == 0) { + __dma_page_cpu_to_dev(page, offset, size, dir); + return dma_addr; + } + if (PageHighMem(page)) { - dev_err(dev, "DMA buffer bouncing of HIGHMEM pages " - "is not supported\n"); + dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n"); return ~0; } @@ -363,10 +346,19 @@ EXPORT_SYMBOL(__dma_map_page); void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { + struct safe_buffer *buf; + dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", __func__, (void *) dma_addr, size, dir); - unmap_single(dev, dma_addr, size, dir); + buf = find_safe_buffer_dev(dev, dma_addr, __func__); + if (!buf) { + __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)), + dma_addr & ~PAGE_MASK, size, dir); + return; + } + + unmap_single(dev, buf, size, dir); } EXPORT_SYMBOL(__dma_unmap_page); -- cgit v1.2.3 From e2f521e247576c897e1bf0ada801e87c7e2db89f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 3 Jul 2011 23:53:13 +0100 Subject: ARM: dmabounce: remove useless pr_err We already check that dev != NULL, so this won't be reached. Signed-off-by: Russell King --- arch/arm/common/dmabounce.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'arch/arm/common/dmabounce.c') diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 6ae292cc43bf..0077c1b7d7ff 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -210,10 +210,7 @@ static struct safe_buffer *find_safe_buffer_dev(struct device *dev, 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); + dev_err(dev, "Trying to %s invalid mapping\n", where); return NULL; } return find_safe_buffer(dev->archdata.dmabounce, dma_addr); -- cgit v1.2.3 From dfa322fceb15227c07670c415e835d2dfa8a4307 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 3 Jul 2011 23:54:34 +0100 Subject: ARM: dmabounce: check pointer against NULL not 0 Pointers should be checked against NULL rather than 0, otherwise we get sparse warnings. Signed-off-by: Russell King --- arch/arm/common/dmabounce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/common/dmabounce.c') diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 0077c1b7d7ff..b4a8759e0fa4 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -249,7 +249,7 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, DO_STATS ( device_info->map_op_count++ ); buf = alloc_safe_buffer(device_info, ptr, size, dir); - if (buf == 0) { + if (buf == NULL) { dev_err(dev, "%s: unable to map unsafe buffer %p!\n", __func__, ptr); return ~0; -- cgit v1.2.3 From c289b2e0ccff1142908e20398930dc2e14697e74 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 3 Jul 2011 23:56:17 +0100 Subject: ARM: dmabounce: correct unmap_single dev_dbg DMA addresses should not be casted to void * for printing. Fix that to be consistent with the rest of the file. Signed-off-by: Russell King --- arch/arm/common/dmabounce.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/common/dmabounce.c') diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index b4a8759e0fa4..4f13505ac936 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -345,8 +345,8 @@ void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, { struct safe_buffer *buf; - dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", - __func__, (void *) dma_addr, size, dir); + dev_dbg(dev, "%s(dma=%#x,size=%d,dir=%x)\n", + __func__, dma_addr, size, dir); buf = find_safe_buffer_dev(dev, dma_addr, __func__); if (!buf) { -- cgit v1.2.3 From 0703ed2a6b260cd743adf49a8281eb064d728832 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 4 Jul 2011 08:32:21 +0100 Subject: ARM: dmabounce: get rid of dma_needs_bounce global function Pass the device type specific needs_bounce function in at dmabounce register time, avoiding the need for a platform specific global function to do this. Signed-off-by: Russell King --- arch/arm/common/dmabounce.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'arch/arm/common/dmabounce.c') diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 4f13505ac936..595ecd290ebf 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -79,6 +79,8 @@ struct dmabounce_device_info { struct dmabounce_pool large; rwlock_t lock; + + int (*needs_bounce)(struct device *, dma_addr_t, size_t); }; #ifdef STATS @@ -236,7 +238,7 @@ static int needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) return 1; } - return dma_needs_bounce(dev, dma_addr, size) ? 1 : 0; + return !!dev->archdata.dmabounce->needs_bounce(dev, dma_addr, size); } static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, @@ -430,7 +432,8 @@ static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, } int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, - unsigned long large_buffer_size) + unsigned long large_buffer_size, + int (*needs_bounce_fn)(struct device *, dma_addr_t, size_t)) { struct dmabounce_device_info *device_info; int ret; @@ -466,6 +469,7 @@ int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, device_info->dev = dev; INIT_LIST_HEAD(&device_info->safe_buffers); rwlock_init(&device_info->lock); + device_info->needs_bounce = needs_bounce_fn; #ifdef STATS device_info->total_allocs = 0; -- cgit v1.2.3