diff options
author | Marek Szyprowski <m.szyprowski@samsung.com> | 2012-10-15 10:03:52 -0400 |
---|---|---|
committer | Inki Dae <daeinki@gmail.com> | 2012-11-29 06:30:34 -0500 |
commit | 549a17e447d72bab648c783abbba98f3bd5b4dd5 (patch) | |
tree | 51d4664c81dc8540b8b8becb4f67299cc32eee33 /arch | |
parent | 4b9347dcbe3b426d19bda99b2061a2d1fe5a2dce (diff) |
ARM: dma-mapping: add support for DMA_ATTR_FORCE_CONTIGUOUS attribute
This patch adds support for DMA_ATTR_FORCE_CONTIGUOUS attribute for
dma_alloc_attrs() in IOMMU-aware implementation. For allocating physically
contiguous buffers Contiguous Memory Allocator is used.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Diffstat (limited to 'arch')
-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 58bc3e4d3bd0..f076f209c7a4 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, | |||
1036 | spin_unlock_irqrestore(&mapping->lock, flags); | 1036 | spin_unlock_irqrestore(&mapping->lock, flags); |
1037 | } | 1037 | } |
1038 | 1038 | ||
1039 | static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t gfp) | 1039 | static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, |
1040 | gfp_t gfp, struct dma_attrs *attrs) | ||
1040 | { | 1041 | { |
1041 | struct page **pages; | 1042 | struct page **pages; |
1042 | int count = size >> PAGE_SHIFT; | 1043 | int count = size >> PAGE_SHIFT; |
@@ -1050,6 +1051,23 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t | |||
1050 | if (!pages) | 1051 | if (!pages) |
1051 | return NULL; | 1052 | return NULL; |
1052 | 1053 | ||
1054 | if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) | ||
1055 | { | ||
1056 | unsigned long order = get_order(size); | ||
1057 | struct page *page; | ||
1058 | |||
1059 | page = dma_alloc_from_contiguous(dev, count, order); | ||
1060 | if (!page) | ||
1061 | goto error; | ||
1062 | |||
1063 | __dma_clear_buffer(page, size); | ||
1064 | |||
1065 | for (i = 0; i < count; i++) | ||
1066 | pages[i] = page + i; | ||
1067 | |||
1068 | return pages; | ||
1069 | } | ||
1070 | |||
1053 | while (count) { | 1071 | while (count) { |
1054 | int j, order = __fls(count); | 1072 | int j, order = __fls(count); |
1055 | 1073 | ||
@@ -1083,14 +1101,21 @@ error: | |||
1083 | return NULL; | 1101 | return NULL; |
1084 | } | 1102 | } |
1085 | 1103 | ||
1086 | static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t size) | 1104 | static int __iommu_free_buffer(struct device *dev, struct page **pages, |
1105 | size_t size, struct dma_attrs *attrs) | ||
1087 | { | 1106 | { |
1088 | int count = size >> PAGE_SHIFT; | 1107 | int count = size >> PAGE_SHIFT; |
1089 | int array_size = count * sizeof(struct page *); | 1108 | int array_size = count * sizeof(struct page *); |
1090 | int i; | 1109 | int i; |
1091 | for (i = 0; i < count; i++) | 1110 | |
1092 | if (pages[i]) | 1111 | if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) { |
1093 | __free_pages(pages[i], 0); | 1112 | dma_release_from_contiguous(dev, pages[0], count); |
1113 | } else { | ||
1114 | for (i = 0; i < count; i++) | ||
1115 | if (pages[i]) | ||
1116 | __free_pages(pages[i], 0); | ||
1117 | } | ||
1118 | |||
1094 | if (array_size <= PAGE_SIZE) | 1119 | if (array_size <= PAGE_SIZE) |
1095 | kfree(pages); | 1120 | kfree(pages); |
1096 | else | 1121 | else |
@@ -1252,7 +1277,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, | |||
1252 | if (gfp & GFP_ATOMIC) | 1277 | if (gfp & GFP_ATOMIC) |
1253 | return __iommu_alloc_atomic(dev, size, handle); | 1278 | return __iommu_alloc_atomic(dev, size, handle); |
1254 | 1279 | ||
1255 | pages = __iommu_alloc_buffer(dev, size, gfp); | 1280 | pages = __iommu_alloc_buffer(dev, size, gfp, attrs); |
1256 | if (!pages) | 1281 | if (!pages) |
1257 | return NULL; | 1282 | return NULL; |
1258 | 1283 | ||
@@ -1273,7 +1298,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, | |||
1273 | err_mapping: | 1298 | err_mapping: |
1274 | __iommu_remove_mapping(dev, *handle, size); | 1299 | __iommu_remove_mapping(dev, *handle, size); |
1275 | err_buffer: | 1300 | err_buffer: |
1276 | __iommu_free_buffer(dev, pages, size); | 1301 | __iommu_free_buffer(dev, pages, size, attrs); |
1277 | return NULL; | 1302 | return NULL; |
1278 | } | 1303 | } |
1279 | 1304 | ||
@@ -1329,7 +1354,7 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, | |||
1329 | } | 1354 | } |
1330 | 1355 | ||
1331 | __iommu_remove_mapping(dev, handle, size); | 1356 | __iommu_remove_mapping(dev, handle, size); |
1332 | __iommu_free_buffer(dev, pages, size); | 1357 | __iommu_free_buffer(dev, pages, size, attrs); |
1333 | } | 1358 | } |
1334 | 1359 | ||
1335 | static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt, | 1360 | static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt, |