diff options
Diffstat (limited to 'arch/arm/mm/dma-mapping.c')
| -rw-r--r-- | arch/arm/mm/dma-mapping.c | 41 | 
1 files changed, 33 insertions, 8 deletions
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 58bc3e4d3bd..f076f209c7a 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1036,7 +1036,8 @@ static inline void __free_iova(struct dma_iommu_mapping *mapping,  	spin_unlock_irqrestore(&mapping->lock, flags);  } -static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t gfp) +static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, +					  gfp_t gfp, struct dma_attrs *attrs)  {  	struct page **pages;  	int count = size >> PAGE_SHIFT; @@ -1050,6 +1051,23 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t  	if (!pages)  		return NULL; +	if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) +	{ +		unsigned long order = get_order(size); +		struct page *page; + +		page = dma_alloc_from_contiguous(dev, count, order); +		if (!page) +			goto error; + +		__dma_clear_buffer(page, size); + +		for (i = 0; i < count; i++) +			pages[i] = page + i; + +		return pages; +	} +  	while (count) {  		int j, order = __fls(count); @@ -1083,14 +1101,21 @@ error:  	return NULL;  } -static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t size) +static int __iommu_free_buffer(struct device *dev, struct page **pages, +			       size_t size, struct dma_attrs *attrs)  {  	int count = size >> PAGE_SHIFT;  	int array_size = count * sizeof(struct page *);  	int i; -	for (i = 0; i < count; i++) -		if (pages[i]) -			__free_pages(pages[i], 0); + +	if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) { +		dma_release_from_contiguous(dev, pages[0], count); +	} else { +		for (i = 0; i < count; i++) +			if (pages[i]) +				__free_pages(pages[i], 0); +	} +  	if (array_size <= PAGE_SIZE)  		kfree(pages);  	else @@ -1252,7 +1277,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,  	if (gfp & GFP_ATOMIC)  		return __iommu_alloc_atomic(dev, size, handle); -	pages = __iommu_alloc_buffer(dev, size, gfp); +	pages = __iommu_alloc_buffer(dev, size, gfp, attrs);  	if (!pages)  		return NULL; @@ -1273,7 +1298,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,  err_mapping:  	__iommu_remove_mapping(dev, *handle, size);  err_buffer: -	__iommu_free_buffer(dev, pages, size); +	__iommu_free_buffer(dev, pages, size, attrs);  	return NULL;  } @@ -1329,7 +1354,7 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,  	}  	__iommu_remove_mapping(dev, handle, size); -	__iommu_free_buffer(dev, pages, size); +	__iommu_free_buffer(dev, pages, size, attrs);  }  static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,  |