arm64: dma-mapping: implement dma_get_sgtable()
PATCH 1/2 arm64: dma-mapping: implement dma_get_sgtable()
The default dma_common_get_sgtable() implementation relies on the CPU address of the buffer being a regular lowmem address. This is not always the case on arm64, since allocations from the various DMA pools may have remapped vmalloc addresses, rendering the use of virt_to_page() invalid.
Fix this by providing our own implementation based on the fact that we can safely derive a physical address from the DMA address in both cases.
--- arch/arm64/mm/dma-mapping.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
arch/arm64/mm/dma-mapping.c +14 -0
@@ -337,10 +337,24 @@ static int __swiotlb_mmap(struct device *dev,return __dma_common_mmap (dev, vma, cpu_addr, dma_addr, size); } +int __swiotlb_get_sgtable (struct device *dev,struct sg_table *sgt, +void *cpu_addr,dma_addr_t handle,size_t size, +struct dma_attrs *attrs) +{ +int ret =sg_alloc_table (sgt,1 ,GFP_KERNEL ); + +if (!ret) +sg_set_page (sgt->sgl,phys_to_page (dma_to_phys (dev, handle)), +PAGE_ALIGN (size),0 ); + +return ret; +} +static struct dma_map_ops swiotlb_dma_ops = { .alloc = __dma_alloc, .free = __dma_free, .mmap = __swiotlb_mmap, + .get_sgtable = __swiotlb_get_sgtable, .map_page = __swiotlb_map_page, .unmap_page = __swiotlb_unmap_page, .map_sg = __swiotlb_map_sg_attrs,
Signature · 1 line
1.9.1
PATCH 2/2 arm64: dma-mapping: consolidate __swiotlb_mmap()
Since commit 9d3bfbb4df58 ("arm64: Combine coherent and non-coherent swiotlb dma_ops"), __dma_common_mmap() is no longer shared between two callers, so roll it into the remaining one.
--- arch/arm64/mm/dma-mapping.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-)
arch/arm64/mm/dma-mapping.c +6 -13
@@ -303,9 +303,9 @@ static void __swiotlb_sync_sg_for_device(struct device *dev, sg->length, dir); } -/* vma->vm_page_prot must be set appropriately before calling this function */ -static int __dma_common_mmap (struct device *dev,struct vm_area_struct *vma, -void *cpu_addr,dma_addr_t dma_addr,size_t size) +static int __swiotlb_mmap (struct device *dev,struct vm_area_struct *vma, +void *cpu_addr,dma_addr_t dma_addr,size_t size, +struct dma_attrs *attrs) {int ret = -ENXIO ; unsigned long nr_vma_pages = (vma->vm_end - vma->vm_start) >>
@@ -314,6 +314,9 @@ static int __dma_common_mmap(struct device *dev, struct vm_area_struct *vma,unsigned long pfn =dma_to_phys (dev, dma_addr) >>PAGE_SHIFT ;unsigned long off = vma->vm_pgoff; + vma->vm_page_prot =__get_dma_pgprot (attrs, vma->vm_page_prot, +is_device_dma_coherent (dev)); +if (dma_mmap_from_coherent (dev, vma, cpu_addr, size, &ret))return ret;
@@ -327,16 +330,6 @@ static int __dma_common_mmap(struct device *dev, struct vm_area_struct *vma,return ret; } -static int __swiotlb_mmap (struct device *dev, -struct vm_area_struct *vma, -void *cpu_addr,dma_addr_t dma_addr,size_t size, -struct dma_attrs *attrs) -{ - vma->vm_page_prot =__get_dma_pgprot (attrs, vma->vm_page_prot, -is_device_dma_coherent (dev)); -return __dma_common_mmap (dev, vma, cpu_addr, dma_addr, size); -} -int __swiotlb_get_sgtable (struct device *dev,struct sg_table *sgt,void *cpu_addr,dma_addr_t handle,size_t size,struct dma_attrs *attrs)
Signature · 1 line
1.9.1
PATCH 1/2 arm64: dma-mapping: implement dma_get_sgtable()
In reply to Robin MurphyQuoted 24 lines · Robin Murphy
The default
dma_common_get_sgtable()implementation relies on the CPU address of the buffer being a regular lowmem address. This is not always the case on arm64, since allocations from the various DMA pools may have remapped vmalloc addresses, rendering the use ofvirt_to_page()invalid.Fix this by providing our own implementation based on the fact that we can safely derive a physical address from the DMA address in both cases.
CC Jon Medhurst <[email protected]>Signed-off-by Robin Murphy <[email protected]>--- arch/arm64/mm/dma-mapping.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)arch/arm64/mm/dma-mapping.c +2
-0@@ -337,10 +337,24 @@ static int __swiotlb_mmap(struct device *dev,return __dma_common_mmap (dev, vma, cpu_addr, dma_addr, size); } +int __swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t handle, size_t size,
arch/arm64/mm/dma-mapping.c static int __swiotlb_mmap(struct device *dev, · line 351
Quoted 10 lines
arch/arm64/mm/dma-mapping.c +10
-0+ struct dma_attrs *attrs) +{ +int ret =sg_alloc_table (sgt,1 ,GFP_KERNEL ); + +if (!ret) +sg_set_page (sgt->sgl,phys_to_page (dma_to_phys (dev, handle)), +PAGE_ALIGN (size),0 ); + +return ret; +}
Any reason not to do this in dma_common_get_sgtable?
Will
PATCH 1/2 arm64: dma-mapping: implement dma_get_sgtable()
Hi Will,
Quoted 23 lines · Will Deacon
Quoted 22 lines · Robin Murphy
The default
dma_common_get_sgtable()implementation relies on the CPU address of the buffer being a regular lowmem address. This is not always the case on arm64, since allocations from the various DMA pools may have remapped vmalloc addresses, rendering the use ofvirt_to_page()invalid.Fix this by providing our own implementation based on the fact that we can safely derive a physical address from the DMA address in both cases.
CC Jon Medhurst <[email protected]>Signed-off-by Robin Murphy <[email protected]>--- arch/arm64/mm/dma-mapping.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)arch/arm64/mm/dma-mapping.c +0
-0@@ -337,10 +337,24 @@ static int __swiotlb_mmap(struct device *dev,return __dma_common_mmap (dev, vma, cpu_addr, dma_addr, size); }
Quoted 14 lines
arch/arm64/mm/dma-mapping.c static int __swiotlb_mmap(struct device *dev, · line 351
Quoted 12 lines
arch/arm64/mm/dma-mapping.c +12
-0+int __swiotlb_get_sgtable (struct device *dev,struct sg_table *sgt, +void *cpu_addr,dma_addr_t handle,size_t size, +struct dma_attrs *attrs) +{ +int ret =sg_alloc_table (sgt,1 ,GFP_KERNEL ); + +if (!ret) +sg_set_page (sgt->sgl,phys_to_page (dma_to_phys (dev, handle)), +PAGE_ALIGN (size),0 ); + +return ret; +}Any reason not to do this in
dma_common_get_sgtable?
Summarising the discussion over at [1], most architectures seem to depend on dma_common_get_sgtable, but only a handful implement dma_to_phys (plus this approach seems to match the original intent). There doesn't seem to be a nice solution for doing this in common code without a big cross-architecture patch, and it's somewhat questionable how widely this is actually needed.
Robin.
[1]:http://thread.gmane.org/gmane.linux.kernel/1998795
Quoted 3 lines
Will