]>
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 | ||
74c64efa RG |
80 | dmab->area = gen_pool_dma_alloc_align(pool, size, &dmab->addr, |
81 | PAGE_SIZE); | |
05503214 NC |
82 | } |
83 | ||
84 | /** | |
85 | * snd_free_dev_iram - free allocated specific memory from on-chip internal ram | |
86 | * @dmab: buffer allocation record to store the allocated data | |
87 | */ | |
9f694bc7 | 88 | static void snd_free_dev_iram(struct snd_dma_buffer *dmab) |
05503214 NC |
89 | { |
90 | struct gen_pool *pool = dmab->private_data; | |
91 | ||
92 | if (pool && dmab->area) | |
93 | gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes); | |
94 | } | |
63437313 | 95 | #endif /* CONFIG_GENERIC_ALLOCATOR */ |
8f11551b | 96 | #endif /* CONFIG_HAS_DMA */ |
1da177e4 | 97 | |
1da177e4 LT |
98 | /* |
99 | * | |
100 | * ALSA generic memory management | |
101 | * | |
102 | */ | |
103 | ||
1fe7f397 TI |
104 | static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev, |
105 | gfp_t default_gfp) | |
08422d2c TI |
106 | { |
107 | if (!dev) | |
1fe7f397 | 108 | return default_gfp; |
08422d2c TI |
109 | else |
110 | return (__force gfp_t)(unsigned long)dev; | |
111 | } | |
1da177e4 LT |
112 | |
113 | /** | |
114 | * snd_dma_alloc_pages - allocate the buffer area according to the given type | |
115 | * @type: the DMA buffer type | |
116 | * @device: the device pointer | |
117 | * @size: the buffer size to allocate | |
118 | * @dmab: buffer allocation record to store the allocated data | |
119 | * | |
120 | * Calls the memory-allocator function for the corresponding | |
121 | * buffer type. | |
eb7c06e8 YB |
122 | * |
123 | * Return: Zero if the buffer with the given size is allocated successfully, | |
124 | * otherwise a negative value on error. | |
1da177e4 LT |
125 | */ |
126 | int snd_dma_alloc_pages(int type, struct device *device, size_t size, | |
127 | struct snd_dma_buffer *dmab) | |
128 | { | |
1fe7f397 TI |
129 | gfp_t gfp; |
130 | ||
7eaa943c TI |
131 | if (WARN_ON(!size)) |
132 | return -ENXIO; | |
133 | if (WARN_ON(!dmab)) | |
134 | return -ENXIO; | |
1da177e4 | 135 | |
5c1733e3 | 136 | size = PAGE_ALIGN(size); |
1da177e4 LT |
137 | dmab->dev.type = type; |
138 | dmab->dev.dev = device; | |
139 | dmab->bytes = 0; | |
28e60dbb TI |
140 | dmab->area = NULL; |
141 | dmab->addr = 0; | |
142 | dmab->private_data = NULL; | |
1da177e4 LT |
143 | switch (type) { |
144 | case SNDRV_DMA_TYPE_CONTINUOUS: | |
1fe7f397 TI |
145 | gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL); |
146 | dmab->area = alloc_pages_exact(size, gfp); | |
1fe7f397 TI |
147 | break; |
148 | case SNDRV_DMA_TYPE_VMALLOC: | |
149 | gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL | __GFP_HIGHMEM); | |
88dca4ca | 150 | dmab->area = __vmalloc(size, gfp); |
1da177e4 | 151 | break; |
8f11551b | 152 | #ifdef CONFIG_HAS_DMA |
a5606f85 | 153 | #ifdef CONFIG_GENERIC_ALLOCATOR |
05503214 NC |
154 | case SNDRV_DMA_TYPE_DEV_IRAM: |
155 | snd_malloc_dev_iram(dmab, size); | |
156 | if (dmab->area) | |
157 | break; | |
158 | /* Internal memory might have limited size and no enough space, | |
159 | * so if we fail to malloc, try to fetch memory traditionally. | |
160 | */ | |
161 | dmab->dev.type = SNDRV_DMA_TYPE_DEV; | |
c0dbbdad | 162 | fallthrough; |
b1c14124 | 163 | #endif /* CONFIG_GENERIC_ALLOCATOR */ |
1da177e4 | 164 | case SNDRV_DMA_TYPE_DEV: |
42e748a0 | 165 | case SNDRV_DMA_TYPE_DEV_UC: |
28f3f4f6 | 166 | snd_malloc_dev_pages(dmab, size); |
1da177e4 | 167 | break; |
cc6a8acd TI |
168 | #endif |
169 | #ifdef CONFIG_SND_DMA_SGBUF | |
1da177e4 | 170 | case SNDRV_DMA_TYPE_DEV_SG: |
42e748a0 | 171 | case SNDRV_DMA_TYPE_DEV_UC_SG: |
1da177e4 LT |
172 | snd_malloc_sgbuf_pages(device, size, dmab, NULL); |
173 | break; | |
8f11551b | 174 | #endif |
1da177e4 | 175 | default: |
f2f9307a | 176 | pr_err("snd-malloc: invalid device type %d\n", type); |
1da177e4 LT |
177 | return -ENXIO; |
178 | } | |
179 | if (! dmab->area) | |
180 | return -ENOMEM; | |
181 | dmab->bytes = size; | |
182 | return 0; | |
183 | } | |
35f80014 | 184 | EXPORT_SYMBOL(snd_dma_alloc_pages); |
1da177e4 LT |
185 | |
186 | /** | |
187 | * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback | |
188 | * @type: the DMA buffer type | |
189 | * @device: the device pointer | |
190 | * @size: the buffer size to allocate | |
191 | * @dmab: buffer allocation record to store the allocated data | |
192 | * | |
193 | * Calls the memory-allocator function for the corresponding | |
194 | * buffer type. When no space is left, this function reduces the size and | |
195 | * tries to allocate again. The size actually allocated is stored in | |
196 | * res_size argument. | |
eb7c06e8 YB |
197 | * |
198 | * Return: Zero if the buffer with the given size is allocated successfully, | |
199 | * otherwise a negative value on error. | |
1da177e4 LT |
200 | */ |
201 | int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size, | |
202 | struct snd_dma_buffer *dmab) | |
203 | { | |
204 | int err; | |
205 | ||
1da177e4 LT |
206 | while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) { |
207 | if (err != -ENOMEM) | |
208 | return err; | |
1da177e4 LT |
209 | if (size <= PAGE_SIZE) |
210 | return -ENOMEM; | |
dfef01e1 TI |
211 | size >>= 1; |
212 | size = PAGE_SIZE << get_order(size); | |
1da177e4 LT |
213 | } |
214 | if (! dmab->area) | |
215 | return -ENOMEM; | |
216 | return 0; | |
217 | } | |
35f80014 | 218 | EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); |
1da177e4 LT |
219 | |
220 | ||
221 | /** | |
222 | * snd_dma_free_pages - release the allocated buffer | |
223 | * @dmab: the buffer allocation record to release | |
224 | * | |
225 | * Releases the allocated buffer via snd_dma_alloc_pages(). | |
226 | */ | |
227 | void snd_dma_free_pages(struct snd_dma_buffer *dmab) | |
228 | { | |
229 | switch (dmab->dev.type) { | |
230 | case SNDRV_DMA_TYPE_CONTINUOUS: | |
734b5a0b | 231 | free_pages_exact(dmab->area, dmab->bytes); |
1da177e4 | 232 | break; |
1fe7f397 TI |
233 | case SNDRV_DMA_TYPE_VMALLOC: |
234 | vfree(dmab->area); | |
235 | break; | |
8f11551b | 236 | #ifdef CONFIG_HAS_DMA |
a5606f85 | 237 | #ifdef CONFIG_GENERIC_ALLOCATOR |
05503214 NC |
238 | case SNDRV_DMA_TYPE_DEV_IRAM: |
239 | snd_free_dev_iram(dmab); | |
240 | break; | |
a5606f85 | 241 | #endif /* CONFIG_GENERIC_ALLOCATOR */ |
1da177e4 | 242 | case SNDRV_DMA_TYPE_DEV: |
42e748a0 | 243 | case SNDRV_DMA_TYPE_DEV_UC: |
28f3f4f6 | 244 | snd_free_dev_pages(dmab); |
1da177e4 | 245 | break; |
cc6a8acd TI |
246 | #endif |
247 | #ifdef CONFIG_SND_DMA_SGBUF | |
1da177e4 | 248 | case SNDRV_DMA_TYPE_DEV_SG: |
42e748a0 | 249 | case SNDRV_DMA_TYPE_DEV_UC_SG: |
1da177e4 LT |
250 | snd_free_sgbuf_pages(dmab); |
251 | break; | |
8f11551b | 252 | #endif |
1da177e4 | 253 | default: |
f2f9307a | 254 | pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type); |
1da177e4 LT |
255 | } |
256 | } | |
1da177e4 | 257 | EXPORT_SYMBOL(snd_dma_free_pages); |