Branch data Line data Source code
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 : 0 : void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
46 : : {
47 : : int pg;
48 : :
49 [ # # ][ # # ]: 0 : if (WARN_ON(!size))
50 : : return NULL;
51 [ # # ][ # # ]: 0 : if (WARN_ON(!gfp_flags))
52 : : return NULL;
53 : 0 : gfp_flags |= __GFP_COMP; /* compound page lets parts be mapped */
54 [ # # ][ # # ]: 0 : pg = get_order(size);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
55 : 0 : 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 : 0 : void snd_free_pages(void *ptr, size_t size)
66 : : {
67 : : int pg;
68 : :
69 [ # # ]: 0 : if (ptr == NULL)
70 : 0 : return;
71 [ # # ][ # # ]: 0 : pg = get_order(size);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
72 : 0 : 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 : 0 : 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 [ # # ][ # # ]: 0 : if (WARN_ON(!dma))
89 : : return NULL;
90 [ # # ][ # # ]: 0 : 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 : 0 : return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
96 : : }
97 : :
98 : : /* free the coherent DMA pages */
99 : 0 : 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 [ # # ]: 0 : if (ptr == NULL)
105 : 0 : return;
106 [ # # ][ # # ]: 0 : pg = get_order(size);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
107 : 0 : 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 : 0 : int snd_dma_alloc_pages(int type, struct device *device, size_t size,
173 : : struct snd_dma_buffer *dmab)
174 : : {
175 [ # # ][ # # ]: 0 : if (WARN_ON(!size))
176 : : return -ENXIO;
177 [ # # ][ # # ]: 0 : if (WARN_ON(!dmab))
178 : : return -ENXIO;
179 : :
180 : 0 : dmab->dev.type = type;
181 : 0 : dmab->dev.dev = device;
182 : 0 : dmab->bytes = 0;
183 [ # # # ]: 0 : switch (type) {
184 : : case SNDRV_DMA_TYPE_CONTINUOUS:
185 : 0 : dmab->area = snd_malloc_pages(size,
186 : : (__force gfp_t)(unsigned long)device);
187 : 0 : dmab->addr = 0;
188 : 0 : 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 : 0 : dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
202 : 0 : 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 : 0 : printk(KERN_ERR "snd-malloc: invalid device type %d\n", type);
211 : 0 : dmab->area = NULL;
212 : 0 : dmab->addr = 0;
213 : 0 : return -ENXIO;
214 : : }
215 [ # # ]: 0 : if (! dmab->area)
216 : : return -ENOMEM;
217 : 0 : dmab->bytes = size;
218 : 0 : 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 : 0 : 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 [ # # ]: 0 : while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) {
242 : : size_t aligned_size;
243 [ # # ]: 0 : if (err != -ENOMEM)
244 : : return err;
245 [ # # ]: 0 : if (size <= PAGE_SIZE)
246 : : return -ENOMEM;
247 [ # # ][ # # ]: 0 : aligned_size = PAGE_SIZE << get_order(size);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
248 [ # # ]: 0 : if (size != aligned_size)
249 : : size = aligned_size;
250 : : else
251 : 0 : size >>= 1;
252 : : }
253 [ # # ]: 0 : if (! dmab->area)
254 : : return -ENOMEM;
255 : 0 : 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 : 0 : void snd_dma_free_pages(struct snd_dma_buffer *dmab)
266 : : {
267 [ # # # ]: 0 : switch (dmab->dev.type) {
268 : : case SNDRV_DMA_TYPE_CONTINUOUS:
269 : 0 : snd_free_pages(dmab->area, dmab->bytes);
270 : 0 : 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 : 0 : snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
279 : 0 : 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 : 0 : printk(KERN_ERR "snd-malloc: invalid device type %d\n", dmab->dev.type);
288 : : }
289 : 0 : }
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);
|