linux/drivers/media/video/videobuf2-vmalloc.c
<<
>>
Prefs
   1/*
   2 * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
   3 *
   4 * Copyright (C) 2010 Samsung Electronics
   5 *
   6 * Author: Pawel Osciak <pawel@osciak.com>
   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.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/mm.h>
  15#include <linux/slab.h>
  16#include <linux/vmalloc.h>
  17
  18#include <media/videobuf2-core.h>
  19#include <media/videobuf2-memops.h>
  20
  21struct vb2_vmalloc_buf {
  22        void                            *vaddr;
  23        unsigned long                   size;
  24        atomic_t                        refcount;
  25        struct vb2_vmarea_handler       handler;
  26};
  27
  28static void vb2_vmalloc_put(void *buf_priv);
  29
  30static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
  31{
  32        struct vb2_vmalloc_buf *buf;
  33
  34        buf = kzalloc(sizeof *buf, GFP_KERNEL);
  35        if (!buf)
  36                return NULL;
  37
  38        buf->size = size;
  39        buf->vaddr = vmalloc_user(buf->size);
  40        buf->handler.refcount = &buf->refcount;
  41        buf->handler.put = vb2_vmalloc_put;
  42        buf->handler.arg = buf;
  43
  44        if (!buf->vaddr) {
  45                printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size);
  46                kfree(buf);
  47                return NULL;
  48        }
  49
  50        atomic_inc(&buf->refcount);
  51        printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n",
  52                        buf->size, buf->vaddr);
  53
  54        return buf;
  55}
  56
  57static void vb2_vmalloc_put(void *buf_priv)
  58{
  59        struct vb2_vmalloc_buf *buf = buf_priv;
  60
  61        if (atomic_dec_and_test(&buf->refcount)) {
  62                printk(KERN_DEBUG "%s: Freeing vmalloc mem at vaddr=%p\n",
  63                        __func__, buf->vaddr);
  64                vfree(buf->vaddr);
  65                kfree(buf);
  66        }
  67}
  68
  69static void *vb2_vmalloc_vaddr(void *buf_priv)
  70{
  71        struct vb2_vmalloc_buf *buf = buf_priv;
  72
  73        BUG_ON(!buf);
  74
  75        if (!buf->vaddr) {
  76                printk(KERN_ERR "Address of an unallocated plane requested\n");
  77                return NULL;
  78        }
  79
  80        return buf->vaddr;
  81}
  82
  83static unsigned int vb2_vmalloc_num_users(void *buf_priv)
  84{
  85        struct vb2_vmalloc_buf *buf = buf_priv;
  86        return atomic_read(&buf->refcount);
  87}
  88
  89static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
  90{
  91        struct vb2_vmalloc_buf *buf = buf_priv;
  92        int ret;
  93
  94        if (!buf) {
  95                printk(KERN_ERR "No memory to map\n");
  96                return -EINVAL;
  97        }
  98
  99        ret = remap_vmalloc_range(vma, buf->vaddr, 0);
 100        if (ret) {
 101                printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret);
 102                return ret;
 103        }
 104
 105        /*
 106         * Make sure that vm_areas for 2 buffers won't be merged together
 107         */
 108        vma->vm_flags           |= VM_DONTEXPAND;
 109
 110        /*
 111         * Use common vm_area operations to track buffer refcount.
 112         */
 113        vma->vm_private_data    = &buf->handler;
 114        vma->vm_ops             = &vb2_common_vm_ops;
 115
 116        vma->vm_ops->open(vma);
 117
 118        return 0;
 119}
 120
 121const struct vb2_mem_ops vb2_vmalloc_memops = {
 122        .alloc          = vb2_vmalloc_alloc,
 123        .put            = vb2_vmalloc_put,
 124        .vaddr          = vb2_vmalloc_vaddr,
 125        .mmap           = vb2_vmalloc_mmap,
 126        .num_users      = vb2_vmalloc_num_users,
 127};
 128EXPORT_SYMBOL_GPL(vb2_vmalloc_memops);
 129
 130MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2");
 131MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
 132MODULE_LICENSE("GPL");
 133