PageRenderTime 36ms CodeModel.GetById 27ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/media/video/videobuf2-vmalloc.c

https://bitbucket.org/ndreys/linux-sunxi
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");