aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/videobuf2-vmalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/videobuf2-vmalloc.c')
-rw-r--r--drivers/media/video/videobuf2-vmalloc.c90
1 files changed, 78 insertions, 12 deletions
diff --git a/drivers/media/video/videobuf2-vmalloc.c b/drivers/media/video/videobuf2-vmalloc.c
index a3a884234059..4e789a178f8a 100644
--- a/drivers/media/video/videobuf2-vmalloc.c
+++ b/drivers/media/video/videobuf2-vmalloc.c
@@ -12,6 +12,7 @@
12 12
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/mm.h> 14#include <linux/mm.h>
15#include <linux/sched.h>
15#include <linux/slab.h> 16#include <linux/slab.h>
16#include <linux/vmalloc.h> 17#include <linux/vmalloc.h>
17 18
@@ -20,7 +21,10 @@
20 21
21struct vb2_vmalloc_buf { 22struct vb2_vmalloc_buf {
22 void *vaddr; 23 void *vaddr;
24 struct page **pages;
25 int write;
23 unsigned long size; 26 unsigned long size;
27 unsigned int n_pages;
24 atomic_t refcount; 28 atomic_t refcount;
25 struct vb2_vmarea_handler handler; 29 struct vb2_vmarea_handler handler;
26}; 30};
@@ -31,7 +35,7 @@ static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
31{ 35{
32 struct vb2_vmalloc_buf *buf; 36 struct vb2_vmalloc_buf *buf;
33 37
34 buf = kzalloc(sizeof *buf, GFP_KERNEL); 38 buf = kzalloc(sizeof(*buf), GFP_KERNEL);
35 if (!buf) 39 if (!buf)
36 return NULL; 40 return NULL;
37 41
@@ -42,15 +46,12 @@ static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
42 buf->handler.arg = buf; 46 buf->handler.arg = buf;
43 47
44 if (!buf->vaddr) { 48 if (!buf->vaddr) {
45 printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size); 49 pr_debug("vmalloc of size %ld failed\n", buf->size);
46 kfree(buf); 50 kfree(buf);
47 return NULL; 51 return NULL;
48 } 52 }
49 53
50 atomic_inc(&buf->refcount); 54 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 return buf;
55} 56}
56 57
@@ -59,21 +60,84 @@ static void vb2_vmalloc_put(void *buf_priv)
59 struct vb2_vmalloc_buf *buf = buf_priv; 60 struct vb2_vmalloc_buf *buf = buf_priv;
60 61
61 if (atomic_dec_and_test(&buf->refcount)) { 62 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); 63 vfree(buf->vaddr);
65 kfree(buf); 64 kfree(buf);
66 } 65 }
67} 66}
68 67
69static void *vb2_vmalloc_vaddr(void *buf_priv) 68static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
69 unsigned long size, int write)
70{
71 struct vb2_vmalloc_buf *buf;
72 unsigned long first, last;
73 int n_pages, offset;
74
75 buf = kzalloc(sizeof(*buf), GFP_KERNEL);
76 if (!buf)
77 return NULL;
78
79 buf->write = write;
80 offset = vaddr & ~PAGE_MASK;
81 buf->size = size;
82
83 first = vaddr >> PAGE_SHIFT;
84 last = (vaddr + size - 1) >> PAGE_SHIFT;
85 buf->n_pages = last - first + 1;
86 buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), GFP_KERNEL);
87 if (!buf->pages)
88 goto fail_pages_array_alloc;
89
90 /* current->mm->mmap_sem is taken by videobuf2 core */
91 n_pages = get_user_pages(current, current->mm, vaddr & PAGE_MASK,
92 buf->n_pages, write, 1, /* force */
93 buf->pages, NULL);
94 if (n_pages != buf->n_pages)
95 goto fail_get_user_pages;
96
97 buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, PAGE_KERNEL);
98 if (!buf->vaddr)
99 goto fail_get_user_pages;
100
101 buf->vaddr += offset;
102 return buf;
103
104fail_get_user_pages:
105 pr_debug("get_user_pages requested/got: %d/%d]\n", n_pages,
106 buf->n_pages);
107 while (--n_pages >= 0)
108 put_page(buf->pages[n_pages]);
109 kfree(buf->pages);
110
111fail_pages_array_alloc:
112 kfree(buf);
113
114 return NULL;
115}
116
117static void vb2_vmalloc_put_userptr(void *buf_priv)
70{ 118{
71 struct vb2_vmalloc_buf *buf = buf_priv; 119 struct vb2_vmalloc_buf *buf = buf_priv;
120 unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK;
121 unsigned int i;
122
123 if (vaddr)
124 vm_unmap_ram((void *)vaddr, buf->n_pages);
125 for (i = 0; i < buf->n_pages; ++i) {
126 if (buf->write)
127 set_page_dirty_lock(buf->pages[i]);
128 put_page(buf->pages[i]);
129 }
130 kfree(buf->pages);
131 kfree(buf);
132}
72 133
73 BUG_ON(!buf); 134static void *vb2_vmalloc_vaddr(void *buf_priv)
135{
136 struct vb2_vmalloc_buf *buf = buf_priv;
74 137
75 if (!buf->vaddr) { 138 if (!buf->vaddr) {
76 printk(KERN_ERR "Address of an unallocated plane requested\n"); 139 pr_err("Address of an unallocated plane requested "
140 "or cannot map user pointer\n");
77 return NULL; 141 return NULL;
78 } 142 }
79 143
@@ -92,13 +156,13 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
92 int ret; 156 int ret;
93 157
94 if (!buf) { 158 if (!buf) {
95 printk(KERN_ERR "No memory to map\n"); 159 pr_err("No memory to map\n");
96 return -EINVAL; 160 return -EINVAL;
97 } 161 }
98 162
99 ret = remap_vmalloc_range(vma, buf->vaddr, 0); 163 ret = remap_vmalloc_range(vma, buf->vaddr, 0);
100 if (ret) { 164 if (ret) {
101 printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret); 165 pr_err("Remapping vmalloc memory, error: %d\n", ret);
102 return ret; 166 return ret;
103 } 167 }
104 168
@@ -121,6 +185,8 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
121const struct vb2_mem_ops vb2_vmalloc_memops = { 185const struct vb2_mem_ops vb2_vmalloc_memops = {
122 .alloc = vb2_vmalloc_alloc, 186 .alloc = vb2_vmalloc_alloc,
123 .put = vb2_vmalloc_put, 187 .put = vb2_vmalloc_put,
188 .get_userptr = vb2_vmalloc_get_userptr,
189 .put_userptr = vb2_vmalloc_put_userptr,
124 .vaddr = vb2_vmalloc_vaddr, 190 .vaddr = vb2_vmalloc_vaddr,
125 .mmap = vb2_vmalloc_mmap, 191 .mmap = vb2_vmalloc_mmap,
126 .num_users = vb2_vmalloc_num_users, 192 .num_users = vb2_vmalloc_num_users,