ALSA: memalloc: Add vmalloc buffer allocation support
[linux-2.6-block.git] / sound / core / memalloc.c
index 1b1c7620cbdac292ecada6ad22085acbe81aa784..a83553fbedf00a8c2bf338355d1523dc80be3628 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
 #include <linux/genalloc.h>
+#include <linux/vmalloc.h>
 #ifdef CONFIG_X86
 #include <asm/set_memory.h>
 #endif
@@ -99,10 +100,11 @@ static void snd_free_dev_iram(struct snd_dma_buffer *dmab)
  *
  */
 
-static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev)
+static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev,
+                                         gfp_t default_gfp)
 {
        if (!dev)
-               return GFP_KERNEL;
+               return default_gfp;
        else
                return (__force gfp_t)(unsigned long)dev;
 }
@@ -123,6 +125,8 @@ static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev)
 int snd_dma_alloc_pages(int type, struct device *device, size_t size,
                        struct snd_dma_buffer *dmab)
 {
+       gfp_t gfp;
+
        if (WARN_ON(!size))
                return -ENXIO;
        if (WARN_ON(!dmab))
@@ -133,8 +137,13 @@ 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 = alloc_pages_exact(size,
-                                              snd_mem_get_gfp_flags(device));
+               gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL);
+               dmab->area = alloc_pages_exact(size, gfp);
+               dmab->addr = 0;
+               break;
+       case SNDRV_DMA_TYPE_VMALLOC:
+               gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL | __GFP_HIGHMEM);
+               dmab->area = __vmalloc(size, gfp, PAGE_KERNEL);
                dmab->addr = 0;
                break;
 #ifdef CONFIG_HAS_DMA
@@ -220,6 +229,9 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
        case SNDRV_DMA_TYPE_CONTINUOUS:
                free_pages_exact(dmab->area, dmab->bytes);
                break;
+       case SNDRV_DMA_TYPE_VMALLOC:
+               vfree(dmab->area);
+               break;
 #ifdef CONFIG_HAS_DMA
 #ifdef CONFIG_GENERIC_ALLOCATOR
        case SNDRV_DMA_TYPE_DEV_IRAM: