2 * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
4 * Copyright (C) 2010 Samsung Electronics
6 * Author: Pawel Osciak <pawel@osciak.com>
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.
14 #include <linux/module.h>
16 #include <linux/sched.h>
17 #include <linux/slab.h>
18 #include <linux/vmalloc.h>
20 #include <media/videobuf2-core.h>
21 #include <media/videobuf2-vmalloc.h>
22 #include <media/videobuf2-memops.h>
24 struct vb2_vmalloc_buf
{
27 struct vm_area_struct
*vma
;
32 struct vb2_vmarea_handler handler
;
36 static void vb2_vmalloc_put(void *buf_priv
);
38 static void *vb2_vmalloc_alloc(void *alloc_ctx
, unsigned long size
, gfp_t gfp_flags
)
40 struct vb2_vmalloc_buf
*buf
;
42 buf
= kzalloc(sizeof(*buf
), GFP_KERNEL
| gfp_flags
);
47 buf
->vaddr
= vmalloc_user(buf
->size
);
48 buf
->handler
.refcount
= &buf
->refcount
;
49 buf
->handler
.put
= vb2_vmalloc_put
;
50 buf
->handler
.arg
= buf
;
53 pr_debug("vmalloc of size %ld failed\n", buf
->size
);
58 atomic_inc(&buf
->refcount
);
62 static void vb2_vmalloc_put(void *buf_priv
)
64 struct vb2_vmalloc_buf
*buf
= buf_priv
;
66 if (atomic_dec_and_test(&buf
->refcount
)) {
72 static void *vb2_vmalloc_get_userptr(void *alloc_ctx
, unsigned long vaddr
,
73 unsigned long size
, int write
)
75 struct vb2_vmalloc_buf
*buf
;
76 unsigned long first
, last
;
78 struct vm_area_struct
*vma
;
81 buf
= kzalloc(sizeof(*buf
), GFP_KERNEL
);
86 offset
= vaddr
& ~PAGE_MASK
;
90 vma
= find_vma(current
->mm
, vaddr
);
91 if (vma
&& (vma
->vm_flags
& VM_PFNMAP
) && (vma
->vm_pgoff
)) {
92 if (vb2_get_contig_userptr(vaddr
, size
, &vma
, &physp
))
93 goto fail_pages_array_alloc
;
95 buf
->vaddr
= ioremap_nocache(physp
, size
);
97 goto fail_pages_array_alloc
;
99 first
= vaddr
>> PAGE_SHIFT
;
100 last
= (vaddr
+ size
- 1) >> PAGE_SHIFT
;
101 buf
->n_pages
= last
- first
+ 1;
102 buf
->pages
= kzalloc(buf
->n_pages
* sizeof(struct page
*),
105 goto fail_pages_array_alloc
;
107 /* current->mm->mmap_sem is taken by videobuf2 core */
108 n_pages
= get_user_pages(current
, current
->mm
,
109 vaddr
& PAGE_MASK
, buf
->n_pages
,
110 write
, 1, /* force */
112 if (n_pages
!= buf
->n_pages
)
113 goto fail_get_user_pages
;
115 buf
->vaddr
= vm_map_ram(buf
->pages
, buf
->n_pages
, -1,
118 goto fail_get_user_pages
;
121 buf
->vaddr
+= offset
;
125 pr_debug("get_user_pages requested/got: %d/%d]\n", n_pages
,
127 while (--n_pages
>= 0)
128 put_page(buf
->pages
[n_pages
]);
131 fail_pages_array_alloc
:
137 static void vb2_vmalloc_put_userptr(void *buf_priv
)
139 struct vb2_vmalloc_buf
*buf
= buf_priv
;
140 unsigned long vaddr
= (unsigned long)buf
->vaddr
& PAGE_MASK
;
145 vm_unmap_ram((void *)vaddr
, buf
->n_pages
);
146 for (i
= 0; i
< buf
->n_pages
; ++i
) {
148 set_page_dirty_lock(buf
->pages
[i
]);
149 put_page(buf
->pages
[i
]);
154 vb2_put_vma(buf
->vma
);
160 static void *vb2_vmalloc_vaddr(void *buf_priv
)
162 struct vb2_vmalloc_buf
*buf
= buf_priv
;
165 pr_err("Address of an unallocated plane requested "
166 "or cannot map user pointer\n");
173 static unsigned int vb2_vmalloc_num_users(void *buf_priv
)
175 struct vb2_vmalloc_buf
*buf
= buf_priv
;
176 return atomic_read(&buf
->refcount
);
179 static int vb2_vmalloc_mmap(void *buf_priv
, struct vm_area_struct
*vma
)
181 struct vb2_vmalloc_buf
*buf
= buf_priv
;
185 pr_err("No memory to map\n");
189 ret
= remap_vmalloc_range(vma
, buf
->vaddr
, 0);
191 pr_err("Remapping vmalloc memory, error: %d\n", ret
);
196 * Make sure that vm_areas for 2 buffers won't be merged together
198 vma
->vm_flags
|= VM_DONTEXPAND
;
201 * Use common vm_area operations to track buffer refcount.
203 vma
->vm_private_data
= &buf
->handler
;
204 vma
->vm_ops
= &vb2_common_vm_ops
;
206 vma
->vm_ops
->open(vma
);
211 /*********************************************/
212 /* callbacks for DMABUF buffers */
213 /*********************************************/
215 static int vb2_vmalloc_map_dmabuf(void *mem_priv
)
217 struct vb2_vmalloc_buf
*buf
= mem_priv
;
219 buf
->vaddr
= dma_buf_vmap(buf
->dbuf
);
221 return buf
->vaddr
? 0 : -EFAULT
;
224 static void vb2_vmalloc_unmap_dmabuf(void *mem_priv
)
226 struct vb2_vmalloc_buf
*buf
= mem_priv
;
228 dma_buf_vunmap(buf
->dbuf
, buf
->vaddr
);
232 static void vb2_vmalloc_detach_dmabuf(void *mem_priv
)
234 struct vb2_vmalloc_buf
*buf
= mem_priv
;
237 dma_buf_vunmap(buf
->dbuf
, buf
->vaddr
);
242 static void *vb2_vmalloc_attach_dmabuf(void *alloc_ctx
, struct dma_buf
*dbuf
,
243 unsigned long size
, int write
)
245 struct vb2_vmalloc_buf
*buf
;
247 if (dbuf
->size
< size
)
248 return ERR_PTR(-EFAULT
);
250 buf
= kzalloc(sizeof(*buf
), GFP_KERNEL
);
252 return ERR_PTR(-ENOMEM
);
262 const struct vb2_mem_ops vb2_vmalloc_memops
= {
263 .alloc
= vb2_vmalloc_alloc
,
264 .put
= vb2_vmalloc_put
,
265 .get_userptr
= vb2_vmalloc_get_userptr
,
266 .put_userptr
= vb2_vmalloc_put_userptr
,
267 .map_dmabuf
= vb2_vmalloc_map_dmabuf
,
268 .unmap_dmabuf
= vb2_vmalloc_unmap_dmabuf
,
269 .attach_dmabuf
= vb2_vmalloc_attach_dmabuf
,
270 .detach_dmabuf
= vb2_vmalloc_detach_dmabuf
,
271 .vaddr
= vb2_vmalloc_vaddr
,
272 .mmap
= vb2_vmalloc_mmap
,
273 .num_users
= vb2_vmalloc_num_users
,
275 EXPORT_SYMBOL_GPL(vb2_vmalloc_memops
);
277 MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2");
278 MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
279 MODULE_LICENSE("GPL");