Commit 5397fc64 authored by Tony Lindgren's avatar Tony Lindgren Committed by Russell King

[ARM PATCH] 1931/1: Allow device address translation in dma-mapping, version 3

Patch from Tony Lindgren

Allows translation of shared memory addresses for devices using 
dma-mapping. In some cases the device DMA address is different
from the ARM DMA address, for example with some USB OHCI 
controllers.

For more background information, please see the ARM Linux mailing
list thread "OHCI controller".
parent 3bf94ba3
...@@ -234,7 +234,7 @@ map_single(struct device *dev, void *ptr, size_t size, ...@@ -234,7 +234,7 @@ map_single(struct device *dev, void *ptr, size_t size,
} }
} }
dma_addr = virt_to_bus(ptr); dma_addr = virt_to_dma(dev, ptr);
if (device_info && dma_needs_bounce(dev, dma_addr, size)) { if (device_info && dma_needs_bounce(dev, dma_addr, size)) {
struct safe_buffer *buf; struct safe_buffer *buf;
...@@ -248,7 +248,7 @@ map_single(struct device *dev, void *ptr, size_t size, ...@@ -248,7 +248,7 @@ map_single(struct device *dev, void *ptr, size_t size,
dev_dbg(dev, dev_dbg(dev,
"%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", "%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
__func__, buf->ptr, (void *) virt_to_bus(buf->ptr), __func__, buf->ptr, (void *) virt_to_dma(dev, buf->ptr),
buf->safe, (void *) buf->safe_dma_addr); buf->safe, (void *) buf->safe_dma_addr);
if ((dir == DMA_TO_DEVICE) || if ((dir == DMA_TO_DEVICE) ||
...@@ -290,7 +290,7 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ...@@ -290,7 +290,7 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
dev_dbg(dev, dev_dbg(dev,
"%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", "%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
__func__, buf->ptr, (void *) virt_to_bus(buf->ptr), __func__, buf->ptr, (void *) virt_to_dma(dev, buf->ptr),
buf->safe, (void *) buf->safe_dma_addr); buf->safe, (void *) buf->safe_dma_addr);
...@@ -342,7 +342,7 @@ sync_single(struct device *dev, dma_addr_t dma_addr, size_t size, ...@@ -342,7 +342,7 @@ sync_single(struct device *dev, dma_addr_t dma_addr, size_t size,
dev_dbg(dev, dev_dbg(dev,
"%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", "%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
__func__, buf->ptr, (void *) virt_to_bus(buf->ptr), __func__, buf->ptr, (void *) virt_to_dma(dev, buf->ptr),
buf->safe, (void *) buf->safe_dma_addr); buf->safe, (void *) buf->safe_dma_addr);
DO_STATS ( device_info->bounce_count++ ); DO_STATS ( device_info->bounce_count++ );
...@@ -367,7 +367,7 @@ sync_single(struct device *dev, dma_addr_t dma_addr, size_t size, ...@@ -367,7 +367,7 @@ sync_single(struct device *dev, dma_addr_t dma_addr, size_t size,
} }
consistent_sync(buf->safe, size, dir); consistent_sync(buf->safe, size, dir);
} else { } else {
consistent_sync(bus_to_virt(dma_addr), size, dir); consistent_sync(dma_to_virt(dev, dma_addr), size, dir);
} }
} }
......
...@@ -194,7 +194,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp, ...@@ -194,7 +194,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp,
/* /*
* Set the "dma handle" * Set the "dma handle"
*/ */
*handle = page_to_bus(page); *handle = page_to_dma(dev, page);
do { do {
BUG_ON(!pte_none(*pte)); BUG_ON(!pte_none(*pte));
......
...@@ -57,12 +57,28 @@ ...@@ -57,12 +57,28 @@
/* /*
* OMAP-1510 bus address is translated into a Local Bus address if the * OMAP-1510 bus address is translated into a Local Bus address if the
* OMAP bus type is lbus. See dmadev_uses_omap_lbus(). * OMAP bus type is lbus. We do the address translation based on the
* device overriding the defaults used in the dma-mapping API.
*/ */
#ifdef CONFIG_ARCH_OMAP1510 #ifdef CONFIG_ARCH_OMAP1510
#define bus_to_lbus(x) ((x) + (OMAP1510_LB_OFFSET - PHYS_OFFSET))
#define lbus_to_bus(x) ((x) - (OMAP1510_LB_OFFSET - PHYS_OFFSET)) #define virt_to_lbus(x) ((x) - PAGE_OFFSET + OMAP1510_LB_OFFSET)
#endif #define lbus_to_virt(x) ((x) - OMAP1510_LB_OFFSET + PAGE_OFFSET)
#define is_lbus_device(dev) (cpu_is_omap1510() && dev->coherent_dma_mask == 0x0fffffff)
#define __arch_page_to_dma(dev, page) ({is_lbus_device(dev) ? \
(dma_addr_t)virt_to_lbus(page_address(page)) : \
(dma_addr_t)__virt_to_bus(page_address(page));})
#define __arch_dma_to_virt(dev, addr) ({is_lbus_device(dev) ? \
lbus_to_virt(addr) : \
__bus_to_virt(addr);})
#define __arch_virt_to_dma(dev, addr) ({is_lbus_device(dev) ? \
virt_to_lbus(addr) : \
__virt_to_bus(addr);})
#endif /* CONFIG_ARCH_OMAP1510 */
#define PHYS_TO_NID(addr) (0) #define PHYS_TO_NID(addr) (0)
#endif #endif
......
...@@ -124,7 +124,7 @@ dma_map_single(struct device *dev, void *cpu_addr, size_t size, ...@@ -124,7 +124,7 @@ dma_map_single(struct device *dev, void *cpu_addr, size_t size,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
consistent_sync(cpu_addr, size, dir); consistent_sync(cpu_addr, size, dir);
return __virt_to_bus((unsigned long)cpu_addr); return virt_to_dma(dev, (unsigned long)cpu_addr);
} }
#else #else
extern dma_addr_t dma_map_single(struct device *,void *, size_t, enum dma_data_direction); extern dma_addr_t dma_map_single(struct device *,void *, size_t, enum dma_data_direction);
...@@ -231,7 +231,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ...@@ -231,7 +231,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
for (i = 0; i < nents; i++, sg++) { for (i = 0; i < nents; i++, sg++) {
char *virt; char *virt;
sg->dma_address = page_to_bus(sg->page) + sg->offset; sg->dma_address = page_to_dma(dev, sg->page) + sg->offset;
virt = page_address(sg->page) + sg->offset; virt = page_address(sg->page) + sg->offset;
consistent_sync(virt, sg->length, dir); consistent_sync(virt, sg->length, dir);
} }
...@@ -288,14 +288,14 @@ static inline void ...@@ -288,14 +288,14 @@ static inline void
dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size, dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
consistent_sync((void *)__bus_to_virt(handle), size, dir); consistent_sync((void *)dma_to_virt(dev, handle), size, dir);
} }
static inline void static inline void
dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size, dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
consistent_sync((void *)__bus_to_virt(handle), size, dir); consistent_sync((void *)dma_to_virt(dev, handle), size, dir);
} }
#else #else
extern void dma_sync_single_for_cpu(struct device*, dma_addr_t, size_t, enum dma_data_direction); extern void dma_sync_single_for_cpu(struct device*, dma_addr_t, size_t, enum dma_data_direction);
......
...@@ -159,9 +159,18 @@ static inline void *phys_to_virt(unsigned long x) ...@@ -159,9 +159,18 @@ static inline void *phys_to_virt(unsigned long x)
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
/* /*
* Optional device DMA address remapping. Do _not_ use directly!
* We should really eliminate virt_to_bus() here - it's deprecated. * We should really eliminate virt_to_bus() here - it's deprecated.
*/ */
#define page_to_bus(page) (virt_to_bus(page_address(page))) #ifndef __arch_page_to_dma
#define page_to_dma(dev, page) ((dma_addr_t)__virt_to_bus(page_address(page)))
#define dma_to_virt(dev, addr) (__bus_to_virt(addr))
#define virt_to_dma(dev, addr) (__virt_to_bus(addr))
#else
#define page_to_dma(dev, page) (__arch_page_to_dma(dev, page))
#define dma_to_virt(dev, addr) (__arch_dma_to_virt(dev, addr))
#define virt_to_dma(dev, addr) (__arch_virt_to_dma(dev, addr))
#endif
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment