[alsa-devel] [PATCH 1/7] ALSA: core: Add device-managed page allocator helper
Takashi Iwai
tiwai at suse.de
Thu Sep 20 17:54:56 CEST 2018
This is a preparation for managing the whole resource via devres.
As a first step, add a new allocator function, snd_devm_alloc_pages()
to manage the allocated pages via devres, so that the pages will be
automagically released as device unbinding.
Unlike the old snd_dma_alloc_pages(), the new function returns
directly the snd_dma_buffer pointer. The caller needs to check the
error via IS_ERR().
Signed-off-by: Takashi Iwai <tiwai at suse.de>
---
include/sound/memalloc.h | 4 ++
sound/core/memalloc.c | 88 ++++++++++++++++++++++++++++++++--------
2 files changed, 74 insertions(+), 18 deletions(-)
diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h
index af3fa577fa06..3a1d9fb44fcf 100644
--- a/include/sound/memalloc.h
+++ b/include/sound/memalloc.h
@@ -156,5 +156,9 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab);
void *snd_malloc_pages(size_t size, gfp_t gfp_flags);
void snd_free_pages(void *ptr, size_t size);
+/* device-managed memory allocator */
+struct snd_dma_buffer *snd_devm_alloc_pages(struct device *dev, int type,
+ size_t size);
+
#endif /* __SOUND_MEMALLOC_H */
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index aa266907ec9b..a54d7aacec43 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -161,22 +161,8 @@ static void snd_free_dev_iram(struct snd_dma_buffer *dmab)
*
*/
-
-/**
- * snd_dma_alloc_pages - allocate the buffer area according to the given type
- * @type: the DMA buffer type
- * @device: the device pointer
- * @size: the buffer size to allocate
- * @dmab: buffer allocation record to store the allocated data
- *
- * Calls the memory-allocator function for the corresponding
- * buffer type.
- *
- * Return: Zero if the buffer with the given size is allocated successfully,
- * otherwise a negative value on error.
- */
-int snd_dma_alloc_pages(int type, struct device *device, size_t size,
- struct snd_dma_buffer *dmab)
+static int __snd_dma_alloc_pages(struct device *device, int type, size_t size,
+ gfp_t gfp_flags, struct snd_dma_buffer *dmab)
{
if (WARN_ON(!size))
return -ENXIO;
@@ -188,8 +174,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
dmab->bytes = 0;
switch (type) {
case SNDRV_DMA_TYPE_CONTINUOUS:
- dmab->area = snd_malloc_pages(size,
- (__force gfp_t)(unsigned long)device);
+ dmab->area = snd_malloc_pages(size, gfp_flags);
dmab->addr = 0;
break;
#ifdef CONFIG_HAS_DMA
@@ -225,6 +210,30 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
dmab->bytes = size;
return 0;
}
+
+/**
+ * snd_dma_alloc_pages - allocate the buffer area according to the given type
+ * @type: the DMA buffer type
+ * @device: the device pointer
+ * @size: the buffer size to allocate
+ * @dmab: buffer allocation record to store the allocated data
+ *
+ * Calls the memory-allocator function for the corresponding
+ * buffer type.
+ *
+ * Return: Zero if the buffer with the given size is allocated successfully,
+ * otherwise a negative value on error.
+ */
+int snd_dma_alloc_pages(int type, struct device *device, size_t size,
+ struct snd_dma_buffer *dmab)
+{
+ gfp_t gfp_flags = 0;
+
+ if (type == SNDRV_DMA_TYPE_CONTINUOUS)
+ gfp_flags = (__force gfp_t)(unsigned long)device;
+
+ return __snd_dma_alloc_pages(device, type, size, gfp_flags, dmab);
+}
EXPORT_SYMBOL(snd_dma_alloc_pages);
/**
@@ -296,3 +305,46 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
}
}
EXPORT_SYMBOL(snd_dma_free_pages);
+
+/* called by devres */
+static void __snd_release_pages(struct device *dev, void *res)
+{
+ snd_dma_free_pages(res);
+}
+
+/**
+ * snd_devm_alloc_pages - allocate the buffer and manage with devres
+ * @dev: the device pointer
+ * @type: the DMA buffer type
+ * @size: the buffer size to allocate
+ *
+ * Allocate buffer pages depending on the given type and manage using devres.
+ * The pages will be released automatically at the device removal.
+ *
+ * The function cannot handle GFP flags for SNDRV_DMA_TYPE_CONTINUOUS type,
+ * only GFP_KERNEL is assumed.
+ *
+ * The function returns the snd_dma_buffer object at success or the encoded
+ * error pointer via ERR_PTR(). The caller needs to check the error via
+ * IS_ERR() and PTR_ERR().
+ */
+struct snd_dma_buffer *
+snd_devm_alloc_pages(struct device *dev, int type, size_t size)
+{
+ struct snd_dma_buffer *dmab;
+ int err;
+
+ dmab = devres_alloc(__snd_release_pages, sizeof(*dmab), GFP_KERNEL);
+ if (!dmab)
+ return ERR_PTR(-ENOMEM);
+
+ err = __snd_dma_alloc_pages(dev, type, size, GFP_KERNEL, dmab);
+ if (err < 0) {
+ devres_free(dmab);
+ return ERR_PTR(err);
+ }
+
+ devres_add(dev, dmab);
+ return dmab;
+}
+EXPORT_SYMBOL_GPL(snd_devm_alloc_pages);
--
2.18.0
More information about the Alsa-devel
mailing list