diff options
Diffstat (limited to 'kernel/dma/contiguous.c')
-rw-r--r-- | kernel/dma/contiguous.c | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c new file mode 100644 index 000000000000..d987dcd1bd56 --- /dev/null +++ b/kernel/dma/contiguous.c | |||
@@ -0,0 +1,278 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | /* | ||
3 | * Contiguous Memory Allocator for DMA mapping framework | ||
4 | * Copyright (c) 2010-2011 by Samsung Electronics. | ||
5 | * Written by: | ||
6 | * Marek Szyprowski <m.szyprowski@samsung.com> | ||
7 | * Michal Nazarewicz <mina86@mina86.com> | ||
8 | */ | ||
9 | |||
10 | #define pr_fmt(fmt) "cma: " fmt | ||
11 | |||
12 | #ifdef CONFIG_CMA_DEBUG | ||
13 | #ifndef DEBUG | ||
14 | # define DEBUG | ||
15 | #endif | ||
16 | #endif | ||
17 | |||
18 | #include <asm/page.h> | ||
19 | #include <asm/dma-contiguous.h> | ||
20 | |||
21 | #include <linux/memblock.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/sizes.h> | ||
24 | #include <linux/dma-contiguous.h> | ||
25 | #include <linux/cma.h> | ||
26 | |||
27 | #ifdef CONFIG_CMA_SIZE_MBYTES | ||
28 | #define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES | ||
29 | #else | ||
30 | #define CMA_SIZE_MBYTES 0 | ||
31 | #endif | ||
32 | |||
33 | struct cma *dma_contiguous_default_area; | ||
34 | |||
35 | /* | ||
36 | * Default global CMA area size can be defined in kernel's .config. | ||
37 | * This is useful mainly for distro maintainers to create a kernel | ||
38 | * that works correctly for most supported systems. | ||
39 | * The size can be set in bytes or as a percentage of the total memory | ||
40 | * in the system. | ||
41 | * | ||
42 | * Users, who want to set the size of global CMA area for their system | ||
43 | * should use cma= kernel parameter. | ||
44 | */ | ||
45 | static const phys_addr_t size_bytes = (phys_addr_t)CMA_SIZE_MBYTES * SZ_1M; | ||
46 | static phys_addr_t size_cmdline = -1; | ||
47 | static phys_addr_t base_cmdline; | ||
48 | static phys_addr_t limit_cmdline; | ||
49 | |||
50 | static int __init early_cma(char *p) | ||
51 | { | ||
52 | pr_debug("%s(%s)\n", __func__, p); | ||
53 | size_cmdline = memparse(p, &p); | ||
54 | if (*p != '@') | ||
55 | return 0; | ||
56 | base_cmdline = memparse(p + 1, &p); | ||
57 | if (*p != '-') { | ||
58 | limit_cmdline = base_cmdline + size_cmdline; | ||
59 | return 0; | ||
60 | } | ||
61 | limit_cmdline = memparse(p + 1, &p); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | early_param("cma", early_cma); | ||
66 | |||
67 | #ifdef CONFIG_CMA_SIZE_PERCENTAGE | ||
68 | |||
69 | static phys_addr_t __init __maybe_unused cma_early_percent_memory(void) | ||
70 | { | ||
71 | struct memblock_region *reg; | ||
72 | unsigned long total_pages = 0; | ||
73 | |||
74 | /* | ||
75 | * We cannot use memblock_phys_mem_size() here, because | ||
76 | * memblock_analyze() has not been called yet. | ||
77 | */ | ||
78 | for_each_memblock(memory, reg) | ||
79 | total_pages += memblock_region_memory_end_pfn(reg) - | ||
80 | memblock_region_memory_base_pfn(reg); | ||
81 | |||
82 | return (total_pages * CONFIG_CMA_SIZE_PERCENTAGE / 100) << PAGE_SHIFT; | ||
83 | } | ||
84 | |||
85 | #else | ||
86 | |||
87 | static inline __maybe_unused phys_addr_t cma_early_percent_memory(void) | ||
88 | { | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | #endif | ||
93 | |||
94 | /** | ||
95 | * dma_contiguous_reserve() - reserve area(s) for contiguous memory handling | ||
96 | * @limit: End address of the reserved memory (optional, 0 for any). | ||
97 | * | ||
98 | * This function reserves memory from early allocator. It should be | ||
99 | * called by arch specific code once the early allocator (memblock or bootmem) | ||
100 | * has been activated and all other subsystems have already allocated/reserved | ||
101 | * memory. | ||
102 | */ | ||
103 | void __init dma_contiguous_reserve(phys_addr_t limit) | ||
104 | { | ||
105 | phys_addr_t selected_size = 0; | ||
106 | phys_addr_t selected_base = 0; | ||
107 | phys_addr_t selected_limit = limit; | ||
108 | bool fixed = false; | ||
109 | |||
110 | pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit); | ||
111 | |||
112 | if (size_cmdline != -1) { | ||
113 | selected_size = size_cmdline; | ||
114 | selected_base = base_cmdline; | ||
115 | selected_limit = min_not_zero(limit_cmdline, limit); | ||
116 | if (base_cmdline + size_cmdline == limit_cmdline) | ||
117 | fixed = true; | ||
118 | } else { | ||
119 | #ifdef CONFIG_CMA_SIZE_SEL_MBYTES | ||
120 | selected_size = size_bytes; | ||
121 | #elif defined(CONFIG_CMA_SIZE_SEL_PERCENTAGE) | ||
122 | selected_size = cma_early_percent_memory(); | ||
123 | #elif defined(CONFIG_CMA_SIZE_SEL_MIN) | ||
124 | selected_size = min(size_bytes, cma_early_percent_memory()); | ||
125 | #elif defined(CONFIG_CMA_SIZE_SEL_MAX) | ||
126 | selected_size = max(size_bytes, cma_early_percent_memory()); | ||
127 | #endif | ||
128 | } | ||
129 | |||
130 | if (selected_size && !dma_contiguous_default_area) { | ||
131 | pr_debug("%s: reserving %ld MiB for global area\n", __func__, | ||
132 | (unsigned long)selected_size / SZ_1M); | ||
133 | |||
134 | dma_contiguous_reserve_area(selected_size, selected_base, | ||
135 | selected_limit, | ||
136 | &dma_contiguous_default_area, | ||
137 | fixed); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | /** | ||
142 | * dma_contiguous_reserve_area() - reserve custom contiguous area | ||
143 | * @size: Size of the reserved area (in bytes), | ||
144 | * @base: Base address of the reserved area optional, use 0 for any | ||
145 | * @limit: End address of the reserved memory (optional, 0 for any). | ||
146 | * @res_cma: Pointer to store the created cma region. | ||
147 | * @fixed: hint about where to place the reserved area | ||
148 | * | ||
149 | * This function reserves memory from early allocator. It should be | ||
150 | * called by arch specific code once the early allocator (memblock or bootmem) | ||
151 | * has been activated and all other subsystems have already allocated/reserved | ||
152 | * memory. This function allows to create custom reserved areas for specific | ||
153 | * devices. | ||
154 | * | ||
155 | * If @fixed is true, reserve contiguous area at exactly @base. If false, | ||
156 | * reserve in range from @base to @limit. | ||
157 | */ | ||
158 | int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, | ||
159 | phys_addr_t limit, struct cma **res_cma, | ||
160 | bool fixed) | ||
161 | { | ||
162 | int ret; | ||
163 | |||
164 | ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed, | ||
165 | "reserved", res_cma); | ||
166 | if (ret) | ||
167 | return ret; | ||
168 | |||
169 | /* Architecture specific contiguous memory fixup. */ | ||
170 | dma_contiguous_early_fixup(cma_get_base(*res_cma), | ||
171 | cma_get_size(*res_cma)); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * dma_alloc_from_contiguous() - allocate pages from contiguous area | ||
178 | * @dev: Pointer to device for which the allocation is performed. | ||
179 | * @count: Requested number of pages. | ||
180 | * @align: Requested alignment of pages (in PAGE_SIZE order). | ||
181 | * @gfp_mask: GFP flags to use for this allocation. | ||
182 | * | ||
183 | * This function allocates memory buffer for specified device. It uses | ||
184 | * device specific contiguous memory area if available or the default | ||
185 | * global one. Requires architecture specific dev_get_cma_area() helper | ||
186 | * function. | ||
187 | */ | ||
188 | struct page *dma_alloc_from_contiguous(struct device *dev, size_t count, | ||
189 | unsigned int align, gfp_t gfp_mask) | ||
190 | { | ||
191 | if (align > CONFIG_CMA_ALIGNMENT) | ||
192 | align = CONFIG_CMA_ALIGNMENT; | ||
193 | |||
194 | return cma_alloc(dev_get_cma_area(dev), count, align, gfp_mask); | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * dma_release_from_contiguous() - release allocated pages | ||
199 | * @dev: Pointer to device for which the pages were allocated. | ||
200 | * @pages: Allocated pages. | ||
201 | * @count: Number of allocated pages. | ||
202 | * | ||
203 | * This function releases memory allocated by dma_alloc_from_contiguous(). | ||
204 | * It returns false when provided pages do not belong to contiguous area and | ||
205 | * true otherwise. | ||
206 | */ | ||
207 | bool dma_release_from_contiguous(struct device *dev, struct page *pages, | ||
208 | int count) | ||
209 | { | ||
210 | return cma_release(dev_get_cma_area(dev), pages, count); | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * Support for reserved memory regions defined in device tree | ||
215 | */ | ||
216 | #ifdef CONFIG_OF_RESERVED_MEM | ||
217 | #include <linux/of.h> | ||
218 | #include <linux/of_fdt.h> | ||
219 | #include <linux/of_reserved_mem.h> | ||
220 | |||
221 | #undef pr_fmt | ||
222 | #define pr_fmt(fmt) fmt | ||
223 | |||
224 | static int rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev) | ||
225 | { | ||
226 | dev_set_cma_area(dev, rmem->priv); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static void rmem_cma_device_release(struct reserved_mem *rmem, | ||
231 | struct device *dev) | ||
232 | { | ||
233 | dev_set_cma_area(dev, NULL); | ||
234 | } | ||
235 | |||
236 | static const struct reserved_mem_ops rmem_cma_ops = { | ||
237 | .device_init = rmem_cma_device_init, | ||
238 | .device_release = rmem_cma_device_release, | ||
239 | }; | ||
240 | |||
241 | static int __init rmem_cma_setup(struct reserved_mem *rmem) | ||
242 | { | ||
243 | phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order); | ||
244 | phys_addr_t mask = align - 1; | ||
245 | unsigned long node = rmem->fdt_node; | ||
246 | struct cma *cma; | ||
247 | int err; | ||
248 | |||
249 | if (!of_get_flat_dt_prop(node, "reusable", NULL) || | ||
250 | of_get_flat_dt_prop(node, "no-map", NULL)) | ||
251 | return -EINVAL; | ||
252 | |||
253 | if ((rmem->base & mask) || (rmem->size & mask)) { | ||
254 | pr_err("Reserved memory: incorrect alignment of CMA region\n"); | ||
255 | return -EINVAL; | ||
256 | } | ||
257 | |||
258 | err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma); | ||
259 | if (err) { | ||
260 | pr_err("Reserved memory: unable to setup CMA region\n"); | ||
261 | return err; | ||
262 | } | ||
263 | /* Architecture specific contiguous memory fixup. */ | ||
264 | dma_contiguous_early_fixup(rmem->base, rmem->size); | ||
265 | |||
266 | if (of_get_flat_dt_prop(node, "linux,cma-default", NULL)) | ||
267 | dma_contiguous_set_default(cma); | ||
268 | |||
269 | rmem->ops = &rmem_cma_ops; | ||
270 | rmem->priv = cma; | ||
271 | |||
272 | pr_info("Reserved memory: created CMA memory pool at %pa, size %ld MiB\n", | ||
273 | &rmem->base, (unsigned long)rmem->size / SZ_1M); | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup); | ||
278 | #endif | ||