2 * videobuf2-dma-sg.c - dma scatter/gather memory allocator for videobuf2
4 * Copyright (C) 2010 Samsung Electronics
6 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.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.
13 #include <linux/module.h>
15 #include <linux/scatterlist.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-memops.h>
22 #include <media/videobuf2-dma-sg.h>
24 struct vb2_dma_sg_buf
{
29 struct vb2_dma_sg_desc sg_desc
;
31 struct vb2_vmarea_handler handler
;
34 static void vb2_dma_sg_put(void *buf_priv
);
36 static void *vb2_dma_sg_alloc(void *alloc_ctx
, unsigned long size
)
38 struct vb2_dma_sg_buf
*buf
;
41 buf
= kzalloc(sizeof *buf
, GFP_KERNEL
);
48 buf
->sg_desc
.size
= size
;
49 buf
->sg_desc
.num_pages
= (size
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
51 buf
->sg_desc
.sglist
= vmalloc(buf
->sg_desc
.num_pages
*
52 sizeof(*buf
->sg_desc
.sglist
));
53 if (!buf
->sg_desc
.sglist
)
54 goto fail_sglist_alloc
;
55 memset(buf
->sg_desc
.sglist
, 0, buf
->sg_desc
.num_pages
*
56 sizeof(*buf
->sg_desc
.sglist
));
57 sg_init_table(buf
->sg_desc
.sglist
, buf
->sg_desc
.num_pages
);
59 buf
->pages
= kzalloc(buf
->sg_desc
.num_pages
* sizeof(struct page
*),
62 goto fail_pages_array_alloc
;
64 for (i
= 0; i
< buf
->sg_desc
.num_pages
; ++i
) {
65 buf
->pages
[i
] = alloc_page(GFP_KERNEL
| __GFP_ZERO
);
66 if (NULL
== buf
->pages
[i
])
67 goto fail_pages_alloc
;
68 sg_set_page(&buf
->sg_desc
.sglist
[i
],
69 buf
->pages
[i
], PAGE_SIZE
, 0);
72 buf
->handler
.refcount
= &buf
->refcount
;
73 buf
->handler
.put
= vb2_dma_sg_put
;
74 buf
->handler
.arg
= buf
;
76 atomic_inc(&buf
->refcount
);
78 printk(KERN_DEBUG
"%s: Allocated buffer of %d pages\n",
79 __func__
, buf
->sg_desc
.num_pages
);
82 buf
->vaddr
= vm_map_ram(buf
->pages
,
83 buf
->sg_desc
.num_pages
,
90 __free_page(buf
->pages
[i
]);
93 fail_pages_array_alloc
:
94 vfree(buf
->sg_desc
.sglist
);
101 static void vb2_dma_sg_put(void *buf_priv
)
103 struct vb2_dma_sg_buf
*buf
= buf_priv
;
104 int i
= buf
->sg_desc
.num_pages
;
106 if (atomic_dec_and_test(&buf
->refcount
)) {
107 printk(KERN_DEBUG
"%s: Freeing buffer of %d pages\n", __func__
,
108 buf
->sg_desc
.num_pages
);
110 vm_unmap_ram(buf
->vaddr
, buf
->sg_desc
.num_pages
);
111 vfree(buf
->sg_desc
.sglist
);
113 __free_page(buf
->pages
[i
]);
119 static void *vb2_dma_sg_get_userptr(void *alloc_ctx
, unsigned long vaddr
,
120 unsigned long size
, int write
)
122 struct vb2_dma_sg_buf
*buf
;
123 unsigned long first
, last
;
124 int num_pages_from_user
, i
;
126 buf
= kzalloc(sizeof *buf
, GFP_KERNEL
);
132 buf
->offset
= vaddr
& ~PAGE_MASK
;
133 buf
->sg_desc
.size
= size
;
135 first
= (vaddr
& PAGE_MASK
) >> PAGE_SHIFT
;
136 last
= ((vaddr
+ size
- 1) & PAGE_MASK
) >> PAGE_SHIFT
;
137 buf
->sg_desc
.num_pages
= last
- first
+ 1;
139 buf
->sg_desc
.sglist
= vmalloc(
140 buf
->sg_desc
.num_pages
* sizeof(*buf
->sg_desc
.sglist
));
141 if (!buf
->sg_desc
.sglist
)
142 goto userptr_fail_sglist_alloc
;
144 memset(buf
->sg_desc
.sglist
, 0,
145 buf
->sg_desc
.num_pages
* sizeof(*buf
->sg_desc
.sglist
));
146 sg_init_table(buf
->sg_desc
.sglist
, buf
->sg_desc
.num_pages
);
148 buf
->pages
= kzalloc(buf
->sg_desc
.num_pages
* sizeof(struct page
*),
151 goto userptr_fail_pages_array_alloc
;
153 down_read(¤t
->mm
->mmap_sem
);
154 num_pages_from_user
= get_user_pages(current
, current
->mm
,
156 buf
->sg_desc
.num_pages
,
161 up_read(¤t
->mm
->mmap_sem
);
162 if (num_pages_from_user
!= buf
->sg_desc
.num_pages
)
163 goto userptr_fail_get_user_pages
;
165 sg_set_page(&buf
->sg_desc
.sglist
[0], buf
->pages
[0],
166 PAGE_SIZE
- buf
->offset
, buf
->offset
);
167 size
-= PAGE_SIZE
- buf
->offset
;
168 for (i
= 1; i
< buf
->sg_desc
.num_pages
; ++i
) {
169 sg_set_page(&buf
->sg_desc
.sglist
[i
], buf
->pages
[i
],
170 min_t(size_t, PAGE_SIZE
, size
), 0);
171 size
-= min_t(size_t, PAGE_SIZE
, size
);
175 userptr_fail_get_user_pages
:
176 printk(KERN_DEBUG
"get_user_pages requested/got: %d/%d]\n",
177 num_pages_from_user
, buf
->sg_desc
.num_pages
);
178 while (--num_pages_from_user
>= 0)
179 put_page(buf
->pages
[num_pages_from_user
]);
182 userptr_fail_pages_array_alloc
:
183 vfree(buf
->sg_desc
.sglist
);
185 userptr_fail_sglist_alloc
:
191 * @put_userptr: inform the allocator that a USERPTR buffer will no longer
194 static void vb2_dma_sg_put_userptr(void *buf_priv
)
196 struct vb2_dma_sg_buf
*buf
= buf_priv
;
197 int i
= buf
->sg_desc
.num_pages
;
199 printk(KERN_DEBUG
"%s: Releasing userspace buffer of %d pages\n",
200 __func__
, buf
->sg_desc
.num_pages
);
202 vm_unmap_ram(buf
->vaddr
, buf
->sg_desc
.num_pages
);
205 set_page_dirty_lock(buf
->pages
[i
]);
206 put_page(buf
->pages
[i
]);
208 vfree(buf
->sg_desc
.sglist
);
213 static void *vb2_dma_sg_vaddr(void *buf_priv
)
215 struct vb2_dma_sg_buf
*buf
= buf_priv
;
220 buf
->vaddr
= vm_map_ram(buf
->pages
,
221 buf
->sg_desc
.num_pages
,
225 /* add offset in case userptr is not page-aligned */
226 return buf
->vaddr
+ buf
->offset
;
229 static unsigned int vb2_dma_sg_num_users(void *buf_priv
)
231 struct vb2_dma_sg_buf
*buf
= buf_priv
;
233 return atomic_read(&buf
->refcount
);
236 static int vb2_dma_sg_mmap(void *buf_priv
, struct vm_area_struct
*vma
)
238 struct vb2_dma_sg_buf
*buf
= buf_priv
;
239 unsigned long uaddr
= vma
->vm_start
;
240 unsigned long usize
= vma
->vm_end
- vma
->vm_start
;
244 printk(KERN_ERR
"No memory to map\n");
251 ret
= vm_insert_page(vma
, uaddr
, buf
->pages
[i
++]);
253 printk(KERN_ERR
"Remapping memory, error: %d\n", ret
);
263 * Use common vm_area operations to track buffer refcount.
265 vma
->vm_private_data
= &buf
->handler
;
266 vma
->vm_ops
= &vb2_common_vm_ops
;
268 vma
->vm_ops
->open(vma
);
273 static void *vb2_dma_sg_cookie(void *buf_priv
)
275 struct vb2_dma_sg_buf
*buf
= buf_priv
;
277 return &buf
->sg_desc
;
280 const struct vb2_mem_ops vb2_dma_sg_memops
= {
281 .alloc
= vb2_dma_sg_alloc
,
282 .put
= vb2_dma_sg_put
,
283 .get_userptr
= vb2_dma_sg_get_userptr
,
284 .put_userptr
= vb2_dma_sg_put_userptr
,
285 .vaddr
= vb2_dma_sg_vaddr
,
286 .mmap
= vb2_dma_sg_mmap
,
287 .num_users
= vb2_dma_sg_num_users
,
288 .cookie
= vb2_dma_sg_cookie
,
290 EXPORT_SYMBOL_GPL(vb2_dma_sg_memops
);
292 MODULE_DESCRIPTION("dma scatter/gather memory handling routines for videobuf2");
293 MODULE_AUTHOR("Andrzej Pietrasiewicz");
294 MODULE_LICENSE("GPL");