blob: 22c01097e8a821f95c04ae9d8ae9432623381d46 [file] [log] [blame]
Magnus Damm2cc45cf2008-07-16 21:33:39 -03001/*
2 * helper functions for physically contiguous capture buffers
3 *
4 * The functions support hardware lacking scatter gather support
5 * (i.e. the buffers must be linear in physical memory)
6 *
7 * Copyright (c) 2008 Magnus Damm
8 *
9 * Based on videobuf-vmalloc.c,
10 * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2
15 */
16
17#include <linux/init.h>
18#include <linux/module.h>
Hans Verkuilf19ad392008-07-18 02:02:50 -030019#include <linux/mm.h>
Magnus Damm720b17e2009-06-16 15:32:36 -070020#include <linux/pagemap.h>
Magnus Damm2cc45cf2008-07-16 21:33:39 -030021#include <linux/dma-mapping.h>
Guennadi Liakhovetskif39c1ab2009-11-09 16:11:34 -030022#include <linux/sched.h>
Magnus Damm2cc45cf2008-07-16 21:33:39 -030023#include <media/videobuf-dma-contig.h>
24
25struct videobuf_dma_contig_memory {
26 u32 magic;
27 void *vaddr;
28 dma_addr_t dma_handle;
29 unsigned long size;
Magnus Damm720b17e2009-06-16 15:32:36 -070030 int is_userptr;
Magnus Damm2cc45cf2008-07-16 21:33:39 -030031};
32
33#define MAGIC_DC_MEM 0x0733ac61
Guennadi Liakhovetskic60f2b52008-07-17 17:30:47 -030034#define MAGIC_CHECK(is, should) \
35 if (unlikely((is) != (should))) { \
36 pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
37 BUG(); \
Magnus Damm2cc45cf2008-07-16 21:33:39 -030038 }
39
40static void
41videobuf_vm_open(struct vm_area_struct *vma)
42{
43 struct videobuf_mapping *map = vma->vm_private_data;
44
45 dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
46 map, map->count, vma->vm_start, vma->vm_end);
47
48 map->count++;
49}
50
51static void videobuf_vm_close(struct vm_area_struct *vma)
52{
53 struct videobuf_mapping *map = vma->vm_private_data;
54 struct videobuf_queue *q = map->q;
55 int i;
56
57 dev_dbg(map->q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
58 map, map->count, vma->vm_start, vma->vm_end);
59
60 map->count--;
61 if (0 == map->count) {
62 struct videobuf_dma_contig_memory *mem;
63
64 dev_dbg(map->q->dev, "munmap %p q=%p\n", map, q);
65 mutex_lock(&q->vb_lock);
66
67 /* We need first to cancel streams, before unmapping */
68 if (q->streaming)
69 videobuf_queue_cancel(q);
70
71 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
72 if (NULL == q->bufs[i])
73 continue;
74
75 if (q->bufs[i]->map != map)
76 continue;
77
78 mem = q->bufs[i]->priv;
79 if (mem) {
80 /* This callback is called only if kernel has
81 allocated memory and this memory is mmapped.
82 In this case, memory should be freed,
83 in order to do memory unmap.
84 */
85
86 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
87
88 /* vfree is not atomic - can't be
89 called with IRQ's disabled
90 */
91 dev_dbg(map->q->dev, "buf[%d] freeing %p\n",
92 i, mem->vaddr);
93
94 dma_free_coherent(q->dev, mem->size,
95 mem->vaddr, mem->dma_handle);
96 mem->vaddr = NULL;
97 }
98
99 q->bufs[i]->map = NULL;
100 q->bufs[i]->baddr = 0;
101 }
102
103 kfree(map);
104
105 mutex_unlock(&q->vb_lock);
106 }
107}
108
Alexey Dobriyanf0f37e22009-09-27 22:29:37 +0400109static const struct vm_operations_struct videobuf_vm_ops = {
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300110 .open = videobuf_vm_open,
111 .close = videobuf_vm_close,
112};
113
Magnus Damm720b17e2009-06-16 15:32:36 -0700114/**
115 * videobuf_dma_contig_user_put() - reset pointer to user space buffer
116 * @mem: per-buffer private videobuf-dma-contig data
117 *
118 * This function resets the user space pointer
119 */
120static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
121{
122 mem->is_userptr = 0;
123 mem->dma_handle = 0;
124 mem->size = 0;
125}
126
127/**
128 * videobuf_dma_contig_user_get() - setup user space memory pointer
129 * @mem: per-buffer private videobuf-dma-contig data
130 * @vb: video buffer to map
131 *
132 * This function validates and sets up a pointer to user space memory.
133 * Only physically contiguous pfn-mapped memory is accepted.
134 *
135 * Returns 0 if successful.
136 */
137static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
138 struct videobuf_buffer *vb)
139{
140 struct mm_struct *mm = current->mm;
141 struct vm_area_struct *vma;
142 unsigned long prev_pfn, this_pfn;
143 unsigned long pages_done, user_address;
Muralidharan Karicheri31bedfa2009-12-10 16:47:48 -0300144 unsigned int offset;
Magnus Damm720b17e2009-06-16 15:32:36 -0700145 int ret;
146
Muralidharan Karicheri31bedfa2009-12-10 16:47:48 -0300147 offset = vb->baddr & ~PAGE_MASK;
148 mem->size = PAGE_ALIGN(vb->size + offset);
Magnus Damm720b17e2009-06-16 15:32:36 -0700149 mem->is_userptr = 0;
150 ret = -EINVAL;
151
152 down_read(&mm->mmap_sem);
153
154 vma = find_vma(mm, vb->baddr);
155 if (!vma)
156 goto out_up;
157
158 if ((vb->baddr + mem->size) > vma->vm_end)
159 goto out_up;
160
161 pages_done = 0;
162 prev_pfn = 0; /* kill warning */
163 user_address = vb->baddr;
164
165 while (pages_done < (mem->size >> PAGE_SHIFT)) {
166 ret = follow_pfn(vma, user_address, &this_pfn);
167 if (ret)
168 break;
169
170 if (pages_done == 0)
Muralidharan Karicheri31bedfa2009-12-10 16:47:48 -0300171 mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
Magnus Damm720b17e2009-06-16 15:32:36 -0700172 else if (this_pfn != (prev_pfn + 1))
173 ret = -EFAULT;
174
175 if (ret)
176 break;
177
178 prev_pfn = this_pfn;
179 user_address += PAGE_SIZE;
180 pages_done++;
181 }
182
183 if (!ret)
184 mem->is_userptr = 1;
185
186 out_up:
187 up_read(&current->mm->mmap_sem);
188
189 return ret;
190}
191
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300192static void *__videobuf_alloc(size_t size)
193{
194 struct videobuf_dma_contig_memory *mem;
195 struct videobuf_buffer *vb;
196
197 vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
198 if (vb) {
199 mem = vb->priv = ((char *)vb) + size;
200 mem->magic = MAGIC_DC_MEM;
201 }
202
203 return vb;
204}
205
206static void *__videobuf_to_vmalloc(struct videobuf_buffer *buf)
207{
208 struct videobuf_dma_contig_memory *mem = buf->priv;
209
210 BUG_ON(!mem);
211 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
212
213 return mem->vaddr;
214}
215
216static int __videobuf_iolock(struct videobuf_queue *q,
217 struct videobuf_buffer *vb,
218 struct v4l2_framebuffer *fbuf)
219{
220 struct videobuf_dma_contig_memory *mem = vb->priv;
221
222 BUG_ON(!mem);
223 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
224
225 switch (vb->memory) {
226 case V4L2_MEMORY_MMAP:
227 dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
228
229 /* All handling should be done by __videobuf_mmap_mapper() */
230 if (!mem->vaddr) {
231 dev_err(q->dev, "memory is not alloced/mmapped.\n");
232 return -EINVAL;
233 }
234 break;
235 case V4L2_MEMORY_USERPTR:
236 dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
237
Magnus Damm720b17e2009-06-16 15:32:36 -0700238 /* handle pointer from user space */
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300239 if (vb->baddr)
Magnus Damm720b17e2009-06-16 15:32:36 -0700240 return videobuf_dma_contig_user_get(mem, vb);
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300241
Magnus Damm720b17e2009-06-16 15:32:36 -0700242 /* allocate memory for the read() method */
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300243 mem->size = PAGE_ALIGN(vb->size);
244 mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
245 &mem->dma_handle, GFP_KERNEL);
246 if (!mem->vaddr) {
247 dev_err(q->dev, "dma_alloc_coherent %ld failed\n",
248 mem->size);
249 return -ENOMEM;
250 }
251
252 dev_dbg(q->dev, "dma_alloc_coherent data is at %p (%ld)\n",
253 mem->vaddr, mem->size);
254 break;
255 case V4L2_MEMORY_OVERLAY:
256 default:
257 dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n",
258 __func__);
259 return -EINVAL;
260 }
261
262 return 0;
263}
264
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300265static int __videobuf_mmap_free(struct videobuf_queue *q)
266{
267 unsigned int i;
268
269 dev_dbg(q->dev, "%s\n", __func__);
270 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
271 if (q->bufs[i] && q->bufs[i]->map)
272 return -EBUSY;
273 }
274
275 return 0;
276}
277
278static int __videobuf_mmap_mapper(struct videobuf_queue *q,
279 struct vm_area_struct *vma)
280{
281 struct videobuf_dma_contig_memory *mem;
282 struct videobuf_mapping *map;
283 unsigned int first;
284 int retval;
285 unsigned long size, offset = vma->vm_pgoff << PAGE_SHIFT;
286
287 dev_dbg(q->dev, "%s\n", __func__);
288 if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
289 return -EINVAL;
290
291 /* look for first buffer to map */
292 for (first = 0; first < VIDEO_MAX_FRAME; first++) {
293 if (!q->bufs[first])
294 continue;
295
296 if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
297 continue;
298 if (q->bufs[first]->boff == offset)
299 break;
300 }
301 if (VIDEO_MAX_FRAME == first) {
302 dev_dbg(q->dev, "invalid user space offset [offset=0x%lx]\n",
303 offset);
304 return -EINVAL;
305 }
306
307 /* create mapping + update buffer list */
308 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
309 if (!map)
310 return -ENOMEM;
311
312 q->bufs[first]->map = map;
313 map->start = vma->vm_start;
314 map->end = vma->vm_end;
315 map->q = q;
316
317 q->bufs[first]->baddr = vma->vm_start;
318
319 mem = q->bufs[first]->priv;
320 BUG_ON(!mem);
321 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
322
323 mem->size = PAGE_ALIGN(q->bufs[first]->bsize);
324 mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
325 &mem->dma_handle, GFP_KERNEL);
326 if (!mem->vaddr) {
327 dev_err(q->dev, "dma_alloc_coherent size %ld failed\n",
328 mem->size);
329 goto error;
330 }
331 dev_dbg(q->dev, "dma_alloc_coherent data is at addr %p (size %ld)\n",
332 mem->vaddr, mem->size);
333
334 /* Try to remap memory */
335
336 size = vma->vm_end - vma->vm_start;
337 size = (size < mem->size) ? size : mem->size;
338
339 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
340 retval = remap_pfn_range(vma, vma->vm_start,
341 mem->dma_handle >> PAGE_SHIFT,
342 size, vma->vm_page_prot);
343 if (retval) {
344 dev_err(q->dev, "mmap: remap failed with error %d. ", retval);
345 dma_free_coherent(q->dev, mem->size,
346 mem->vaddr, mem->dma_handle);
347 goto error;
348 }
349
350 vma->vm_ops = &videobuf_vm_ops;
351 vma->vm_flags |= VM_DONTEXPAND;
352 vma->vm_private_data = map;
353
354 dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
355 map, q, vma->vm_start, vma->vm_end,
356 (long int) q->bufs[first]->bsize,
357 vma->vm_pgoff, first);
358
359 videobuf_vm_open(vma);
360
361 return 0;
362
363error:
364 kfree(map);
365 return -ENOMEM;
366}
367
368static int __videobuf_copy_to_user(struct videobuf_queue *q,
369 char __user *data, size_t count,
370 int nonblocking)
371{
372 struct videobuf_dma_contig_memory *mem = q->read_buf->priv;
373 void *vaddr;
374
375 BUG_ON(!mem);
376 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
377 BUG_ON(!mem->vaddr);
378
379 /* copy to userspace */
380 if (count > q->read_buf->size - q->read_off)
381 count = q->read_buf->size - q->read_off;
382
383 vaddr = mem->vaddr;
384
385 if (copy_to_user(data, vaddr + q->read_off, count))
386 return -EFAULT;
387
388 return count;
389}
390
391static int __videobuf_copy_stream(struct videobuf_queue *q,
392 char __user *data, size_t count, size_t pos,
393 int vbihack, int nonblocking)
394{
395 unsigned int *fc;
396 struct videobuf_dma_contig_memory *mem = q->read_buf->priv;
397
398 BUG_ON(!mem);
399 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
400
401 if (vbihack) {
402 /* dirty, undocumented hack -- pass the frame counter
403 * within the last four bytes of each vbi data block.
404 * We need that one to maintain backward compatibility
405 * to all vbi decoding software out there ... */
406 fc = (unsigned int *)mem->vaddr;
407 fc += (q->read_buf->size >> 2) - 1;
408 *fc = q->read_buf->field_count >> 1;
409 dev_dbg(q->dev, "vbihack: %d\n", *fc);
410 }
411
412 /* copy stuff using the common method */
413 count = __videobuf_copy_to_user(q, data, count, nonblocking);
414
415 if ((count == -EFAULT) && (pos == 0))
416 return -EFAULT;
417
418 return count;
419}
420
421static struct videobuf_qtype_ops qops = {
422 .magic = MAGIC_QTYPE_OPS,
423
424 .alloc = __videobuf_alloc,
425 .iolock = __videobuf_iolock,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300426 .mmap_free = __videobuf_mmap_free,
427 .mmap_mapper = __videobuf_mmap_mapper,
428 .video_copy_to_user = __videobuf_copy_to_user,
429 .copy_stream = __videobuf_copy_stream,
430 .vmalloc = __videobuf_to_vmalloc,
431};
432
433void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
Jonathan Corbet38a54f32009-11-17 19:43:41 -0300434 const struct videobuf_queue_ops *ops,
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300435 struct device *dev,
436 spinlock_t *irqlock,
437 enum v4l2_buf_type type,
438 enum v4l2_field field,
439 unsigned int msize,
440 void *priv)
441{
442 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
443 priv, &qops);
444}
445EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
446
447dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
448{
449 struct videobuf_dma_contig_memory *mem = buf->priv;
450
451 BUG_ON(!mem);
452 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
453
454 return mem->dma_handle;
455}
456EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
457
458void videobuf_dma_contig_free(struct videobuf_queue *q,
459 struct videobuf_buffer *buf)
460{
461 struct videobuf_dma_contig_memory *mem = buf->priv;
462
463 /* mmapped memory can't be freed here, otherwise mmapped region
464 would be released, while still needed. In this case, the memory
465 release should happen inside videobuf_vm_close().
466 So, it should free memory only if the memory were allocated for
467 read() operation.
468 */
Magnus Damm720b17e2009-06-16 15:32:36 -0700469 if (buf->memory != V4L2_MEMORY_USERPTR)
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300470 return;
471
472 if (!mem)
473 return;
474
475 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
476
Magnus Damm720b17e2009-06-16 15:32:36 -0700477 /* handle user space pointer case */
478 if (buf->baddr) {
479 videobuf_dma_contig_user_put(mem);
480 return;
481 }
482
483 /* read() method */
Magnus Damm2cc45cf2008-07-16 21:33:39 -0300484 dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
485 mem->vaddr = NULL;
486}
487EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
488
489MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
490MODULE_AUTHOR("Magnus Damm");
491MODULE_LICENSE("GPL");