@@ -27,6 +27,15 @@ static inline struct dma_coherent_mem *dev_get_coherent_memory(struct device *de
return dma_coherent_default_memory;
}
+static inline dma_addr_t dma_get_device_base(struct device *dev,
+ struct dma_coherent_mem * mem)
+{
+ if (!dev)
+ return mem->pfn_base << PAGE_SHIFT;
+
+ return (mem->pfn_base + dev->dma_pfn_offset) << PAGE_SHIFT;
+}
+
static bool dma_init_coherent_memory(
phys_addr_t phys_addr, dma_addr_t device_addr, size_t size, int flags,
struct dma_coherent_mem **mem)
@@ -92,13 +101,19 @@ static void dma_release_coherent_memory(struct dma_coherent_mem *mem)
static int dma_assign_coherent_memory(struct device *dev,
struct dma_coherent_mem *mem)
{
+ unsigned long dma_pfn_offset = mem->pfn_base - PFN_DOWN(mem->device_base);
+
if (!dev)
return -ENODEV;
if (dev->dma_mem)
return -EBUSY;
+ if (dev->dma_pfn_offset)
+ WARN_ON(dev->dma_pfn_offset != dma_pfn_offset);
+
dev->dma_mem = mem;
+ dev->dma_pfn_offset = dma_pfn_offset;
/* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
return 0;
@@ -145,7 +160,7 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
return ERR_PTR(-EINVAL);
spin_lock_irqsave(&mem->spinlock, flags);
- pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
+ pos = PFN_DOWN(device_addr - dma_get_device_base(dev, mem));
err = bitmap_allocate_region(mem->bitmap, pos, get_order(size));
spin_unlock_irqrestore(&mem->spinlock, flags);
@@ -195,8 +210,9 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size,
/*
* Memory was found in the per-device area.
*/
- *dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
+ *dma_handle = dma_get_device_base(dev, mem) + (pageno << PAGE_SHIFT);
*ret = mem->virt_base + (pageno << PAGE_SHIFT);
+
dma_memory_map = (mem->flags & DMA_MEMORY_MAP);
spin_unlock_irqrestore(&mem->spinlock, flags);
if (dma_memory_map)