[PATCH AUTOSEL for 4.9 163/293] drivers: dma-coherent: Account dma_pfn_offset when used with device tree

2018-04-08 Thread Sasha Levin
From: Vladimir Murzin 

[ Upstream commit c41f9ea998f3ba61f38fa350eef28ec6caf0a07d ]

dma_declare_coherent_memory() and friends are designed to account
difference in CPU and device addresses. However, when it is used with
reserved memory regions there is assumption that CPU and device have
the same view on address space. This assumption gets invalid when
reserved memory for coherent DMA allocations is referenced by device
with non-empty "dma-range" property.

Simply feeding device address as rmem->base + dev->dma_pfn_offset
would not work due to reserved memory region can be shared, so this
patch turns device address to be expressed with help of CPU address
and device's dma_pfn_offset in case memory reservation has been done
via device tree; non device tree users continue to use the old scheme.

Cc: Michal Nazarewicz 
Cc: Marek Szyprowski 
Cc: Roger Quadros 
Cc: Greg Kroah-Hartman 
Tested-by: Benjamin Gaignard 
Tested-by: Andras Szemzo 
Tested-by: Alexandre TORGUE 
Signed-off-by: Vladimir Murzin 
Signed-off-by: Christoph Hellwig 
Signed-off-by: Sasha Levin 
---
 drivers/base/dma-coherent.c | 15 +--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c
index 640a7e63c453..99c969520f30 100644
--- a/drivers/base/dma-coherent.c
+++ b/drivers/base/dma-coherent.c
@@ -16,8 +16,18 @@ struct dma_coherent_mem {
int flags;
unsigned long   *bitmap;
spinlock_t  spinlock;
+   booluse_dev_dma_pfn_offset;
 };
 
+static inline dma_addr_t dma_get_device_base(struct device *dev,
+struct dma_coherent_mem * mem)
+{
+   if (mem->use_dev_dma_pfn_offset)
+   return (mem->pfn_base - dev->dma_pfn_offset) << PAGE_SHIFT;
+   else
+   return mem->device_base;
+}
+
 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)
@@ -133,7 +143,7 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
return ERR_PTR(-EINVAL);
 
spin_lock_irqsave(>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(>spinlock, flags);
 
@@ -186,7 +196,7 @@ 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(>spinlock, flags);
@@ -299,6 +309,7 @@ static int rmem_dma_device_init(struct reserved_mem *rmem, 
struct device *dev)
>base, (unsigned long)rmem->size / SZ_1M);
return -ENODEV;
}
+   mem->use_dev_dma_pfn_offset = true;
rmem->priv = mem;
dma_assign_coherent_memory(dev, mem);
return 0;
-- 
2.15.1


[PATCH AUTOSEL for 4.9 163/293] drivers: dma-coherent: Account dma_pfn_offset when used with device tree

2018-04-08 Thread Sasha Levin
From: Vladimir Murzin 

[ Upstream commit c41f9ea998f3ba61f38fa350eef28ec6caf0a07d ]

dma_declare_coherent_memory() and friends are designed to account
difference in CPU and device addresses. However, when it is used with
reserved memory regions there is assumption that CPU and device have
the same view on address space. This assumption gets invalid when
reserved memory for coherent DMA allocations is referenced by device
with non-empty "dma-range" property.

Simply feeding device address as rmem->base + dev->dma_pfn_offset
would not work due to reserved memory region can be shared, so this
patch turns device address to be expressed with help of CPU address
and device's dma_pfn_offset in case memory reservation has been done
via device tree; non device tree users continue to use the old scheme.

Cc: Michal Nazarewicz 
Cc: Marek Szyprowski 
Cc: Roger Quadros 
Cc: Greg Kroah-Hartman 
Tested-by: Benjamin Gaignard 
Tested-by: Andras Szemzo 
Tested-by: Alexandre TORGUE 
Signed-off-by: Vladimir Murzin 
Signed-off-by: Christoph Hellwig 
Signed-off-by: Sasha Levin 
---
 drivers/base/dma-coherent.c | 15 +--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c
index 640a7e63c453..99c969520f30 100644
--- a/drivers/base/dma-coherent.c
+++ b/drivers/base/dma-coherent.c
@@ -16,8 +16,18 @@ struct dma_coherent_mem {
int flags;
unsigned long   *bitmap;
spinlock_t  spinlock;
+   booluse_dev_dma_pfn_offset;
 };
 
+static inline dma_addr_t dma_get_device_base(struct device *dev,
+struct dma_coherent_mem * mem)
+{
+   if (mem->use_dev_dma_pfn_offset)
+   return (mem->pfn_base - dev->dma_pfn_offset) << PAGE_SHIFT;
+   else
+   return mem->device_base;
+}
+
 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)
@@ -133,7 +143,7 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
return ERR_PTR(-EINVAL);
 
spin_lock_irqsave(>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(>spinlock, flags);
 
@@ -186,7 +196,7 @@ 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(>spinlock, flags);
@@ -299,6 +309,7 @@ static int rmem_dma_device_init(struct reserved_mem *rmem, 
struct device *dev)
>base, (unsigned long)rmem->size / SZ_1M);
return -ENODEV;
}
+   mem->use_dev_dma_pfn_offset = true;
rmem->priv = mem;
dma_assign_coherent_memory(dev, mem);
return 0;
-- 
2.15.1