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 <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
23bc9873ba
commit
dd3641fc3c
|
@ -246,21 +246,11 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size,
|
||||||
enum dma_data_direction dir)
|
enum dma_data_direction dir)
|
||||||
{
|
{
|
||||||
struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
|
struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
|
||||||
dma_addr_t dma_addr;
|
struct safe_buffer *buf;
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (device_info)
|
if (device_info)
|
||||||
DO_STATS ( device_info->map_op_count++ );
|
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);
|
buf = alloc_safe_buffer(device_info, ptr, size, dir);
|
||||||
if (buf == 0) {
|
if (buf == 0) {
|
||||||
dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
|
dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
|
||||||
|
@ -268,42 +258,26 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size,
|
||||||
return ~0;
|
return ~0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(dev,
|
dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
|
||||||
"%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
|
|
||||||
__func__, buf->ptr, virt_to_dma(dev, buf->ptr),
|
__func__, buf->ptr, virt_to_dma(dev, buf->ptr),
|
||||||
buf->safe, buf->safe_dma_addr);
|
buf->safe, buf->safe_dma_addr);
|
||||||
|
|
||||||
if ((dir == DMA_TO_DEVICE) ||
|
if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) {
|
||||||
(dir == DMA_BIDIRECTIONAL)) {
|
|
||||||
dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n",
|
dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n",
|
||||||
__func__, ptr, buf->safe, size);
|
__func__, ptr, buf->safe, size);
|
||||||
memcpy(buf->safe, ptr, size);
|
memcpy(buf->safe, ptr, size);
|
||||||
}
|
}
|
||||||
ptr = buf->safe;
|
|
||||||
|
|
||||||
dma_addr = buf->safe_dma_addr;
|
return 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 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)
|
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->size != size);
|
||||||
BUG_ON(buf->direction != dir);
|
BUG_ON(buf->direction != dir);
|
||||||
|
|
||||||
dev_dbg(dev,
|
dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
|
||||||
"%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
|
|
||||||
__func__, buf->ptr, virt_to_dma(dev, buf->ptr),
|
__func__, buf->ptr, virt_to_dma(dev, buf->ptr),
|
||||||
buf->safe, buf->safe_dma_addr);
|
buf->safe, buf->safe_dma_addr);
|
||||||
|
|
||||||
|
@ -312,8 +286,7 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr,
|
||||||
if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) {
|
if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) {
|
||||||
void *ptr = buf->ptr;
|
void *ptr = buf->ptr;
|
||||||
|
|
||||||
dev_dbg(dev,
|
dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n",
|
||||||
"%s: copy back safe %p to unsafe %p size %d\n",
|
|
||||||
__func__, buf->safe, ptr, size);
|
__func__, buf->safe, ptr, size);
|
||||||
memcpy(ptr, buf->safe, size);
|
memcpy(ptr, buf->safe, size);
|
||||||
|
|
||||||
|
@ -325,9 +298,6 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr,
|
||||||
__cpuc_flush_dcache_area(ptr, size);
|
__cpuc_flush_dcache_area(ptr, size);
|
||||||
}
|
}
|
||||||
free_safe_buffer(dev->archdata.dmabounce, buf);
|
free_safe_buffer(dev->archdata.dmabounce, buf);
|
||||||
} else {
|
|
||||||
__dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************** */
|
/* ************************************************** */
|
||||||
|
@ -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,
|
dma_addr_t __dma_map_page(struct device *dev, struct page *page,
|
||||||
unsigned long offset, size_t size, enum dma_data_direction dir)
|
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",
|
dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n",
|
||||||
__func__, page, offset, size, dir);
|
__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)) {
|
if (PageHighMem(page)) {
|
||||||
dev_err(dev, "DMA buffer bouncing of HIGHMEM pages "
|
dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n");
|
||||||
"is not supported\n");
|
|
||||||
return ~0;
|
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,
|
void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
|
||||||
enum dma_data_direction dir)
|
enum dma_data_direction dir)
|
||||||
{
|
{
|
||||||
|
struct safe_buffer *buf;
|
||||||
|
|
||||||
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
|
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
|
||||||
__func__, (void *) dma_addr, size, dir);
|
__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);
|
EXPORT_SYMBOL(__dma_unmap_page);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue