2 * helper functions for physically contiguous capture buffers
4 * The functions support hardware lacking scatter gather support
5 * (i.e. the buffers must be linear in physical memory)
7 * Copyright (c) 2008 Magnus Damm
9 * Based on videobuf-vmalloc.c,
10 * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
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
17 #include <linux/init.h>
18 #include <linux/module.h>
20 #include <linux/pagemap.h>
21 #include <linux/dma-mapping.h>
22 #include <linux/sched.h>
23 #include <linux/slab.h>
24 #include <media/videobuf-dma-contig.h>
26 struct videobuf_dma_contig_memory {
29 dma_addr_t dma_handle;
33 #define MAGIC_DC_MEM 0x0733ac61
34 #define MAGIC_CHECK(is, should) \
35 if (unlikely((is) != (should))) { \
36 pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
40 static int __videobuf_dc_alloc(struct device *dev,
41 struct videobuf_dma_contig_memory *mem,
42 unsigned long size, gfp_t flags)
45 mem->vaddr = dma_alloc_coherent(dev, mem->size,
46 &mem->dma_handle, flags);
49 dev_err(dev, "memory alloc size %ld failed\n", mem->size);
53 dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size);
58 static void __videobuf_dc_free(struct device *dev,
59 struct videobuf_dma_contig_memory *mem)
61 dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
66 static void videobuf_vm_open(struct vm_area_struct *vma)
68 struct videobuf_mapping *map = vma->vm_private_data;
69 struct videobuf_queue *q = map->q;
71 dev_dbg(q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
72 map, map->count, vma->vm_start, vma->vm_end);
74 videobuf_queue_lock(q);
76 videobuf_queue_unlock(q);
79 static void videobuf_vm_close(struct vm_area_struct *vma)
81 struct videobuf_mapping *map = vma->vm_private_data;
82 struct videobuf_queue *q = map->q;
85 dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
86 map, map->count, vma->vm_start, vma->vm_end);
88 videobuf_queue_lock(q);
90 struct videobuf_dma_contig_memory *mem;
92 dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
94 /* We need first to cancel streams, before unmapping */
96 videobuf_queue_cancel(q);
98 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
99 if (NULL == q->bufs[i])
102 if (q->bufs[i]->map != map)
105 mem = q->bufs[i]->priv;
107 /* This callback is called only if kernel has
108 allocated memory and this memory is mmapped.
109 In this case, memory should be freed,
110 in order to do memory unmap.
113 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
115 /* vfree is not atomic - can't be
116 called with IRQ's disabled
118 dev_dbg(q->dev, "buf[%d] freeing %p\n",
121 __videobuf_dc_free(q->dev, mem);
125 q->bufs[i]->map = NULL;
126 q->bufs[i]->baddr = 0;
132 videobuf_queue_unlock(q);
135 static const struct vm_operations_struct videobuf_vm_ops = {
136 .open = videobuf_vm_open,
137 .close = videobuf_vm_close,
141 * videobuf_dma_contig_user_put() - reset pointer to user space buffer
142 * @mem: per-buffer private videobuf-dma-contig data
144 * This function resets the user space pointer
146 static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
153 * videobuf_dma_contig_user_get() - setup user space memory pointer
154 * @mem: per-buffer private videobuf-dma-contig data
155 * @vb: video buffer to map
157 * This function validates and sets up a pointer to user space memory.
158 * Only physically contiguous pfn-mapped memory is accepted.
160 * Returns 0 if successful.
162 static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
163 struct videobuf_buffer *vb)
165 struct mm_struct *mm = current->mm;
166 struct vm_area_struct *vma;
167 unsigned long prev_pfn, this_pfn;
168 unsigned long pages_done, user_address;
172 offset = vb->baddr & ~PAGE_MASK;
173 mem->size = PAGE_ALIGN(vb->size + offset);
176 down_read(&mm->mmap_sem);
178 vma = find_vma(mm, vb->baddr);
182 if ((vb->baddr + mem->size) > vma->vm_end)
186 prev_pfn = 0; /* kill warning */
187 user_address = vb->baddr;
189 while (pages_done < (mem->size >> PAGE_SHIFT)) {
190 ret = follow_pfn(vma, user_address, &this_pfn);
195 mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
196 else if (this_pfn != (prev_pfn + 1))
203 user_address += PAGE_SIZE;
208 up_read(¤t->mm->mmap_sem);
213 static struct videobuf_buffer *__videobuf_alloc(size_t size)
215 struct videobuf_dma_contig_memory *mem;
216 struct videobuf_buffer *vb;
218 vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
220 vb->priv = ((char *)vb) + size;
222 mem->magic = MAGIC_DC_MEM;
228 static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
230 struct videobuf_dma_contig_memory *mem = buf->priv;
233 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
238 static int __videobuf_iolock(struct videobuf_queue *q,
239 struct videobuf_buffer *vb,
240 struct v4l2_framebuffer *fbuf)
242 struct videobuf_dma_contig_memory *mem = vb->priv;
245 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
247 switch (vb->memory) {
248 case V4L2_MEMORY_MMAP:
249 dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
251 /* All handling should be done by __videobuf_mmap_mapper() */
253 dev_err(q->dev, "memory is not alloced/mmapped.\n");
257 case V4L2_MEMORY_USERPTR:
258 dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
260 /* handle pointer from user space */
262 return videobuf_dma_contig_user_get(mem, vb);
264 /* allocate memory for the read() method */
265 if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size),
269 case V4L2_MEMORY_OVERLAY:
271 dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__);
278 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
279 struct videobuf_buffer *buf,
280 struct vm_area_struct *vma)
282 struct videobuf_dma_contig_memory *mem;
283 struct videobuf_mapping *map;
287 dev_dbg(q->dev, "%s\n", __func__);
289 /* create mapping + update buffer list */
290 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
297 buf->baddr = vma->vm_start;
301 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
303 if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize),
304 GFP_KERNEL | __GFP_COMP))
307 /* Try to remap memory */
308 size = vma->vm_end - vma->vm_start;
309 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
310 retval = vm_iomap_memory(vma, vma->vm_start, size);
312 dev_err(q->dev, "mmap: remap failed with error %d. ",
314 dma_free_coherent(q->dev, mem->size,
315 mem->vaddr, mem->dma_handle);
319 vma->vm_ops = &videobuf_vm_ops;
320 vma->vm_flags |= VM_DONTEXPAND;
321 vma->vm_private_data = map;
323 dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
324 map, q, vma->vm_start, vma->vm_end,
325 (long int)buf->bsize, vma->vm_pgoff, buf->i);
327 videobuf_vm_open(vma);
336 static struct videobuf_qtype_ops qops = {
337 .magic = MAGIC_QTYPE_OPS,
338 .alloc_vb = __videobuf_alloc,
339 .iolock = __videobuf_iolock,
340 .mmap_mapper = __videobuf_mmap_mapper,
341 .vaddr = __videobuf_to_vaddr,
344 void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
345 const struct videobuf_queue_ops *ops,
348 enum v4l2_buf_type type,
349 enum v4l2_field field,
352 struct mutex *ext_lock)
354 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
355 priv, &qops, ext_lock);
357 EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
359 dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
361 struct videobuf_dma_contig_memory *mem = buf->priv;
364 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
366 return mem->dma_handle;
368 EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
370 void videobuf_dma_contig_free(struct videobuf_queue *q,
371 struct videobuf_buffer *buf)
373 struct videobuf_dma_contig_memory *mem = buf->priv;
375 /* mmapped memory can't be freed here, otherwise mmapped region
376 would be released, while still needed. In this case, the memory
377 release should happen inside videobuf_vm_close().
378 So, it should free memory only if the memory were allocated for
381 if (buf->memory != V4L2_MEMORY_USERPTR)
387 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
389 /* handle user space pointer case */
391 videobuf_dma_contig_user_put(mem);
397 __videobuf_dc_free(q->dev, mem);
401 EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
403 MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
404 MODULE_AUTHOR("Magnus Damm");
405 MODULE_LICENSE("GPL");