summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2018-11-04 14:29:28 -0500
committerChristoph Hellwig <hch@lst.de>2018-12-01 12:07:11 -0500
commit0c3b3171ceccb8830c2bb5adff1b4e9b204c1450 (patch)
treec7dbe5478677405c690334e59acc392c5db86858
parentf0edfea8ef93ed6cc5f747c46c85c8e53e0798a0 (diff)
dma-mapping: move the arm64 noncoherent alloc/free support to common code
The arm64 codebase to implement coherent dma allocation for architectures with non-coherent DMA is a good start for a generic implementation, given that is uses the generic remap helpers, provides the atomic pool for allocations that can't sleep and still is realtively simple and well tested. Move it to kernel/dma and allow architectures to opt into it using a config symbol. Architectures just need to provide a new arch_dma_prep_coherent helper to writeback an invalidate the caches for any memory that gets remapped for uncached access. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Will Deacon <will.deacon@arm.com> Reviewed-by: Robin Murphy <robin.murphy@arm.com>
-rw-r--r--arch/arm64/Kconfig2
-rw-r--r--arch/arm64/mm/dma-mapping.c184
-rw-r--r--include/linux/dma-mapping.h5
-rw-r--r--include/linux/dma-noncoherent.h2
-rw-r--r--kernel/dma/Kconfig5
-rw-r--r--kernel/dma/remap.c158
6 files changed, 180 insertions, 176 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 5d065acb6d10..2e645ea693ea 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -82,7 +82,7 @@ config ARM64
82 select CRC32 82 select CRC32
83 select DCACHE_WORD_ACCESS 83 select DCACHE_WORD_ACCESS
84 select DMA_DIRECT_OPS 84 select DMA_DIRECT_OPS
85 select DMA_REMAP 85 select DMA_DIRECT_REMAP
86 select EDAC_SUPPORT 86 select EDAC_SUPPORT
87 select FRAME_POINTER 87 select FRAME_POINTER
88 select GENERIC_ALLOCATOR 88 select GENERIC_ALLOCATOR
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index a3ac26284845..e2e7e5d0f94e 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -33,113 +33,6 @@
33 33
34#include <asm/cacheflush.h> 34#include <asm/cacheflush.h>
35 35
36static struct gen_pool *atomic_pool __ro_after_init;
37
38#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
39static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE;
40
41static int __init early_coherent_pool(char *p)
42{
43 atomic_pool_size = memparse(p, &p);
44 return 0;
45}
46early_param("coherent_pool", early_coherent_pool);
47
48static void *__alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags)
49{
50 unsigned long val;
51 void *ptr = NULL;
52
53 if (!atomic_pool) {
54 WARN(1, "coherent pool not initialised!\n");
55 return NULL;
56 }
57
58 val = gen_pool_alloc(atomic_pool, size);
59 if (val) {
60 phys_addr_t phys = gen_pool_virt_to_phys(atomic_pool, val);
61
62 *ret_page = phys_to_page(phys);
63 ptr = (void *)val;
64 memset(ptr, 0, size);
65 }
66
67 return ptr;
68}
69
70static bool __in_atomic_pool(void *start, size_t size)
71{
72 return addr_in_gen_pool(atomic_pool, (unsigned long)start, size);
73}
74
75static int __free_from_pool(void *start, size_t size)
76{
77 if (!__in_atomic_pool(start, size))
78 return 0;
79
80 gen_pool_free(atomic_pool, (unsigned long)start, size);
81
82 return 1;
83}
84
85void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
86 gfp_t flags, unsigned long attrs)
87{
88 struct page *page;
89 void *ptr, *coherent_ptr;
90 pgprot_t prot = pgprot_writecombine(PAGE_KERNEL);
91
92 size = PAGE_ALIGN(size);
93
94 if (!gfpflags_allow_blocking(flags)) {
95 struct page *page = NULL;
96 void *addr = __alloc_from_pool(size, &page, flags);
97
98 if (addr)
99 *dma_handle = phys_to_dma(dev, page_to_phys(page));
100
101 return addr;
102 }
103
104 ptr = dma_direct_alloc_pages(dev, size, dma_handle, flags, attrs);
105 if (!ptr)
106 goto no_mem;
107
108 /* remove any dirty cache lines on the kernel alias */
109 __dma_flush_area(ptr, size);
110
111 /* create a coherent mapping */
112 page = virt_to_page(ptr);
113 coherent_ptr = dma_common_contiguous_remap(page, size, VM_USERMAP,
114 prot, __builtin_return_address(0));
115 if (!coherent_ptr)
116 goto no_map;
117
118 return coherent_ptr;
119
120no_map:
121 dma_direct_free_pages(dev, size, ptr, *dma_handle, attrs);
122no_mem:
123 return NULL;
124}
125
126void arch_dma_free(struct device *dev, size_t size, void *vaddr,
127 dma_addr_t dma_handle, unsigned long attrs)
128{
129 if (!__free_from_pool(vaddr, PAGE_ALIGN(size))) {
130 void *kaddr = phys_to_virt(dma_to_phys(dev, dma_handle));
131
132 vunmap(vaddr);
133 dma_direct_free_pages(dev, size, kaddr, dma_handle, attrs);
134 }
135}
136
137long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
138 dma_addr_t dma_addr)
139{
140 return __phys_to_pfn(dma_to_phys(dev, dma_addr));
141}
142
143pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot, 36pgprot_t arch_dma_mmap_pgprot(struct device *dev, pgprot_t prot,
144 unsigned long attrs) 37 unsigned long attrs)
145{ 38{
@@ -160,6 +53,11 @@ void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
160 __dma_unmap_area(phys_to_virt(paddr), size, dir); 53 __dma_unmap_area(phys_to_virt(paddr), size, dir);
161} 54}
162 55
56void arch_dma_prep_coherent(struct page *page, size_t size)
57{
58 __dma_flush_area(page_address(page), size);
59}
60
163#ifdef CONFIG_IOMMU_DMA 61#ifdef CONFIG_IOMMU_DMA
164static int __swiotlb_get_sgtable_page(struct sg_table *sgt, 62static int __swiotlb_get_sgtable_page(struct sg_table *sgt,
165 struct page *page, size_t size) 63 struct page *page, size_t size)
@@ -191,67 +89,6 @@ static int __swiotlb_mmap_pfn(struct vm_area_struct *vma,
191} 89}
192#endif /* CONFIG_IOMMU_DMA */ 90#endif /* CONFIG_IOMMU_DMA */
193 91
194static int __init atomic_pool_init(void)
195{
196 pgprot_t prot = __pgprot(PROT_NORMAL_NC);
197 unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT;
198 struct page *page;
199 void *addr;
200 unsigned int pool_size_order = get_order(atomic_pool_size);
201
202 if (dev_get_cma_area(NULL))
203 page = dma_alloc_from_contiguous(NULL, nr_pages,
204 pool_size_order, false);
205 else
206 page = alloc_pages(GFP_DMA32, pool_size_order);
207
208 if (page) {
209 int ret;
210 void *page_addr = page_address(page);
211
212 memset(page_addr, 0, atomic_pool_size);
213 __dma_flush_area(page_addr, atomic_pool_size);
214
215 atomic_pool = gen_pool_create(PAGE_SHIFT, -1);
216 if (!atomic_pool)
217 goto free_page;
218
219 addr = dma_common_contiguous_remap(page, atomic_pool_size,
220 VM_USERMAP, prot, atomic_pool_init);
221
222 if (!addr)
223 goto destroy_genpool;
224
225 ret = gen_pool_add_virt(atomic_pool, (unsigned long)addr,
226 page_to_phys(page),
227 atomic_pool_size, -1);
228 if (ret)
229 goto remove_mapping;
230
231 gen_pool_set_algo(atomic_pool,
232 gen_pool_first_fit_order_align,
233 NULL);
234
235 pr_info("DMA: preallocated %zu KiB pool for atomic allocations\n",
236 atomic_pool_size / 1024);
237 return 0;
238 }
239 goto out;
240
241remove_mapping:
242 dma_common_free_remap(addr, atomic_pool_size, VM_USERMAP);
243destroy_genpool:
244 gen_pool_destroy(atomic_pool);
245 atomic_pool = NULL;
246free_page:
247 if (!dma_release_from_contiguous(NULL, page, nr_pages))
248 __free_pages(page, pool_size_order);
249out:
250 pr_err("DMA: failed to allocate %zu KiB pool for atomic coherent allocation\n",
251 atomic_pool_size / 1024);
252 return -ENOMEM;
253}
254
255/******************************************** 92/********************************************
256 * The following APIs are for dummy DMA ops * 93 * The following APIs are for dummy DMA ops *
257 ********************************************/ 94 ********************************************/
@@ -350,8 +187,7 @@ static int __init arm64_dma_init(void)
350 TAINT_CPU_OUT_OF_SPEC, 187 TAINT_CPU_OUT_OF_SPEC,
351 "ARCH_DMA_MINALIGN smaller than CTR_EL0.CWG (%d < %d)", 188 "ARCH_DMA_MINALIGN smaller than CTR_EL0.CWG (%d < %d)",
352 ARCH_DMA_MINALIGN, cache_line_size()); 189 ARCH_DMA_MINALIGN, cache_line_size());
353 190 return dma_atomic_pool_init(GFP_DMA32, __pgprot(PROT_NORMAL_NC));
354 return atomic_pool_init();
355} 191}
356arch_initcall(arm64_dma_init); 192arch_initcall(arm64_dma_init);
357 193
@@ -397,7 +233,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
397 page = alloc_pages(gfp, get_order(size)); 233 page = alloc_pages(gfp, get_order(size));
398 addr = page ? page_address(page) : NULL; 234 addr = page ? page_address(page) : NULL;
399 } else { 235 } else {
400 addr = __alloc_from_pool(size, &page, gfp); 236 addr = dma_alloc_from_pool(size, &page, gfp);
401 } 237 }
402 if (!addr) 238 if (!addr)
403 return NULL; 239 return NULL;
@@ -407,7 +243,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
407 if (coherent) 243 if (coherent)
408 __free_pages(page, get_order(size)); 244 __free_pages(page, get_order(size));
409 else 245 else
410 __free_from_pool(addr, size); 246 dma_free_from_pool(addr, size);
411 addr = NULL; 247 addr = NULL;
412 } 248 }
413 } else if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) { 249 } else if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
@@ -471,9 +307,9 @@ static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
471 * coherent devices. 307 * coherent devices.
472 * Hence how dodgy the below logic looks... 308 * Hence how dodgy the below logic looks...
473 */ 309 */
474 if (__in_atomic_pool(cpu_addr, size)) { 310 if (dma_in_atomic_pool(cpu_addr, size)) {
475 iommu_dma_unmap_page(dev, handle, iosize, 0, 0); 311 iommu_dma_unmap_page(dev, handle, iosize, 0, 0);
476 __free_from_pool(cpu_addr, size); 312 dma_free_from_pool(cpu_addr, size);
477 } else if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) { 313 } else if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
478 struct page *page = vmalloc_to_page(cpu_addr); 314 struct page *page = vmalloc_to_page(cpu_addr);
479 315
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 0f81c713f6e9..1a0edcde7d14 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -455,6 +455,11 @@ void *dma_common_pages_remap(struct page **pages, size_t size,
455 const void *caller); 455 const void *caller);
456void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags); 456void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags);
457 457
458int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot);
459bool dma_in_atomic_pool(void *start, size_t size);
460void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags);
461bool dma_free_from_pool(void *start, size_t size);
462
458/** 463/**
459 * dma_mmap_attrs - map a coherent DMA allocation into user space 464 * dma_mmap_attrs - map a coherent DMA allocation into user space
460 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices 465 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
diff --git a/include/linux/dma-noncoherent.h b/include/linux/dma-noncoherent.h
index 9051b055beec..306557331d7d 100644
--- a/include/linux/dma-noncoherent.h
+++ b/include/linux/dma-noncoherent.h
@@ -69,4 +69,6 @@ static inline void arch_sync_dma_for_cpu_all(struct device *dev)
69} 69}
70#endif /* CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL */ 70#endif /* CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL */
71 71
72void arch_dma_prep_coherent(struct page *page, size_t size);
73
72#endif /* _LINUX_DMA_NONCOHERENT_H */ 74#endif /* _LINUX_DMA_NONCOHERENT_H */
diff --git a/kernel/dma/Kconfig b/kernel/dma/Kconfig
index c92e08173ed8..41c3b1df70eb 100644
--- a/kernel/dma/Kconfig
+++ b/kernel/dma/Kconfig
@@ -55,3 +55,8 @@ config SWIOTLB
55config DMA_REMAP 55config DMA_REMAP
56 depends on MMU 56 depends on MMU
57 bool 57 bool
58
59config DMA_DIRECT_REMAP
60 bool
61 depends on DMA_DIRECT_OPS
62 select DMA_REMAP
diff --git a/kernel/dma/remap.c b/kernel/dma/remap.c
index a15c393ea4e5..b32bb08f96ae 100644
--- a/kernel/dma/remap.c
+++ b/kernel/dma/remap.c
@@ -1,8 +1,13 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: GPL-2.0
2/* 2/*
3 * Copyright (C) 2012 ARM Ltd.
3 * Copyright (c) 2014 The Linux Foundation 4 * Copyright (c) 2014 The Linux Foundation
4 */ 5 */
5#include <linux/dma-mapping.h> 6#include <linux/dma-direct.h>
7#include <linux/dma-noncoherent.h>
8#include <linux/dma-contiguous.h>
9#include <linux/init.h>
10#include <linux/genalloc.h>
6#include <linux/slab.h> 11#include <linux/slab.h>
7#include <linux/vmalloc.h> 12#include <linux/vmalloc.h>
8 13
@@ -86,3 +91,154 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
86 unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size)); 91 unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size));
87 vunmap(cpu_addr); 92 vunmap(cpu_addr);
88} 93}
94
95#ifdef CONFIG_DMA_DIRECT_REMAP
96static struct gen_pool *atomic_pool __ro_after_init;
97
98#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
99static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE;
100
101static int __init early_coherent_pool(char *p)
102{
103 atomic_pool_size = memparse(p, &p);
104 return 0;
105}
106early_param("coherent_pool", early_coherent_pool);
107
108int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot)
109{
110 unsigned int pool_size_order = get_order(atomic_pool_size);
111 unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT;
112 struct page *page;
113 void *addr;
114 int ret;
115
116 if (dev_get_cma_area(NULL))
117 page = dma_alloc_from_contiguous(NULL, nr_pages,
118 pool_size_order, false);
119 else
120 page = alloc_pages(gfp, pool_size_order);
121 if (!page)
122 goto out;
123
124 memset(page_address(page), 0, atomic_pool_size);
125 arch_dma_prep_coherent(page, atomic_pool_size);
126
127 atomic_pool = gen_pool_create(PAGE_SHIFT, -1);
128 if (!atomic_pool)
129 goto free_page;
130
131 addr = dma_common_contiguous_remap(page, atomic_pool_size, VM_USERMAP,
132 prot, __builtin_return_address(0));
133 if (!addr)
134 goto destroy_genpool;
135
136 ret = gen_pool_add_virt(atomic_pool, (unsigned long)addr,
137 page_to_phys(page), atomic_pool_size, -1);
138 if (ret)
139 goto remove_mapping;
140 gen_pool_set_algo(atomic_pool, gen_pool_first_fit_order_align, NULL);
141
142 pr_info("DMA: preallocated %zu KiB pool for atomic allocations\n",
143 atomic_pool_size / 1024);
144 return 0;
145
146remove_mapping:
147 dma_common_free_remap(addr, atomic_pool_size, VM_USERMAP);
148destroy_genpool:
149 gen_pool_destroy(atomic_pool);
150 atomic_pool = NULL;
151free_page:
152 if (!dma_release_from_contiguous(NULL, page, nr_pages))
153 __free_pages(page, pool_size_order);
154out:
155 pr_err("DMA: failed to allocate %zu KiB pool for atomic coherent allocation\n",
156 atomic_pool_size / 1024);
157 return -ENOMEM;
158}
159
160bool dma_in_atomic_pool(void *start, size_t size)
161{
162 return addr_in_gen_pool(atomic_pool, (unsigned long)start, size);
163}
164
165void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags)
166{
167 unsigned long val;
168 void *ptr = NULL;
169
170 if (!atomic_pool) {
171 WARN(1, "coherent pool not initialised!\n");
172 return NULL;
173 }
174
175 val = gen_pool_alloc(atomic_pool, size);
176 if (val) {
177 phys_addr_t phys = gen_pool_virt_to_phys(atomic_pool, val);
178
179 *ret_page = pfn_to_page(__phys_to_pfn(phys));
180 ptr = (void *)val;
181 memset(ptr, 0, size);
182 }
183
184 return ptr;
185}
186
187bool dma_free_from_pool(void *start, size_t size)
188{
189 if (!dma_in_atomic_pool(start, size))
190 return false;
191 gen_pool_free(atomic_pool, (unsigned long)start, size);
192 return true;
193}
194
195void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
196 gfp_t flags, unsigned long attrs)
197{
198 struct page *page = NULL;
199 void *ret, *kaddr;
200
201 size = PAGE_ALIGN(size);
202
203 if (!gfpflags_allow_blocking(flags)) {
204 ret = dma_alloc_from_pool(size, &page, flags);
205 if (!ret)
206 return NULL;
207 *dma_handle = phys_to_dma(dev, page_to_phys(page));
208 return ret;
209 }
210
211 kaddr = dma_direct_alloc_pages(dev, size, dma_handle, flags, attrs);
212 if (!kaddr)
213 return NULL;
214 page = virt_to_page(kaddr);
215
216 /* remove any dirty cache lines on the kernel alias */
217 arch_dma_prep_coherent(page, size);
218
219 /* create a coherent mapping */
220 ret = dma_common_contiguous_remap(page, size, VM_USERMAP,
221 arch_dma_mmap_pgprot(dev, PAGE_KERNEL, attrs),
222 __builtin_return_address(0));
223 if (!ret)
224 dma_direct_free_pages(dev, size, kaddr, *dma_handle, attrs);
225 return ret;
226}
227
228void arch_dma_free(struct device *dev, size_t size, void *vaddr,
229 dma_addr_t dma_handle, unsigned long attrs)
230{
231 if (!dma_free_from_pool(vaddr, PAGE_ALIGN(size))) {
232 void *kaddr = phys_to_virt(dma_to_phys(dev, dma_handle));
233
234 vunmap(vaddr);
235 dma_direct_free_pages(dev, size, kaddr, dma_handle, attrs);
236 }
237}
238
239long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr,
240 dma_addr_t dma_addr)
241{
242 return __phys_to_pfn(dma_to_phys(dev, dma_addr));
243}
244#endif /* CONFIG_DMA_DIRECT_REMAP */