.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
---|
3 | 4 | * Takashi Iwai <tiwai@suse.de> |
---|
4 | 5 | * |
---|
5 | 6 | * Generic memory allocators |
---|
6 | | - * |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License as published by |
---|
10 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
11 | | - * (at your option) any later version. |
---|
12 | | - * |
---|
13 | | - * This program is distributed in the hope that it will be useful, |
---|
14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
16 | | - * GNU General Public License for more details. |
---|
17 | | - * |
---|
18 | | - * You should have received a copy of the GNU General Public License |
---|
19 | | - * along with this program; if not, write to the Free Software |
---|
20 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
21 | | - * |
---|
22 | 7 | */ |
---|
23 | 8 | |
---|
24 | 9 | #include <linux/slab.h> |
---|
25 | 10 | #include <linux/mm.h> |
---|
26 | 11 | #include <linux/dma-mapping.h> |
---|
27 | 12 | #include <linux/genalloc.h> |
---|
| 13 | +#include <linux/vmalloc.h> |
---|
| 14 | +#ifdef CONFIG_X86 |
---|
| 15 | +#include <asm/set_memory.h> |
---|
| 16 | +#endif |
---|
28 | 17 | #include <sound/memalloc.h> |
---|
29 | | - |
---|
30 | | -/* |
---|
31 | | - * |
---|
32 | | - * Generic memory allocators |
---|
33 | | - * |
---|
34 | | - */ |
---|
35 | | - |
---|
36 | | -/** |
---|
37 | | - * snd_malloc_pages - allocate pages with the given size |
---|
38 | | - * @size: the size to allocate in bytes |
---|
39 | | - * @gfp_flags: the allocation conditions, GFP_XXX |
---|
40 | | - * |
---|
41 | | - * Allocates the physically contiguous pages with the given size. |
---|
42 | | - * |
---|
43 | | - * Return: The pointer of the buffer, or %NULL if no enough memory. |
---|
44 | | - */ |
---|
45 | | -void *snd_malloc_pages(size_t size, gfp_t gfp_flags) |
---|
46 | | -{ |
---|
47 | | - int pg; |
---|
48 | | - |
---|
49 | | - if (WARN_ON(!size)) |
---|
50 | | - return NULL; |
---|
51 | | - if (WARN_ON(!gfp_flags)) |
---|
52 | | - return NULL; |
---|
53 | | - gfp_flags |= __GFP_COMP; /* compound page lets parts be mapped */ |
---|
54 | | - pg = get_order(size); |
---|
55 | | - return (void *) __get_free_pages(gfp_flags, pg); |
---|
56 | | -} |
---|
57 | | -EXPORT_SYMBOL(snd_malloc_pages); |
---|
58 | | - |
---|
59 | | -/** |
---|
60 | | - * snd_free_pages - release the pages |
---|
61 | | - * @ptr: the buffer pointer to release |
---|
62 | | - * @size: the allocated buffer size |
---|
63 | | - * |
---|
64 | | - * Releases the buffer allocated via snd_malloc_pages(). |
---|
65 | | - */ |
---|
66 | | -void snd_free_pages(void *ptr, size_t size) |
---|
67 | | -{ |
---|
68 | | - int pg; |
---|
69 | | - |
---|
70 | | - if (ptr == NULL) |
---|
71 | | - return; |
---|
72 | | - pg = get_order(size); |
---|
73 | | - free_pages((unsigned long) ptr, pg); |
---|
74 | | -} |
---|
75 | | -EXPORT_SYMBOL(snd_free_pages); |
---|
76 | 18 | |
---|
77 | 19 | /* |
---|
78 | 20 | * |
---|
.. | .. |
---|
82 | 24 | |
---|
83 | 25 | #ifdef CONFIG_HAS_DMA |
---|
84 | 26 | /* allocate the coherent DMA pages */ |
---|
85 | | -static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) |
---|
| 27 | +static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size) |
---|
86 | 28 | { |
---|
87 | | - int pg; |
---|
88 | 29 | gfp_t gfp_flags; |
---|
89 | 30 | |
---|
90 | | - if (WARN_ON(!dma)) |
---|
91 | | - return NULL; |
---|
92 | | - pg = get_order(size); |
---|
93 | 31 | gfp_flags = GFP_KERNEL |
---|
94 | 32 | | __GFP_COMP /* compound page lets parts be mapped */ |
---|
95 | 33 | | __GFP_NORETRY /* don't trigger OOM-killer */ |
---|
96 | 34 | | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ |
---|
97 | | - return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags); |
---|
| 35 | + dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, |
---|
| 36 | + gfp_flags); |
---|
| 37 | +#ifdef CONFIG_X86 |
---|
| 38 | + if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) |
---|
| 39 | + set_memory_wc((unsigned long)dmab->area, |
---|
| 40 | + PAGE_ALIGN(size) >> PAGE_SHIFT); |
---|
| 41 | +#endif |
---|
98 | 42 | } |
---|
99 | 43 | |
---|
100 | 44 | /* free the coherent DMA pages */ |
---|
101 | | -static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, |
---|
102 | | - dma_addr_t dma) |
---|
| 45 | +static void snd_free_dev_pages(struct snd_dma_buffer *dmab) |
---|
103 | 46 | { |
---|
104 | | - int pg; |
---|
105 | | - |
---|
106 | | - if (ptr == NULL) |
---|
107 | | - return; |
---|
108 | | - pg = get_order(size); |
---|
109 | | - dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); |
---|
| 47 | +#ifdef CONFIG_X86 |
---|
| 48 | + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) |
---|
| 49 | + set_memory_wb((unsigned long)dmab->area, |
---|
| 50 | + PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT); |
---|
| 51 | +#endif |
---|
| 52 | + dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); |
---|
110 | 53 | } |
---|
111 | 54 | |
---|
112 | 55 | #ifdef CONFIG_GENERIC_ALLOCATOR |
---|
.. | .. |
---|
134 | 77 | /* Assign the pool into private_data field */ |
---|
135 | 78 | dmab->private_data = pool; |
---|
136 | 79 | |
---|
137 | | - dmab->area = gen_pool_dma_alloc(pool, size, &dmab->addr); |
---|
| 80 | + dmab->area = gen_pool_dma_alloc_align(pool, size, &dmab->addr, |
---|
| 81 | + PAGE_SIZE); |
---|
138 | 82 | } |
---|
139 | 83 | |
---|
140 | 84 | /** |
---|
.. | .. |
---|
157 | 101 | * |
---|
158 | 102 | */ |
---|
159 | 103 | |
---|
| 104 | +static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev, |
---|
| 105 | + gfp_t default_gfp) |
---|
| 106 | +{ |
---|
| 107 | + if (!dev) |
---|
| 108 | + return default_gfp; |
---|
| 109 | + else |
---|
| 110 | + return (__force gfp_t)(unsigned long)dev; |
---|
| 111 | +} |
---|
160 | 112 | |
---|
161 | 113 | /** |
---|
162 | 114 | * snd_dma_alloc_pages - allocate the buffer area according to the given type |
---|
.. | .. |
---|
174 | 126 | int snd_dma_alloc_pages(int type, struct device *device, size_t size, |
---|
175 | 127 | struct snd_dma_buffer *dmab) |
---|
176 | 128 | { |
---|
| 129 | + gfp_t gfp; |
---|
| 130 | + |
---|
177 | 131 | if (WARN_ON(!size)) |
---|
178 | 132 | return -ENXIO; |
---|
179 | 133 | if (WARN_ON(!dmab)) |
---|
180 | 134 | return -ENXIO; |
---|
181 | 135 | |
---|
| 136 | + size = PAGE_ALIGN(size); |
---|
182 | 137 | dmab->dev.type = type; |
---|
183 | 138 | dmab->dev.dev = device; |
---|
184 | 139 | dmab->bytes = 0; |
---|
| 140 | + dmab->area = NULL; |
---|
| 141 | + dmab->addr = 0; |
---|
| 142 | + dmab->private_data = NULL; |
---|
185 | 143 | switch (type) { |
---|
186 | 144 | case SNDRV_DMA_TYPE_CONTINUOUS: |
---|
187 | | - dmab->area = snd_malloc_pages(size, |
---|
188 | | - (__force gfp_t)(unsigned long)device); |
---|
189 | | - dmab->addr = 0; |
---|
| 145 | + gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL); |
---|
| 146 | + dmab->area = alloc_pages_exact(size, gfp); |
---|
| 147 | + break; |
---|
| 148 | + case SNDRV_DMA_TYPE_VMALLOC: |
---|
| 149 | + gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL | __GFP_HIGHMEM); |
---|
| 150 | + dmab->area = __vmalloc(size, gfp); |
---|
190 | 151 | break; |
---|
191 | 152 | #ifdef CONFIG_HAS_DMA |
---|
192 | 153 | #ifdef CONFIG_GENERIC_ALLOCATOR |
---|
.. | .. |
---|
198 | 159 | * so if we fail to malloc, try to fetch memory traditionally. |
---|
199 | 160 | */ |
---|
200 | 161 | dmab->dev.type = SNDRV_DMA_TYPE_DEV; |
---|
| 162 | + fallthrough; |
---|
201 | 163 | #endif /* CONFIG_GENERIC_ALLOCATOR */ |
---|
202 | 164 | case SNDRV_DMA_TYPE_DEV: |
---|
203 | | - dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); |
---|
| 165 | + case SNDRV_DMA_TYPE_DEV_UC: |
---|
| 166 | + snd_malloc_dev_pages(dmab, size); |
---|
204 | 167 | break; |
---|
205 | 168 | #endif |
---|
206 | 169 | #ifdef CONFIG_SND_DMA_SGBUF |
---|
207 | 170 | case SNDRV_DMA_TYPE_DEV_SG: |
---|
| 171 | + case SNDRV_DMA_TYPE_DEV_UC_SG: |
---|
208 | 172 | snd_malloc_sgbuf_pages(device, size, dmab, NULL); |
---|
209 | 173 | break; |
---|
210 | 174 | #endif |
---|
211 | 175 | default: |
---|
212 | 176 | pr_err("snd-malloc: invalid device type %d\n", type); |
---|
213 | | - dmab->area = NULL; |
---|
214 | | - dmab->addr = 0; |
---|
215 | 177 | return -ENXIO; |
---|
216 | 178 | } |
---|
217 | 179 | if (! dmab->area) |
---|
.. | .. |
---|
266 | 228 | { |
---|
267 | 229 | switch (dmab->dev.type) { |
---|
268 | 230 | case SNDRV_DMA_TYPE_CONTINUOUS: |
---|
269 | | - snd_free_pages(dmab->area, dmab->bytes); |
---|
| 231 | + free_pages_exact(dmab->area, dmab->bytes); |
---|
| 232 | + break; |
---|
| 233 | + case SNDRV_DMA_TYPE_VMALLOC: |
---|
| 234 | + vfree(dmab->area); |
---|
270 | 235 | break; |
---|
271 | 236 | #ifdef CONFIG_HAS_DMA |
---|
272 | 237 | #ifdef CONFIG_GENERIC_ALLOCATOR |
---|
.. | .. |
---|
275 | 240 | break; |
---|
276 | 241 | #endif /* CONFIG_GENERIC_ALLOCATOR */ |
---|
277 | 242 | case SNDRV_DMA_TYPE_DEV: |
---|
278 | | - snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); |
---|
| 243 | + case SNDRV_DMA_TYPE_DEV_UC: |
---|
| 244 | + snd_free_dev_pages(dmab); |
---|
279 | 245 | break; |
---|
280 | 246 | #endif |
---|
281 | 247 | #ifdef CONFIG_SND_DMA_SGBUF |
---|
282 | 248 | case SNDRV_DMA_TYPE_DEV_SG: |
---|
| 249 | + case SNDRV_DMA_TYPE_DEV_UC_SG: |
---|
283 | 250 | snd_free_sgbuf_pages(dmab); |
---|
284 | 251 | break; |
---|
285 | 252 | #endif |
---|