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