From 81e4499b1e19b3e81da993e9a80e3e0b604c719f Mon Sep 17 00:00:00 2001 From: Chintan Pandya Date: Tue, 26 May 2015 17:59:11 +0530 Subject: [PATCH] arm: dma-mapping: map sg lists into the SMMU as virtually contiguous Following commit implements mapping of sg virtually contiguously. "arm64: dma-mapping: map sg lists into the SMMU as virtually contiguous" a03f74ef16cc73531795176d3ea8b82b66ed0146 This has been left for ARM (32-bit). Implement the same for ARM. Change-Id: Ibf67f29a60b8d19e526c4719590f2f473ea9dca5 Signed-off-by: Chintan Pandya --- arch/arm/mm/dma-mapping.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index d049be34fcee..8fa0ef24d7dc 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1689,7 +1689,31 @@ int arm_coherent_iommu_map_sg(struct device *dev, struct scatterlist *sg, int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, struct dma_attrs *attrs) { - return __iommu_map_sg(dev, sg, nents, dir, attrs, false); + struct scatterlist *s; + int i; + size_t ret; + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + unsigned int total_length = 0, current_offset = 0; + dma_addr_t iova; + int prot = __dma_direction_to_prot(dir); + + for_each_sg(sg, s, nents, i) + total_length += s->length; + + iova = __alloc_iova(mapping, total_length); + ret = iommu_map_sg(mapping->domain, iova, sg, nents, prot); + if (ret != total_length) { + __free_iova(mapping, iova, total_length); + return 0; + } + + for_each_sg(sg, s, nents, i) { + s->dma_address = iova + current_offset; + s->dma_length = total_length - current_offset; + current_offset += s->length; + } + + return nents; } static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg, @@ -1739,7 +1763,15 @@ void arm_coherent_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, struct dma_attrs *attrs) { - __iommu_unmap_sg(dev, sg, nents, dir, attrs, false); + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + unsigned int total_length = sg_dma_len(sg); + dma_addr_t iova = sg_dma_address(sg); + + total_length = PAGE_ALIGN((iova & ~PAGE_MASK) + total_length); + iova &= PAGE_MASK; + + iommu_unmap_range(mapping->domain, iova, total_length); + __free_iova(mapping, iova, total_length); } /**