aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHiroshi Doyu <hdoyu@nvidia.com>2012-08-28 01:13:04 -0400
committerMarek Szyprowski <m.szyprowski@samsung.com>2012-08-28 15:01:07 -0400
commit479ed93a4b98eef03fd8260f7ddc00019221c450 (patch)
treeeb4c1d6cb33edd15c4b892e42c2e3f58b227525c
parent665bad7bb911d392000fa69bc6b599c0df992504 (diff)
ARM: dma-mapping: IOMMU allocates pages from atomic_pool with GFP_ATOMIC
Make use of the same atomic pool as DMA does, and skip a kernel page mapping which can involve sleep'able operations at allocating a kernel page table. Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
-rw-r--r--arch/arm/mm/dma-mapping.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 54b158df5afa..051204fc4617 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -1161,6 +1161,34 @@ static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs)
1161 return NULL; 1161 return NULL;
1162} 1162}
1163 1163
1164static void *__iommu_alloc_atomic(struct device *dev, size_t size,
1165 dma_addr_t *handle)
1166{
1167 struct page *page;
1168 void *addr;
1169
1170 addr = __alloc_from_pool(size, &page);
1171 if (!addr)
1172 return NULL;
1173
1174 *handle = __iommu_create_mapping(dev, &page, size);
1175 if (*handle == DMA_ERROR_CODE)
1176 goto err_mapping;
1177
1178 return addr;
1179
1180err_mapping:
1181 __free_from_pool(addr, size);
1182 return NULL;
1183}
1184
1185static void __iommu_free_atomic(struct device *dev, struct page **pages,
1186 dma_addr_t handle, size_t size)
1187{
1188 __iommu_remove_mapping(dev, handle, size);
1189 __free_from_pool(page_address(pages[0]), size);
1190}
1191
1164static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, 1192static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
1165 dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) 1193 dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
1166{ 1194{
@@ -1171,6 +1199,9 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
1171 *handle = DMA_ERROR_CODE; 1199 *handle = DMA_ERROR_CODE;
1172 size = PAGE_ALIGN(size); 1200 size = PAGE_ALIGN(size);
1173 1201
1202 if (gfp & GFP_ATOMIC)
1203 return __iommu_alloc_atomic(dev, size, handle);
1204
1174 pages = __iommu_alloc_buffer(dev, size, gfp); 1205 pages = __iommu_alloc_buffer(dev, size, gfp);
1175 if (!pages) 1206 if (!pages)
1176 return NULL; 1207 return NULL;
@@ -1237,6 +1268,11 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
1237 return; 1268 return;
1238 } 1269 }
1239 1270
1271 if (__in_atomic_pool(cpu_addr, size)) {
1272 __iommu_free_atomic(dev, pages, handle, size);
1273 return;
1274 }
1275
1240 if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) { 1276 if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) {
1241 unmap_kernel_range((unsigned long)cpu_addr, size); 1277 unmap_kernel_range((unsigned long)cpu_addr, size);
1242 vunmap(cpu_addr); 1278 vunmap(cpu_addr);