[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