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