aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Szyprowski <m.szyprowski@samsung.com>2012-05-16 14:38:58 -0400
committerMarek Szyprowski <m.szyprowski@samsung.com>2012-07-30 06:25:46 -0400
commit955c757e090f41188764a0e488ba7036f7dbb215 (patch)
treead5f20e5caa6331ce889261f3f0a11b3c8deed12
parentd5724f172fd1406c6962c4d2e27228b8e9e83642 (diff)
ARM: dma-mapping: add support for DMA_ATTR_NO_KERNEL_MAPPING attribute
This patch adds support for DMA_ATTR_NO_KERNEL_MAPPING attribute for IOMMU allocations, what let drivers to save precious kernel virtual address space for large buffers that are intended to be accessed only from userspace. This patch is heavily based on initial work kindly provided by Abhinav Kochhar <abhinav.k@samsung.com>. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Reviewed-by: Kyungmin Park <kyungmin.park@samsung.com>
-rw-r--r--arch/arm/mm/dma-mapping.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index cbdeaf4a3392..8e505b9df5c7 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -1074,10 +1074,13 @@ static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t si
1074 return 0; 1074 return 0;
1075} 1075}
1076 1076
1077static struct page **__iommu_get_pages(void *cpu_addr) 1077static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs)
1078{ 1078{
1079 struct vm_struct *area; 1079 struct vm_struct *area;
1080 1080
1081 if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
1082 return cpu_addr;
1083
1081 area = find_vm_area(cpu_addr); 1084 area = find_vm_area(cpu_addr);
1082 if (area && (area->flags & VM_ARM_DMA_CONSISTENT)) 1085 if (area && (area->flags & VM_ARM_DMA_CONSISTENT))
1083 return area->pages; 1086 return area->pages;
@@ -1102,6 +1105,9 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
1102 if (*handle == DMA_ERROR_CODE) 1105 if (*handle == DMA_ERROR_CODE)
1103 goto err_buffer; 1106 goto err_buffer;
1104 1107
1108 if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
1109 return pages;
1110
1105 addr = __iommu_alloc_remap(pages, size, gfp, prot, 1111 addr = __iommu_alloc_remap(pages, size, gfp, prot,
1106 __builtin_return_address(0)); 1112 __builtin_return_address(0));
1107 if (!addr) 1113 if (!addr)
@@ -1122,7 +1128,7 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
1122{ 1128{
1123 unsigned long uaddr = vma->vm_start; 1129 unsigned long uaddr = vma->vm_start;
1124 unsigned long usize = vma->vm_end - vma->vm_start; 1130 unsigned long usize = vma->vm_end - vma->vm_start;
1125 struct page **pages = __iommu_get_pages(cpu_addr); 1131 struct page **pages = __iommu_get_pages(cpu_addr, attrs);
1126 1132
1127 vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); 1133 vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
1128 1134
@@ -1149,7 +1155,7 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
1149void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, 1155void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
1150 dma_addr_t handle, struct dma_attrs *attrs) 1156 dma_addr_t handle, struct dma_attrs *attrs)
1151{ 1157{
1152 struct page **pages = __iommu_get_pages(cpu_addr); 1158 struct page **pages = __iommu_get_pages(cpu_addr, attrs);
1153 size = PAGE_ALIGN(size); 1159 size = PAGE_ALIGN(size);
1154 1160
1155 if (!pages) { 1161 if (!pages) {
@@ -1157,8 +1163,10 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
1157 return; 1163 return;
1158 } 1164 }
1159 1165
1160 unmap_kernel_range((unsigned long)cpu_addr, size); 1166 if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) {
1161 vunmap(cpu_addr); 1167 unmap_kernel_range((unsigned long)cpu_addr, size);
1168 vunmap(cpu_addr);
1169 }
1162 1170
1163 __iommu_remove_mapping(dev, handle, size); 1171 __iommu_remove_mapping(dev, handle, size);
1164 __iommu_free_buffer(dev, pages, size); 1172 __iommu_free_buffer(dev, pages, size);