| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
|---|
| 3 | 4 | * Takashi Iwai <tiwai@suse.de> |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * 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 | 7 | */ |
|---|
| 23 | 8 | |
|---|
| 24 | 9 | #include <linux/slab.h> |
|---|
| 25 | 10 | #include <linux/mm.h> |
|---|
| 26 | 11 | #include <linux/dma-mapping.h> |
|---|
| 27 | 12 | #include <linux/genalloc.h> |
|---|
| 13 | +#include <linux/vmalloc.h> |
|---|
| 14 | +#ifdef CONFIG_X86 |
|---|
| 15 | +#include <asm/set_memory.h> |
|---|
| 16 | +#endif |
|---|
| 28 | 17 | #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 | | -void *snd_malloc_pages(size_t size, gfp_t gfp_flags) |
|---|
| 46 | | -{ |
|---|
| 47 | | - int pg; |
|---|
| 48 | | - |
|---|
| 49 | | - if (WARN_ON(!size)) |
|---|
| 50 | | - return NULL; |
|---|
| 51 | | - if (WARN_ON(!gfp_flags)) |
|---|
| 52 | | - return NULL; |
|---|
| 53 | | - gfp_flags |= __GFP_COMP; /* compound page lets parts be mapped */ |
|---|
| 54 | | - pg = get_order(size); |
|---|
| 55 | | - return (void *) __get_free_pages(gfp_flags, pg); |
|---|
| 56 | | -} |
|---|
| 57 | | -EXPORT_SYMBOL(snd_malloc_pages); |
|---|
| 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); |
|---|
| 73 | | - free_pages((unsigned long) ptr, pg); |
|---|
| 74 | | -} |
|---|
| 75 | | -EXPORT_SYMBOL(snd_free_pages); |
|---|
| 76 | 18 | |
|---|
| 77 | 19 | /* |
|---|
| 78 | 20 | * |
|---|
| .. | .. |
|---|
| 82 | 24 | |
|---|
| 83 | 25 | #ifdef CONFIG_HAS_DMA |
|---|
| 84 | 26 | /* allocate the coherent DMA pages */ |
|---|
| 85 | | -static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) |
|---|
| 27 | +static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size) |
|---|
| 86 | 28 | { |
|---|
| 87 | | - int pg; |
|---|
| 88 | 29 | gfp_t gfp_flags; |
|---|
| 89 | 30 | |
|---|
| 90 | | - if (WARN_ON(!dma)) |
|---|
| 91 | | - return NULL; |
|---|
| 92 | | - pg = get_order(size); |
|---|
| 93 | 31 | gfp_flags = GFP_KERNEL |
|---|
| 94 | 32 | | __GFP_COMP /* compound page lets parts be mapped */ |
|---|
| 95 | 33 | | __GFP_NORETRY /* don't trigger OOM-killer */ |
|---|
| 96 | 34 | | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ |
|---|
| 97 | | - return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags); |
|---|
| 35 | + dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, |
|---|
| 36 | + gfp_flags); |
|---|
| 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 |
|---|
| 98 | 42 | } |
|---|
| 99 | 43 | |
|---|
| 100 | 44 | /* 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) |
|---|
| 45 | +static void snd_free_dev_pages(struct snd_dma_buffer *dmab) |
|---|
| 103 | 46 | { |
|---|
| 104 | | - int pg; |
|---|
| 105 | | - |
|---|
| 106 | | - if (ptr == NULL) |
|---|
| 107 | | - return; |
|---|
| 108 | | - pg = get_order(size); |
|---|
| 109 | | - dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); |
|---|
| 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 |
|---|
| 52 | + dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); |
|---|
| 110 | 53 | } |
|---|
| 111 | 54 | |
|---|
| 112 | 55 | #ifdef CONFIG_GENERIC_ALLOCATOR |
|---|
| .. | .. |
|---|
| 134 | 77 | /* Assign the pool into private_data field */ |
|---|
| 135 | 78 | dmab->private_data = pool; |
|---|
| 136 | 79 | |
|---|
| 137 | | - dmab->area = gen_pool_dma_alloc(pool, size, &dmab->addr); |
|---|
| 80 | + dmab->area = gen_pool_dma_alloc_align(pool, size, &dmab->addr, |
|---|
| 81 | + PAGE_SIZE); |
|---|
| 138 | 82 | } |
|---|
| 139 | 83 | |
|---|
| 140 | 84 | /** |
|---|
| .. | .. |
|---|
| 157 | 101 | * |
|---|
| 158 | 102 | */ |
|---|
| 159 | 103 | |
|---|
| 104 | +static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev, |
|---|
| 105 | + gfp_t default_gfp) |
|---|
| 106 | +{ |
|---|
| 107 | + if (!dev) |
|---|
| 108 | + return default_gfp; |
|---|
| 109 | + else |
|---|
| 110 | + return (__force gfp_t)(unsigned long)dev; |
|---|
| 111 | +} |
|---|
| 160 | 112 | |
|---|
| 161 | 113 | /** |
|---|
| 162 | 114 | * snd_dma_alloc_pages - allocate the buffer area according to the given type |
|---|
| .. | .. |
|---|
| 174 | 126 | int snd_dma_alloc_pages(int type, struct device *device, size_t size, |
|---|
| 175 | 127 | struct snd_dma_buffer *dmab) |
|---|
| 176 | 128 | { |
|---|
| 129 | + gfp_t gfp; |
|---|
| 130 | + |
|---|
| 177 | 131 | if (WARN_ON(!size)) |
|---|
| 178 | 132 | return -ENXIO; |
|---|
| 179 | 133 | if (WARN_ON(!dmab)) |
|---|
| 180 | 134 | return -ENXIO; |
|---|
| 181 | 135 | |
|---|
| 136 | + size = PAGE_ALIGN(size); |
|---|
| 182 | 137 | dmab->dev.type = type; |
|---|
| 183 | 138 | dmab->dev.dev = device; |
|---|
| 184 | 139 | dmab->bytes = 0; |
|---|
| 140 | + dmab->area = NULL; |
|---|
| 141 | + dmab->addr = 0; |
|---|
| 142 | + dmab->private_data = NULL; |
|---|
| 185 | 143 | switch (type) { |
|---|
| 186 | 144 | case SNDRV_DMA_TYPE_CONTINUOUS: |
|---|
| 187 | | - dmab->area = snd_malloc_pages(size, |
|---|
| 188 | | - (__force gfp_t)(unsigned long)device); |
|---|
| 189 | | - dmab->addr = 0; |
|---|
| 145 | + gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL); |
|---|
| 146 | + dmab->area = alloc_pages_exact(size, gfp); |
|---|
| 147 | + break; |
|---|
| 148 | + case SNDRV_DMA_TYPE_VMALLOC: |
|---|
| 149 | + gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL | __GFP_HIGHMEM); |
|---|
| 150 | + dmab->area = __vmalloc(size, gfp); |
|---|
| 190 | 151 | break; |
|---|
| 191 | 152 | #ifdef CONFIG_HAS_DMA |
|---|
| 192 | 153 | #ifdef CONFIG_GENERIC_ALLOCATOR |
|---|
| .. | .. |
|---|
| 198 | 159 | * so if we fail to malloc, try to fetch memory traditionally. |
|---|
| 199 | 160 | */ |
|---|
| 200 | 161 | dmab->dev.type = SNDRV_DMA_TYPE_DEV; |
|---|
| 162 | + fallthrough; |
|---|
| 201 | 163 | #endif /* CONFIG_GENERIC_ALLOCATOR */ |
|---|
| 202 | 164 | case SNDRV_DMA_TYPE_DEV: |
|---|
| 203 | | - dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); |
|---|
| 165 | + case SNDRV_DMA_TYPE_DEV_UC: |
|---|
| 166 | + snd_malloc_dev_pages(dmab, size); |
|---|
| 204 | 167 | break; |
|---|
| 205 | 168 | #endif |
|---|
| 206 | 169 | #ifdef CONFIG_SND_DMA_SGBUF |
|---|
| 207 | 170 | case SNDRV_DMA_TYPE_DEV_SG: |
|---|
| 171 | + case SNDRV_DMA_TYPE_DEV_UC_SG: |
|---|
| 208 | 172 | snd_malloc_sgbuf_pages(device, size, dmab, NULL); |
|---|
| 209 | 173 | break; |
|---|
| 210 | 174 | #endif |
|---|
| 211 | 175 | default: |
|---|
| 212 | 176 | pr_err("snd-malloc: invalid device type %d\n", type); |
|---|
| 213 | | - dmab->area = NULL; |
|---|
| 214 | | - dmab->addr = 0; |
|---|
| 215 | 177 | return -ENXIO; |
|---|
| 216 | 178 | } |
|---|
| 217 | 179 | if (! dmab->area) |
|---|
| .. | .. |
|---|
| 266 | 228 | { |
|---|
| 267 | 229 | switch (dmab->dev.type) { |
|---|
| 268 | 230 | case SNDRV_DMA_TYPE_CONTINUOUS: |
|---|
| 269 | | - snd_free_pages(dmab->area, dmab->bytes); |
|---|
| 231 | + free_pages_exact(dmab->area, dmab->bytes); |
|---|
| 232 | + break; |
|---|
| 233 | + case SNDRV_DMA_TYPE_VMALLOC: |
|---|
| 234 | + vfree(dmab->area); |
|---|
| 270 | 235 | break; |
|---|
| 271 | 236 | #ifdef CONFIG_HAS_DMA |
|---|
| 272 | 237 | #ifdef CONFIG_GENERIC_ALLOCATOR |
|---|
| .. | .. |
|---|
| 275 | 240 | break; |
|---|
| 276 | 241 | #endif /* CONFIG_GENERIC_ALLOCATOR */ |
|---|
| 277 | 242 | case SNDRV_DMA_TYPE_DEV: |
|---|
| 278 | | - snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); |
|---|
| 243 | + case SNDRV_DMA_TYPE_DEV_UC: |
|---|
| 244 | + snd_free_dev_pages(dmab); |
|---|
| 279 | 245 | break; |
|---|
| 280 | 246 | #endif |
|---|
| 281 | 247 | #ifdef CONFIG_SND_DMA_SGBUF |
|---|
| 282 | 248 | case SNDRV_DMA_TYPE_DEV_SG: |
|---|
| 249 | + case SNDRV_DMA_TYPE_DEV_UC_SG: |
|---|
| 283 | 250 | snd_free_sgbuf_pages(dmab); |
|---|
| 284 | 251 | break; |
|---|
| 285 | 252 | #endif |
|---|