From 832decaf007d3729dcb64f851ed4a6e2d8c4301e 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 In arm_iommu_map_sg, currently we map each individual link in the given scatterlist into the SMMU individually such that they may or may not be virtually contiguous. However, in most of our use cases we actually want the entire sg list mapped into the SMMU as a single contiguous range. This was missing for arm 32bit, add it. Change-Id: Ibf67f29a60b8d19e526c4719590f2f473ea9dca5 Signed-off-by: Chintan Pandya Signed-off-by: Charan Teja Reddy Signed-off-by: Vijayanand Jitta Signed-off-by: Qingqing Zhou --- arch/arm/mm/dma-mapping.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 57f4f03abd7b..7a3e8288062f 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1751,7 +1751,34 @@ 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, unsigned long 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_info_to_prot(dir, attrs); + + 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; + if (i == 0) + s->dma_length = total_length; + else + s->dma_length = 0; + current_offset += s->length; + } + + return nents; } static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg, @@ -1802,7 +1829,15 @@ void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, unsigned long 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(mapping->domain, iova, total_length); + __free_iova(mapping, iova, total_length); } /**