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