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