From: Hiroshi DOYU hdoyu@nvidia.com
Enable to allocate iova area with a specified address.
Signed-off-by: Hiroshi DOYU hdoyu@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;
linaro-mm-sig@lists.linaro.org