/drivers/media/video/videobuf2-vmalloc.c
C | 132 lines | 89 code | 26 blank | 17 comment | 6 complexity | b82648067c028f03a06d9e4c19af303c MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
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");