diff options
Diffstat (limited to 'arch/arm64/mm/dma-mapping.c')
-rw-r--r-- | arch/arm64/mm/dma-mapping.c | 195 |
1 files changed, 145 insertions, 50 deletions
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 4164c5ace9f8..d92094203913 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c | |||
@@ -20,13 +20,11 @@ | |||
20 | #include <linux/gfp.h> | 20 | #include <linux/gfp.h> |
21 | #include <linux/export.h> | 21 | #include <linux/export.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/genalloc.h> | ||
23 | #include <linux/dma-mapping.h> | 24 | #include <linux/dma-mapping.h> |
24 | #include <linux/dma-contiguous.h> | 25 | #include <linux/dma-contiguous.h> |
25 | #include <linux/of.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/vmalloc.h> | 26 | #include <linux/vmalloc.h> |
28 | #include <linux/swiotlb.h> | 27 | #include <linux/swiotlb.h> |
29 | #include <linux/amba/bus.h> | ||
30 | 28 | ||
31 | #include <asm/cacheflush.h> | 29 | #include <asm/cacheflush.h> |
32 | 30 | ||
@@ -41,6 +39,54 @@ static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot, | |||
41 | return prot; | 39 | return prot; |
42 | } | 40 | } |
43 | 41 | ||
42 | static struct gen_pool *atomic_pool; | ||
43 | |||
44 | #define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K | ||
45 | static size_t atomic_pool_size = DEFAULT_DMA_COHERENT_POOL_SIZE; | ||
46 | |||
47 | static int __init early_coherent_pool(char *p) | ||
48 | { | ||
49 | atomic_pool_size = memparse(p, &p); | ||
50 | return 0; | ||
51 | } | ||
52 | early_param("coherent_pool", early_coherent_pool); | ||
53 | |||
54 | static void *__alloc_from_pool(size_t size, struct page **ret_page) | ||
55 | { | ||
56 | unsigned long val; | ||
57 | void *ptr = NULL; | ||
58 | |||
59 | if (!atomic_pool) { | ||
60 | WARN(1, "coherent pool not initialised!\n"); | ||
61 | return NULL; | ||
62 | } | ||
63 | |||
64 | val = gen_pool_alloc(atomic_pool, size); | ||
65 | if (val) { | ||
66 | phys_addr_t phys = gen_pool_virt_to_phys(atomic_pool, val); | ||
67 | |||
68 | *ret_page = phys_to_page(phys); | ||
69 | ptr = (void *)val; | ||
70 | } | ||
71 | |||
72 | return ptr; | ||
73 | } | ||
74 | |||
75 | static bool __in_atomic_pool(void *start, size_t size) | ||
76 | { | ||
77 | return addr_in_gen_pool(atomic_pool, (unsigned long)start, size); | ||
78 | } | ||
79 | |||
80 | static int __free_from_pool(void *start, size_t size) | ||
81 | { | ||
82 | if (!__in_atomic_pool(start, size)) | ||
83 | return 0; | ||
84 | |||
85 | gen_pool_free(atomic_pool, (unsigned long)start, size); | ||
86 | |||
87 | return 1; | ||
88 | } | ||
89 | |||
44 | static void *__dma_alloc_coherent(struct device *dev, size_t size, | 90 | static void *__dma_alloc_coherent(struct device *dev, size_t size, |
45 | dma_addr_t *dma_handle, gfp_t flags, | 91 | dma_addr_t *dma_handle, gfp_t flags, |
46 | struct dma_attrs *attrs) | 92 | struct dma_attrs *attrs) |
@@ -53,7 +99,7 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size, | |||
53 | if (IS_ENABLED(CONFIG_ZONE_DMA) && | 99 | if (IS_ENABLED(CONFIG_ZONE_DMA) && |
54 | dev->coherent_dma_mask <= DMA_BIT_MASK(32)) | 100 | dev->coherent_dma_mask <= DMA_BIT_MASK(32)) |
55 | flags |= GFP_DMA; | 101 | flags |= GFP_DMA; |
56 | if (IS_ENABLED(CONFIG_DMA_CMA)) { | 102 | if (IS_ENABLED(CONFIG_DMA_CMA) && (flags & __GFP_WAIT)) { |
57 | struct page *page; | 103 | struct page *page; |
58 | 104 | ||
59 | size = PAGE_ALIGN(size); | 105 | size = PAGE_ALIGN(size); |
@@ -73,50 +119,54 @@ static void __dma_free_coherent(struct device *dev, size_t size, | |||
73 | void *vaddr, dma_addr_t dma_handle, | 119 | void *vaddr, dma_addr_t dma_handle, |
74 | struct dma_attrs *attrs) | 120 | struct dma_attrs *attrs) |
75 | { | 121 | { |
122 | bool freed; | ||
123 | phys_addr_t paddr = dma_to_phys(dev, dma_handle); | ||
124 | |||
76 | if (dev == NULL) { | 125 | if (dev == NULL) { |
77 | WARN_ONCE(1, "Use an actual device structure for DMA allocation\n"); | 126 | WARN_ONCE(1, "Use an actual device structure for DMA allocation\n"); |
78 | return; | 127 | return; |
79 | } | 128 | } |
80 | 129 | ||
81 | if (IS_ENABLED(CONFIG_DMA_CMA)) { | 130 | freed = dma_release_from_contiguous(dev, |
82 | phys_addr_t paddr = dma_to_phys(dev, dma_handle); | ||
83 | |||
84 | dma_release_from_contiguous(dev, | ||
85 | phys_to_page(paddr), | 131 | phys_to_page(paddr), |
86 | size >> PAGE_SHIFT); | 132 | size >> PAGE_SHIFT); |
87 | } else { | 133 | if (!freed) |
88 | swiotlb_free_coherent(dev, size, vaddr, dma_handle); | 134 | swiotlb_free_coherent(dev, size, vaddr, dma_handle); |
89 | } | ||
90 | } | 135 | } |
91 | 136 | ||
92 | static void *__dma_alloc_noncoherent(struct device *dev, size_t size, | 137 | static void *__dma_alloc_noncoherent(struct device *dev, size_t size, |
93 | dma_addr_t *dma_handle, gfp_t flags, | 138 | dma_addr_t *dma_handle, gfp_t flags, |
94 | struct dma_attrs *attrs) | 139 | struct dma_attrs *attrs) |
95 | { | 140 | { |
96 | struct page *page, **map; | 141 | struct page *page; |
97 | void *ptr, *coherent_ptr; | 142 | void *ptr, *coherent_ptr; |
98 | int order, i; | ||
99 | 143 | ||
100 | size = PAGE_ALIGN(size); | 144 | size = PAGE_ALIGN(size); |
101 | order = get_order(size); | 145 | |
146 | if (!(flags & __GFP_WAIT)) { | ||
147 | struct page *page = NULL; | ||
148 | void *addr = __alloc_from_pool(size, &page); | ||
149 | |||
150 | if (addr) | ||
151 | *dma_handle = phys_to_dma(dev, page_to_phys(page)); | ||
152 | |||
153 | return addr; | ||
154 | |||
155 | } | ||
102 | 156 | ||
103 | ptr = __dma_alloc_coherent(dev, size, dma_handle, flags, attrs); | 157 | ptr = __dma_alloc_coherent(dev, size, dma_handle, flags, attrs); |
104 | if (!ptr) | 158 | if (!ptr) |
105 | goto no_mem; | 159 | goto no_mem; |
106 | map = kmalloc(sizeof(struct page *) << order, flags & ~GFP_DMA); | ||
107 | if (!map) | ||
108 | goto no_map; | ||
109 | 160 | ||
110 | /* remove any dirty cache lines on the kernel alias */ | 161 | /* remove any dirty cache lines on the kernel alias */ |
111 | __dma_flush_range(ptr, ptr + size); | 162 | __dma_flush_range(ptr, ptr + size); |
112 | 163 | ||
113 | /* create a coherent mapping */ | 164 | /* create a coherent mapping */ |
114 | page = virt_to_page(ptr); | 165 | page = virt_to_page(ptr); |
115 | for (i = 0; i < (size >> PAGE_SHIFT); i++) | 166 | coherent_ptr = dma_common_contiguous_remap(page, size, VM_USERMAP, |
116 | map[i] = page + i; | 167 | __get_dma_pgprot(attrs, |
117 | coherent_ptr = vmap(map, size >> PAGE_SHIFT, VM_MAP, | 168 | __pgprot(PROT_NORMAL_NC), false), |
118 | __get_dma_pgprot(attrs, __pgprot(PROT_NORMAL_NC), false)); | 169 | NULL); |
119 | kfree(map); | ||
120 | if (!coherent_ptr) | 170 | if (!coherent_ptr) |
121 | goto no_map; | 171 | goto no_map; |
122 | 172 | ||
@@ -125,7 +175,7 @@ static void *__dma_alloc_noncoherent(struct device *dev, size_t size, | |||
125 | no_map: | 175 | no_map: |
126 | __dma_free_coherent(dev, size, ptr, *dma_handle, attrs); | 176 | __dma_free_coherent(dev, size, ptr, *dma_handle, attrs); |
127 | no_mem: | 177 | no_mem: |
128 | *dma_handle = ~0; | 178 | *dma_handle = DMA_ERROR_CODE; |
129 | return NULL; | 179 | return NULL; |
130 | } | 180 | } |
131 | 181 | ||
@@ -135,6 +185,8 @@ static void __dma_free_noncoherent(struct device *dev, size_t size, | |||
135 | { | 185 | { |
136 | void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle)); | 186 | void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle)); |
137 | 187 | ||
188 | if (__free_from_pool(vaddr, size)) | ||
189 | return; | ||
138 | vunmap(vaddr); | 190 | vunmap(vaddr); |
139 | __dma_free_coherent(dev, size, swiotlb_addr, dma_handle, attrs); | 191 | __dma_free_coherent(dev, size, swiotlb_addr, dma_handle, attrs); |
140 | } | 192 | } |
@@ -308,45 +360,88 @@ struct dma_map_ops coherent_swiotlb_dma_ops = { | |||
308 | }; | 360 | }; |
309 | EXPORT_SYMBOL(coherent_swiotlb_dma_ops); | 361 | EXPORT_SYMBOL(coherent_swiotlb_dma_ops); |
310 | 362 | ||
311 | static int dma_bus_notifier(struct notifier_block *nb, | 363 | extern int swiotlb_late_init_with_default_size(size_t default_size); |
312 | unsigned long event, void *_dev) | ||
313 | { | ||
314 | struct device *dev = _dev; | ||
315 | |||
316 | if (event != BUS_NOTIFY_ADD_DEVICE) | ||
317 | return NOTIFY_DONE; | ||
318 | |||
319 | if (of_property_read_bool(dev->of_node, "dma-coherent")) | ||
320 | set_dma_ops(dev, &coherent_swiotlb_dma_ops); | ||
321 | 364 | ||
322 | return NOTIFY_OK; | 365 | static int __init atomic_pool_init(void) |
366 | { | ||
367 | pgprot_t prot = __pgprot(PROT_NORMAL_NC); | ||
368 | unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT; | ||
369 | struct page *page; | ||
370 | void *addr; | ||
371 | unsigned int pool_size_order = get_order(atomic_pool_size); | ||
372 | |||
373 | if (dev_get_cma_area(NULL)) | ||
374 | page = dma_alloc_from_contiguous(NULL, nr_pages, | ||
375 | pool_size_order); | ||
376 | else | ||
377 | page = alloc_pages(GFP_DMA, pool_size_order); | ||
378 | |||
379 | if (page) { | ||
380 | int ret; | ||
381 | void *page_addr = page_address(page); | ||
382 | |||
383 | memset(page_addr, 0, atomic_pool_size); | ||
384 | __dma_flush_range(page_addr, page_addr + atomic_pool_size); | ||
385 | |||
386 | atomic_pool = gen_pool_create(PAGE_SHIFT, -1); | ||
387 | if (!atomic_pool) | ||
388 | goto free_page; | ||
389 | |||
390 | addr = dma_common_contiguous_remap(page, atomic_pool_size, | ||
391 | VM_USERMAP, prot, atomic_pool_init); | ||
392 | |||
393 | if (!addr) | ||
394 | goto destroy_genpool; | ||
395 | |||
396 | ret = gen_pool_add_virt(atomic_pool, (unsigned long)addr, | ||
397 | page_to_phys(page), | ||
398 | atomic_pool_size, -1); | ||
399 | if (ret) | ||
400 | goto remove_mapping; | ||
401 | |||
402 | gen_pool_set_algo(atomic_pool, | ||
403 | gen_pool_first_fit_order_align, | ||
404 | (void *)PAGE_SHIFT); | ||
405 | |||
406 | pr_info("DMA: preallocated %zu KiB pool for atomic allocations\n", | ||
407 | atomic_pool_size / 1024); | ||
408 | return 0; | ||
409 | } | ||
410 | goto out; | ||
411 | |||
412 | remove_mapping: | ||
413 | dma_common_free_remap(addr, atomic_pool_size, VM_USERMAP); | ||
414 | destroy_genpool: | ||
415 | gen_pool_destroy(atomic_pool); | ||
416 | atomic_pool = NULL; | ||
417 | free_page: | ||
418 | if (!dma_release_from_contiguous(NULL, page, nr_pages)) | ||
419 | __free_pages(page, pool_size_order); | ||
420 | out: | ||
421 | pr_err("DMA: failed to allocate %zu KiB pool for atomic coherent allocation\n", | ||
422 | atomic_pool_size / 1024); | ||
423 | return -ENOMEM; | ||
323 | } | 424 | } |
324 | 425 | ||
325 | static struct notifier_block platform_bus_nb = { | ||
326 | .notifier_call = dma_bus_notifier, | ||
327 | }; | ||
328 | |||
329 | static struct notifier_block amba_bus_nb = { | ||
330 | .notifier_call = dma_bus_notifier, | ||
331 | }; | ||
332 | |||
333 | extern int swiotlb_late_init_with_default_size(size_t default_size); | ||
334 | |||
335 | static int __init swiotlb_late_init(void) | 426 | static int __init swiotlb_late_init(void) |
336 | { | 427 | { |
337 | size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT); | 428 | size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT); |
338 | 429 | ||
339 | /* | ||
340 | * These must be registered before of_platform_populate(). | ||
341 | */ | ||
342 | bus_register_notifier(&platform_bus_type, &platform_bus_nb); | ||
343 | bus_register_notifier(&amba_bustype, &amba_bus_nb); | ||
344 | |||
345 | dma_ops = &noncoherent_swiotlb_dma_ops; | 430 | dma_ops = &noncoherent_swiotlb_dma_ops; |
346 | 431 | ||
347 | return swiotlb_late_init_with_default_size(swiotlb_size); | 432 | return swiotlb_late_init_with_default_size(swiotlb_size); |
348 | } | 433 | } |
349 | arch_initcall(swiotlb_late_init); | 434 | |
435 | static int __init arm64_dma_init(void) | ||
436 | { | ||
437 | int ret = 0; | ||
438 | |||
439 | ret |= swiotlb_late_init(); | ||
440 | ret |= atomic_pool_init(); | ||
441 | |||
442 | return ret; | ||
443 | } | ||
444 | arch_initcall(arm64_dma_init); | ||
350 | 445 | ||
351 | #define PREALLOC_DMA_DEBUG_ENTRIES 4096 | 446 | #define PREALLOC_DMA_DEBUG_ENTRIES 4096 |
352 | 447 | ||