[media] v4l: videobuf2: add vmalloc allocator
Pawel Osciak [Mon, 11 Oct 2010 13:58:53 +0000 (10:58 -0300)]
Add an implementation of contiguous virtual memory allocator and handling
routines for videobuf2, implemented on top of vmalloc()/vfree() calls.

Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
CC: Pawel Osciak <pawel@osciak.com>
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/videobuf2-vmalloc.c [new file with mode: 0644]
include/media/videobuf2-vmalloc.h [new file with mode: 0644]

index aae5005..b8c21a7 100644 (file)
@@ -50,6 +50,11 @@ config VIDEOBUF2_CORE
 config VIDEOBUF2_MEMOPS
        tristate
 
+config VIDEOBUF2_VMALLOC
+       select VIDEOBUF2_CORE
+       select VIDEOBUF2_MEMOPS
+       tristate
+
 #
 # Multimedia Video device configuration
 #
index fca0444..e31c88e 100644 (file)
@@ -113,6 +113,7 @@ obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 
 obj-$(CONFIG_VIDEOBUF2_CORE)           += videobuf2-core.o
 obj-$(CONFIG_VIDEOBUF2_MEMOPS)         += videobuf2-memops.o
+obj-$(CONFIG_VIDEOBUF2_VMALLOC)                += videobuf2-vmalloc.o
 
 obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
 
diff --git a/drivers/media/video/videobuf2-vmalloc.c b/drivers/media/video/videobuf2-vmalloc.c
new file mode 100644 (file)
index 0000000..b5e6936
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <p.osciak@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+
+struct vb2_vmalloc_buf {
+       void                            *vaddr;
+       unsigned long                   size;
+       atomic_t                        refcount;
+       struct vb2_vmarea_handler       handler;
+};
+
+static void vb2_vmalloc_put(void *buf_priv);
+
+static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
+{
+       struct vb2_vmalloc_buf *buf;
+
+       buf = kzalloc(sizeof *buf, GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->size = size;
+       buf->vaddr = vmalloc_user(buf->size);
+       buf->handler.refcount = &buf->refcount;
+       buf->handler.put = vb2_vmalloc_put;
+       buf->handler.arg = buf;
+
+       if (!buf->vaddr) {
+               printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size);
+               kfree(buf);
+               return NULL;
+       }
+
+       atomic_inc(&buf->refcount);
+       printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n",
+                       buf->size, buf->vaddr);
+
+       return buf;
+}
+
+static void vb2_vmalloc_put(void *buf_priv)
+{
+       struct vb2_vmalloc_buf *buf = buf_priv;
+
+       if (atomic_dec_and_test(&buf->refcount)) {
+               printk(KERN_DEBUG "%s: Freeing vmalloc mem at vaddr=%p\n",
+                       __func__, buf->vaddr);
+               vfree(buf->vaddr);
+               kfree(buf);
+       }
+}
+
+static void *vb2_vmalloc_vaddr(void *buf_priv)
+{
+       struct vb2_vmalloc_buf *buf = buf_priv;
+
+       BUG_ON(!buf);
+
+       if (!buf->vaddr) {
+               printk(KERN_ERR "Address of an unallocated plane requested\n");
+               return NULL;
+       }
+
+       return buf->vaddr;
+}
+
+static unsigned int vb2_vmalloc_num_users(void *buf_priv)
+{
+       struct vb2_vmalloc_buf *buf = buf_priv;
+       return atomic_read(&buf->refcount);
+}
+
+static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+       struct vb2_vmalloc_buf *buf = buf_priv;
+       int ret;
+
+       if (!buf) {
+               printk(KERN_ERR "No memory to map\n");
+               return -EINVAL;
+       }
+
+       ret = remap_vmalloc_range(vma, buf->vaddr, 0);
+       if (ret) {
+               printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * Make sure that vm_areas for 2 buffers won't be merged together
+        */
+       vma->vm_flags           |= VM_DONTEXPAND;
+
+       /*
+        * Use common vm_area operations to track buffer refcount.
+        */
+       vma->vm_private_data    = &buf->handler;
+       vma->vm_ops             = &vb2_common_vm_ops;
+
+       vma->vm_ops->open(vma);
+
+       return 0;
+}
+
+const struct vb2_mem_ops vb2_vmalloc_memops = {
+       .alloc          = vb2_vmalloc_alloc,
+       .put            = vb2_vmalloc_put,
+       .vaddr          = vb2_vmalloc_vaddr,
+       .mmap           = vb2_vmalloc_mmap,
+       .num_users      = vb2_vmalloc_num_users,
+};
+EXPORT_SYMBOL_GPL(vb2_vmalloc_memops);
+
+MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2");
+MODULE_AUTHOR("Pawel Osciak");
+MODULE_LICENSE("GPL");
diff --git a/include/media/videobuf2-vmalloc.h b/include/media/videobuf2-vmalloc.h
new file mode 100644 (file)
index 0000000..a76b8af
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * videobuf2-vmalloc.h - vmalloc memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <p.osciak@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _MEDIA_VIDEOBUF2_VMALLOC_H
+#define _MEDIA_VIDEOBUF2_VMALLOC_H
+
+#include <media/videobuf2-core.h>
+
+extern const struct vb2_mem_ops vb2_vmalloc_memops;
+
+#endif