]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> | |
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 | ||
24 | #include <linux/slab.h> | |
25 | #include <linux/mm.h> | |
26 | #include <linux/dma-mapping.h> | |
27 | #include <linux/genalloc.h> | |
28 | #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 | ||
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); | |
72 | free_pages((unsigned long) ptr, pg); | |
73 | } | |
74 | ||
75 | /* | |
76 | * | |
77 | * Bus-specific memory allocators | |
78 | * | |
79 | */ | |
80 | ||
81 | #ifdef CONFIG_HAS_DMA | |
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; | |
86 | gfp_t gfp_flags; | |
87 | ||
88 | if (WARN_ON(!dma)) | |
89 | return NULL; | |
90 | pg = get_order(size); | |
91 | gfp_flags = GFP_KERNEL | |
92 | | __GFP_COMP /* compound page lets parts be mapped */ | |
93 | | __GFP_NORETRY /* don't trigger OOM-killer */ | |
94 | | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ | |
95 | return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags); | |
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); | |
107 | dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); | |
108 | } | |
109 | ||
110 | #ifdef CONFIG_GENERIC_ALLOCATOR | |
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 | */ | |
118 | static void snd_malloc_dev_iram(struct snd_dma_buffer *dmab, size_t size) | |
119 | { | |
120 | struct device *dev = dmab->dev.dev; | |
121 | struct gen_pool *pool = NULL; | |
122 | ||
123 | dmab->area = NULL; | |
124 | dmab->addr = 0; | |
125 | ||
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 | ||
135 | dmab->area = gen_pool_dma_alloc(pool, size, &dmab->addr); | |
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 | */ | |
142 | static void snd_free_dev_iram(struct snd_dma_buffer *dmab) | |
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 | } | |
149 | #endif /* CONFIG_GENERIC_ALLOCATOR */ | |
150 | #endif /* CONFIG_HAS_DMA */ | |
151 | ||
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. | |
168 | * | |
169 | * Return: Zero if the buffer with the given size is allocated successfully, | |
170 | * otherwise a negative value on error. | |
171 | */ | |
172 | int snd_dma_alloc_pages(int type, struct device *device, size_t size, | |
173 | struct snd_dma_buffer *dmab) | |
174 | { | |
175 | if (WARN_ON(!size)) | |
176 | return -ENXIO; | |
177 | if (WARN_ON(!dmab)) | |
178 | return -ENXIO; | |
179 | ||
180 | dmab->dev.type = type; | |
181 | dmab->dev.dev = device; | |
182 | dmab->bytes = 0; | |
183 | switch (type) { | |
184 | case SNDRV_DMA_TYPE_CONTINUOUS: | |
185 | dmab->area = snd_malloc_pages(size, | |
186 | (__force gfp_t)(unsigned long)device); | |
187 | dmab->addr = 0; | |
188 | break; | |
189 | #ifdef CONFIG_HAS_DMA | |
190 | #ifdef CONFIG_GENERIC_ALLOCATOR | |
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; | |
199 | #endif /* CONFIG_GENERIC_ALLOCATOR */ | |
200 | case SNDRV_DMA_TYPE_DEV: | |
201 | dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); | |
202 | break; | |
203 | #endif | |
204 | #ifdef CONFIG_SND_DMA_SGBUF | |
205 | case SNDRV_DMA_TYPE_DEV_SG: | |
206 | snd_malloc_sgbuf_pages(device, size, dmab, NULL); | |
207 | break; | |
208 | #endif | |
209 | default: | |
210 | pr_err("snd-malloc: invalid device type %d\n", type); | |
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. | |
232 | * | |
233 | * Return: Zero if the buffer with the given size is allocated successfully, | |
234 | * otherwise a negative value on error. | |
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 | ||
241 | while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) { | |
242 | size_t aligned_size; | |
243 | if (err != -ENOMEM) | |
244 | return err; | |
245 | if (size <= PAGE_SIZE) | |
246 | return -ENOMEM; | |
247 | aligned_size = PAGE_SIZE << get_order(size); | |
248 | if (size != aligned_size) | |
249 | size = aligned_size; | |
250 | else | |
251 | size >>= 1; | |
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; | |
271 | #ifdef CONFIG_HAS_DMA | |
272 | #ifdef CONFIG_GENERIC_ALLOCATOR | |
273 | case SNDRV_DMA_TYPE_DEV_IRAM: | |
274 | snd_free_dev_iram(dmab); | |
275 | break; | |
276 | #endif /* CONFIG_GENERIC_ALLOCATOR */ | |
277 | case SNDRV_DMA_TYPE_DEV: | |
278 | snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); | |
279 | break; | |
280 | #endif | |
281 | #ifdef CONFIG_SND_DMA_SGBUF | |
282 | case SNDRV_DMA_TYPE_DEV_SG: | |
283 | snd_free_sgbuf_pages(dmab); | |
284 | break; | |
285 | #endif | |
286 | default: | |
287 | pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type); | |
288 | } | |
289 | } | |
290 | ||
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 | ||
298 | EXPORT_SYMBOL(snd_malloc_pages); | |
299 | EXPORT_SYMBOL(snd_free_pages); |