Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
c1017a4c | 2 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
1da177e4 LT |
3 | * Takashi Iwai <tiwai@suse.de> |
4 | * | |
5 | * 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 | */ | |
23 | ||
1da177e4 LT |
24 | #include <linux/slab.h> |
25 | #include <linux/mm.h> | |
26 | #include <linux/dma-mapping.h> | |
05503214 | 27 | #include <linux/genalloc.h> |
1da177e4 | 28 | #include <sound/memalloc.h> |
1da177e4 | 29 | |
1da177e4 LT |
30 | /* |
31 | * | |
32 | * Generic memory allocators | |
33 | * | |
34 | */ | |
35 | ||
1da177e4 LT |
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 | * | |
eb7c06e8 | 43 | * Return: The pointer of the buffer, or %NULL if no enough memory. |
1da177e4 | 44 | */ |
1ef64e67 | 45 | void *snd_malloc_pages(size_t size, gfp_t gfp_flags) |
1da177e4 LT |
46 | { |
47 | int pg; | |
1da177e4 | 48 | |
7eaa943c TI |
49 | if (WARN_ON(!size)) |
50 | return NULL; | |
51 | if (WARN_ON(!gfp_flags)) | |
52 | return NULL; | |
f3d48f03 | 53 | gfp_flags |= __GFP_COMP; /* compound page lets parts be mapped */ |
1da177e4 | 54 | pg = get_order(size); |
d7b13541 | 55 | return (void *) __get_free_pages(gfp_flags, pg); |
1da177e4 LT |
56 | } |
57 | ||
58 | /** | |
59 | * snd_free_pages - release the pages | |
60 | * @ptr: the buffer pointer to release | |
61 | * @size: the allocated buffer size | |
62 | * | |
63 | * Releases the buffer allocated via snd_malloc_pages(). | |
64 | */ | |
65 | void snd_free_pages(void *ptr, size_t size) | |
66 | { | |
67 | int pg; | |
68 | ||
69 | if (ptr == NULL) | |
70 | return; | |
71 | pg = get_order(size); | |
1da177e4 LT |
72 | free_pages((unsigned long) ptr, pg); |
73 | } | |
74 | ||
75 | /* | |
76 | * | |
77 | * Bus-specific memory allocators | |
78 | * | |
79 | */ | |
80 | ||
8f11551b | 81 | #ifdef CONFIG_HAS_DMA |
1da177e4 LT |
82 | /* allocate the coherent DMA pages */ |
83 | static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) | |
84 | { | |
85 | int pg; | |
1ef64e67 | 86 | gfp_t gfp_flags; |
1da177e4 | 87 | |
7eaa943c TI |
88 | if (WARN_ON(!dma)) |
89 | return NULL; | |
1da177e4 LT |
90 | pg = get_order(size); |
91 | gfp_flags = GFP_KERNEL | |
f3d48f03 | 92 | | __GFP_COMP /* compound page lets parts be mapped */ |
1da177e4 LT |
93 | | __GFP_NORETRY /* don't trigger OOM-killer */ |
94 | | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ | |
d7b13541 | 95 | return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags); |
1da177e4 LT |
96 | } |
97 | ||
98 | /* free the coherent DMA pages */ | |
99 | static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, | |
100 | dma_addr_t dma) | |
101 | { | |
102 | int pg; | |
103 | ||
104 | if (ptr == NULL) | |
105 | return; | |
106 | pg = get_order(size); | |
1da177e4 LT |
107 | dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); |
108 | } | |
05503214 | 109 | |
63437313 | 110 | #ifdef CONFIG_GENERIC_ALLOCATOR |
05503214 NC |
111 | /** |
112 | * snd_malloc_dev_iram - allocate memory from on-chip internal ram | |
113 | * @dmab: buffer allocation record to store the allocated data | |
114 | * @size: number of bytes to allocate from the iram | |
115 | * | |
116 | * This function requires iram phandle provided via of_node | |
117 | */ | |
9f694bc7 | 118 | static void snd_malloc_dev_iram(struct snd_dma_buffer *dmab, size_t size) |
05503214 NC |
119 | { |
120 | struct device *dev = dmab->dev.dev; | |
121 | struct gen_pool *pool = NULL; | |
122 | ||
a40a3937 TI |
123 | dmab->area = NULL; |
124 | dmab->addr = 0; | |
125 | ||
05503214 NC |
126 | if (dev->of_node) |
127 | pool = of_get_named_gen_pool(dev->of_node, "iram", 0); | |
128 | ||
129 | if (!pool) | |
130 | return; | |
131 | ||
132 | /* Assign the pool into private_data field */ | |
133 | dmab->private_data = pool; | |
134 | ||
07968fe4 | 135 | dmab->area = gen_pool_dma_alloc(pool, size, &dmab->addr); |
05503214 NC |
136 | } |
137 | ||
138 | /** | |
139 | * snd_free_dev_iram - free allocated specific memory from on-chip internal ram | |
140 | * @dmab: buffer allocation record to store the allocated data | |
141 | */ | |
9f694bc7 | 142 | static void snd_free_dev_iram(struct snd_dma_buffer *dmab) |
05503214 NC |
143 | { |
144 | struct gen_pool *pool = dmab->private_data; | |
145 | ||
146 | if (pool && dmab->area) | |
147 | gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes); | |
148 | } | |
63437313 | 149 | #endif /* CONFIG_GENERIC_ALLOCATOR */ |
8f11551b | 150 | #endif /* CONFIG_HAS_DMA */ |
1da177e4 | 151 | |
1da177e4 LT |
152 | /* |
153 | * | |
154 | * ALSA generic memory management | |
155 | * | |
156 | */ | |
157 | ||
158 | ||
159 | /** | |
160 | * snd_dma_alloc_pages - allocate the buffer area according to the given type | |
161 | * @type: the DMA buffer type | |
162 | * @device: the device pointer | |
163 | * @size: the buffer size to allocate | |
164 | * @dmab: buffer allocation record to store the allocated data | |
165 | * | |
166 | * Calls the memory-allocator function for the corresponding | |
167 | * buffer type. | |
eb7c06e8 YB |
168 | * |
169 | * Return: Zero if the buffer with the given size is allocated successfully, | |
170 | * otherwise a negative value on error. | |
1da177e4 LT |
171 | */ |
172 | int snd_dma_alloc_pages(int type, struct device *device, size_t size, | |
173 | struct snd_dma_buffer *dmab) | |
174 | { | |
7eaa943c TI |
175 | if (WARN_ON(!size)) |
176 | return -ENXIO; | |
177 | if (WARN_ON(!dmab)) | |
178 | return -ENXIO; | |
1da177e4 LT |
179 | |
180 | dmab->dev.type = type; | |
181 | dmab->dev.dev = device; | |
182 | dmab->bytes = 0; | |
183 | switch (type) { | |
184 | case SNDRV_DMA_TYPE_CONTINUOUS: | |
fea952e5 CL |
185 | dmab->area = snd_malloc_pages(size, |
186 | (__force gfp_t)(unsigned long)device); | |
1da177e4 LT |
187 | dmab->addr = 0; |
188 | break; | |
8f11551b | 189 | #ifdef CONFIG_HAS_DMA |
a5606f85 | 190 | #ifdef CONFIG_GENERIC_ALLOCATOR |
05503214 NC |
191 | case SNDRV_DMA_TYPE_DEV_IRAM: |
192 | snd_malloc_dev_iram(dmab, size); | |
193 | if (dmab->area) | |
194 | break; | |
195 | /* Internal memory might have limited size and no enough space, | |
196 | * so if we fail to malloc, try to fetch memory traditionally. | |
197 | */ | |
198 | dmab->dev.type = SNDRV_DMA_TYPE_DEV; | |
a5606f85 | 199 | #endif /* CONFIG_GENERIC_ALLOCATOR */ |
1da177e4 LT |
200 | case SNDRV_DMA_TYPE_DEV: |
201 | dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); | |
202 | break; | |
cc6a8acd TI |
203 | #endif |
204 | #ifdef CONFIG_SND_DMA_SGBUF | |
1da177e4 LT |
205 | case SNDRV_DMA_TYPE_DEV_SG: |
206 | snd_malloc_sgbuf_pages(device, size, dmab, NULL); | |
207 | break; | |
8f11551b | 208 | #endif |
1da177e4 | 209 | default: |
f2f9307a | 210 | pr_err("snd-malloc: invalid device type %d\n", type); |
1da177e4 LT |
211 | dmab->area = NULL; |
212 | dmab->addr = 0; | |
213 | return -ENXIO; | |
214 | } | |
215 | if (! dmab->area) | |
216 | return -ENOMEM; | |
217 | dmab->bytes = size; | |
218 | return 0; | |
219 | } | |
220 | ||
221 | /** | |
222 | * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback | |
223 | * @type: the DMA buffer type | |
224 | * @device: the device pointer | |
225 | * @size: the buffer size to allocate | |
226 | * @dmab: buffer allocation record to store the allocated data | |
227 | * | |
228 | * Calls the memory-allocator function for the corresponding | |
229 | * buffer type. When no space is left, this function reduces the size and | |
230 | * tries to allocate again. The size actually allocated is stored in | |
231 | * res_size argument. | |
eb7c06e8 YB |
232 | * |
233 | * Return: Zero if the buffer with the given size is allocated successfully, | |
234 | * otherwise a negative value on error. | |
1da177e4 LT |
235 | */ |
236 | int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size, | |
237 | struct snd_dma_buffer *dmab) | |
238 | { | |
239 | int err; | |
240 | ||
1da177e4 | 241 | while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) { |
4e184f8f | 242 | size_t aligned_size; |
1da177e4 LT |
243 | if (err != -ENOMEM) |
244 | return err; | |
1da177e4 LT |
245 | if (size <= PAGE_SIZE) |
246 | return -ENOMEM; | |
4e184f8f TI |
247 | aligned_size = PAGE_SIZE << get_order(size); |
248 | if (size != aligned_size) | |
249 | size = aligned_size; | |
250 | else | |
251 | size >>= 1; | |
1da177e4 LT |
252 | } |
253 | if (! dmab->area) | |
254 | return -ENOMEM; | |
255 | return 0; | |
256 | } | |
257 | ||
258 | ||
259 | /** | |
260 | * snd_dma_free_pages - release the allocated buffer | |
261 | * @dmab: the buffer allocation record to release | |
262 | * | |
263 | * Releases the allocated buffer via snd_dma_alloc_pages(). | |
264 | */ | |
265 | void snd_dma_free_pages(struct snd_dma_buffer *dmab) | |
266 | { | |
267 | switch (dmab->dev.type) { | |
268 | case SNDRV_DMA_TYPE_CONTINUOUS: | |
269 | snd_free_pages(dmab->area, dmab->bytes); | |
270 | break; | |
8f11551b | 271 | #ifdef CONFIG_HAS_DMA |
a5606f85 | 272 | #ifdef CONFIG_GENERIC_ALLOCATOR |
05503214 NC |
273 | case SNDRV_DMA_TYPE_DEV_IRAM: |
274 | snd_free_dev_iram(dmab); | |
275 | break; | |
a5606f85 | 276 | #endif /* CONFIG_GENERIC_ALLOCATOR */ |
1da177e4 LT |
277 | case SNDRV_DMA_TYPE_DEV: |
278 | snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); | |
279 | break; | |
cc6a8acd TI |
280 | #endif |
281 | #ifdef CONFIG_SND_DMA_SGBUF | |
1da177e4 LT |
282 | case SNDRV_DMA_TYPE_DEV_SG: |
283 | snd_free_sgbuf_pages(dmab); | |
284 | break; | |
8f11551b | 285 | #endif |
1da177e4 | 286 | default: |
f2f9307a | 287 | pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type); |
1da177e4 LT |
288 | } |
289 | } | |
290 | ||
1da177e4 LT |
291 | /* |
292 | * exports | |
293 | */ | |
294 | EXPORT_SYMBOL(snd_dma_alloc_pages); | |
295 | EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); | |
296 | EXPORT_SYMBOL(snd_dma_free_pages); | |
297 | ||
1da177e4 LT |
298 | EXPORT_SYMBOL(snd_malloc_pages); |
299 | EXPORT_SYMBOL(snd_free_pages); |