[Linaro-mm-sig] [PATCH 1/1] dma-mapping: Introduce arm_iommu_iova functions

Hiroshi Doyu hdoyu at nvidia.com
Wed Feb 29 07:59:27 UTC 2012


From: Hiroshi DOYU <hdoyu at nvidia.com>

Enable to allocate iova area with a specified address.

Signed-off-by: Hiroshi DOYU <hdoyu at nvidia.com>
---
 arch/arm/include/asm/dma-iommu.h |    9 ++++
 arch/arm/mm/dma-mapping.c        |   98 ++++++++++++++++++++++++++++++++++----
 2 files changed, 98 insertions(+), 9 deletions(-)

diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
index 799b094..8bfaeef 100644
--- a/arch/arm/include/asm/dma-iommu.h
+++ b/arch/arm/include/asm/dma-iommu.h
@@ -30,5 +30,14 @@ void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
 int arm_iommu_attach_device(struct device *dev,
 					struct dma_iommu_mapping *mapping);
 
+dma_addr_t arm_iommu_alloc_iova(struct device *dev, dma_addr_t iova,
+				size_t size);
+
+void arm_iommu_free_iova(struct device *dev, dma_addr_t addr, size_t size);
+
+size_t arm_iommu_iova_avail(struct device *dev);
+
+size_t arm_iommu_iova_max_free(struct device *dev);
+
 #endif /* __KERNEL__ */
 #endif
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 25baa16..f1af7a5 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -749,12 +749,61 @@ fs_initcall(dma_debug_do_init);
 
 /* IOMMU */
 
-static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
-				      size_t size)
+size_t arm_iommu_iova_avail(struct device *dev)
+{
+	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+	unsigned long flags;
+	size_t bytes = 0;
+
+	spin_lock_irqsave(&mapping->lock, flags);
+	while (1) {
+		unsigned long start = 0, end;
+
+		start = bitmap_find_next_zero_area(mapping->bitmap,
+						   mapping->bits, start, 1, 0);
+		if (start > mapping->bits)
+			break;
+
+		end = find_next_bit(mapping->bitmap, mapping->bits, start);
+		bytes += end - start;
+		start = end;
+	}
+	spin_unlock_irqrestore(&mapping->lock, flags);
+	return bytes;
+}
+EXPORT_SYMBOL_GPL(arm_iommu_iova_avail);
+
+size_t arm_iommu_iova_max_free(struct device *dev)
+{
+	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+	unsigned long flags;
+	size_t max_free = 0;
+	unsigned long start = 0;
+
+	spin_lock_irqsave(&mapping->lock, flags);
+	while (1) {
+		unsigned long end;
+
+		start = bitmap_find_next_zero_area(mapping->bitmap,
+						   mapping->bits, start, 1, 0);
+		if (start > mapping->bits)
+			break;
+
+		end = find_next_bit(mapping->bitmap, mapping->bits, start);
+		max_free = max_t(size_t, max_free, end - start);
+		start = end;
+	}
+	spin_unlock_irqrestore(&mapping->lock, flags);
+	return max_free << PAGE_SHIFT;
+}
+EXPORT_SYMBOL_GPL(arm_iommu_iova_max_free);
+
+static dma_addr_t __alloc_iova_addr(struct dma_iommu_mapping *mapping,
+				     dma_addr_t iova, size_t size)
 {
 	unsigned int order = get_order(size);
 	unsigned int align = 0;
-	unsigned int count, start;
+	unsigned int count, orig, start;
 	unsigned long flags;
 
 	count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
@@ -764,18 +813,41 @@ static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
 		align = (1 << (order - mapping->order)) - 1;
 
 	spin_lock_irqsave(&mapping->lock, flags);
-	start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0,
-					   count, align);
-	if (start > mapping->bits) {
-		spin_unlock_irqrestore(&mapping->lock, flags);
-		return ~0;
-	}
+
+	orig = iova ? (iova >> (mapping->order + PAGE_SHIFT)) : 0;
+
+	start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits,
+					   orig, count, align);
+	if (start > mapping->bits)
+		goto not_found;
+
+	if (iova && (orig != start))
+		goto not_found;
 
 	bitmap_set(mapping->bitmap, start, count);
 	spin_unlock_irqrestore(&mapping->lock, flags);
 
 	return mapping->base + (start << (mapping->order + PAGE_SHIFT));
+
+not_found:
+	spin_unlock_irqrestore(&mapping->lock, flags);
+	return ~0;
+}
+
+static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
+				      size_t size)
+{
+	return __alloc_iova_addr(mapping, 0, size);
+}
+
+dma_addr_t arm_iommu_alloc_iova(struct device *dev, dma_addr_t iova,
+				size_t size)
+{
+	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+
+	return __alloc_iova_addr(mapping, iova, size);
 }
+EXPORT_SYMBOL_GPL(arm_iommu_alloc_iova);
 
 static inline void __free_iova(struct dma_iommu_mapping *mapping,
 			       dma_addr_t addr, size_t size)
@@ -791,6 +863,14 @@ static inline void __free_iova(struct dma_iommu_mapping *mapping,
 	spin_unlock_irqrestore(&mapping->lock, flags);
 }
 
+void arm_iommu_free_iova(struct device *dev, dma_addr_t addr, size_t size)
+{
+	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+
+	__free_iova(mapping, addr, size);
+}
+EXPORT_SYMBOL_GPL(arm_iommu_free_iova);
+
 static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
 {
 	struct page **pages;
-- 
1.7.5.4



More information about the Linaro-mm-sig mailing list