Linux Audio

Check our new training course

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