177512baaSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25bc3cb74SMauro Carvalho Chehab /*
35bc3cb74SMauro Carvalho Chehab * helper functions for physically contiguous capture buffers
45bc3cb74SMauro Carvalho Chehab *
55bc3cb74SMauro Carvalho Chehab * The functions support hardware lacking scatter gather support
65bc3cb74SMauro Carvalho Chehab * (i.e. the buffers must be linear in physical memory)
75bc3cb74SMauro Carvalho Chehab *
85bc3cb74SMauro Carvalho Chehab * Copyright (c) 2008 Magnus Damm
95bc3cb74SMauro Carvalho Chehab *
105bc3cb74SMauro Carvalho Chehab * Based on videobuf-vmalloc.c,
1132590819SMauro Carvalho Chehab * (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org>
125bc3cb74SMauro Carvalho Chehab */
135bc3cb74SMauro Carvalho Chehab
145bc3cb74SMauro Carvalho Chehab #include <linux/init.h>
155bc3cb74SMauro Carvalho Chehab #include <linux/module.h>
165bc3cb74SMauro Carvalho Chehab #include <linux/mm.h>
175bc3cb74SMauro Carvalho Chehab #include <linux/pagemap.h>
185bc3cb74SMauro Carvalho Chehab #include <linux/dma-mapping.h>
195bc3cb74SMauro Carvalho Chehab #include <linux/sched.h>
205bc3cb74SMauro Carvalho Chehab #include <linux/slab.h>
215bc3cb74SMauro Carvalho Chehab #include <media/videobuf-dma-contig.h>
225bc3cb74SMauro Carvalho Chehab
235bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory {
245bc3cb74SMauro Carvalho Chehab u32 magic;
255bc3cb74SMauro Carvalho Chehab void *vaddr;
265bc3cb74SMauro Carvalho Chehab dma_addr_t dma_handle;
275bc3cb74SMauro Carvalho Chehab unsigned long size;
285bc3cb74SMauro Carvalho Chehab };
295bc3cb74SMauro Carvalho Chehab
305bc3cb74SMauro Carvalho Chehab #define MAGIC_DC_MEM 0x0733ac61
315bc3cb74SMauro Carvalho Chehab #define MAGIC_CHECK(is, should) \
325bc3cb74SMauro Carvalho Chehab if (unlikely((is) != (should))) { \
335bc3cb74SMauro Carvalho Chehab pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
345bc3cb74SMauro Carvalho Chehab BUG(); \
355bc3cb74SMauro Carvalho Chehab }
365bc3cb74SMauro Carvalho Chehab
__videobuf_dc_alloc(struct device * dev,struct videobuf_dma_contig_memory * mem,unsigned long size)375bc3cb74SMauro Carvalho Chehab static int __videobuf_dc_alloc(struct device *dev,
385bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem,
39b3dc3f8eSChristoph Hellwig unsigned long size)
405bc3cb74SMauro Carvalho Chehab {
415bc3cb74SMauro Carvalho Chehab mem->size = size;
42b3dc3f8eSChristoph Hellwig mem->vaddr = dma_alloc_coherent(dev, mem->size, &mem->dma_handle,
43b3dc3f8eSChristoph Hellwig GFP_KERNEL);
445bc3cb74SMauro Carvalho Chehab if (!mem->vaddr) {
455bc3cb74SMauro Carvalho Chehab dev_err(dev, "memory alloc size %ld failed\n", mem->size);
465bc3cb74SMauro Carvalho Chehab return -ENOMEM;
475bc3cb74SMauro Carvalho Chehab }
485bc3cb74SMauro Carvalho Chehab
495bc3cb74SMauro Carvalho Chehab dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size);
505bc3cb74SMauro Carvalho Chehab
515bc3cb74SMauro Carvalho Chehab return 0;
525bc3cb74SMauro Carvalho Chehab }
535bc3cb74SMauro Carvalho Chehab
__videobuf_dc_free(struct device * dev,struct videobuf_dma_contig_memory * mem)545bc3cb74SMauro Carvalho Chehab static void __videobuf_dc_free(struct device *dev,
555bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem)
565bc3cb74SMauro Carvalho Chehab {
575bc3cb74SMauro Carvalho Chehab dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
585bc3cb74SMauro Carvalho Chehab
595bc3cb74SMauro Carvalho Chehab mem->vaddr = NULL;
605bc3cb74SMauro Carvalho Chehab }
615bc3cb74SMauro Carvalho Chehab
videobuf_vm_open(struct vm_area_struct * vma)625bc3cb74SMauro Carvalho Chehab static void videobuf_vm_open(struct vm_area_struct *vma)
635bc3cb74SMauro Carvalho Chehab {
645bc3cb74SMauro Carvalho Chehab struct videobuf_mapping *map = vma->vm_private_data;
655bc3cb74SMauro Carvalho Chehab
66cca36e2eSHans Verkuil dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
675bc3cb74SMauro Carvalho Chehab map, map->count, vma->vm_start, vma->vm_end);
685bc3cb74SMauro Carvalho Chehab
695bc3cb74SMauro Carvalho Chehab map->count++;
705bc3cb74SMauro Carvalho Chehab }
715bc3cb74SMauro Carvalho Chehab
videobuf_vm_close(struct vm_area_struct * vma)725bc3cb74SMauro Carvalho Chehab static void videobuf_vm_close(struct vm_area_struct *vma)
735bc3cb74SMauro Carvalho Chehab {
745bc3cb74SMauro Carvalho Chehab struct videobuf_mapping *map = vma->vm_private_data;
755bc3cb74SMauro Carvalho Chehab struct videobuf_queue *q = map->q;
765bc3cb74SMauro Carvalho Chehab int i;
775bc3cb74SMauro Carvalho Chehab
785bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
795bc3cb74SMauro Carvalho Chehab map, map->count, vma->vm_start, vma->vm_end);
805bc3cb74SMauro Carvalho Chehab
81cca36e2eSHans Verkuil map->count--;
82cca36e2eSHans Verkuil if (0 == map->count) {
835bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem;
845bc3cb74SMauro Carvalho Chehab
855bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
86cca36e2eSHans Verkuil videobuf_queue_lock(q);
875bc3cb74SMauro Carvalho Chehab
885bc3cb74SMauro Carvalho Chehab /* We need first to cancel streams, before unmapping */
895bc3cb74SMauro Carvalho Chehab if (q->streaming)
905bc3cb74SMauro Carvalho Chehab videobuf_queue_cancel(q);
915bc3cb74SMauro Carvalho Chehab
925bc3cb74SMauro Carvalho Chehab for (i = 0; i < VIDEO_MAX_FRAME; i++) {
935bc3cb74SMauro Carvalho Chehab if (NULL == q->bufs[i])
945bc3cb74SMauro Carvalho Chehab continue;
955bc3cb74SMauro Carvalho Chehab
965bc3cb74SMauro Carvalho Chehab if (q->bufs[i]->map != map)
975bc3cb74SMauro Carvalho Chehab continue;
985bc3cb74SMauro Carvalho Chehab
995bc3cb74SMauro Carvalho Chehab mem = q->bufs[i]->priv;
1005bc3cb74SMauro Carvalho Chehab if (mem) {
1015bc3cb74SMauro Carvalho Chehab /* This callback is called only if kernel has
1025bc3cb74SMauro Carvalho Chehab allocated memory and this memory is mmapped.
1035bc3cb74SMauro Carvalho Chehab In this case, memory should be freed,
1045bc3cb74SMauro Carvalho Chehab in order to do memory unmap.
1055bc3cb74SMauro Carvalho Chehab */
1065bc3cb74SMauro Carvalho Chehab
1075bc3cb74SMauro Carvalho Chehab MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
1085bc3cb74SMauro Carvalho Chehab
1095bc3cb74SMauro Carvalho Chehab /* vfree is not atomic - can't be
1105bc3cb74SMauro Carvalho Chehab called with IRQ's disabled
1115bc3cb74SMauro Carvalho Chehab */
1125bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "buf[%d] freeing %p\n",
1135bc3cb74SMauro Carvalho Chehab i, mem->vaddr);
1145bc3cb74SMauro Carvalho Chehab
1155bc3cb74SMauro Carvalho Chehab __videobuf_dc_free(q->dev, mem);
1165bc3cb74SMauro Carvalho Chehab mem->vaddr = NULL;
1175bc3cb74SMauro Carvalho Chehab }
1185bc3cb74SMauro Carvalho Chehab
1195bc3cb74SMauro Carvalho Chehab q->bufs[i]->map = NULL;
1205bc3cb74SMauro Carvalho Chehab q->bufs[i]->baddr = 0;
1215bc3cb74SMauro Carvalho Chehab }
1225bc3cb74SMauro Carvalho Chehab
1235bc3cb74SMauro Carvalho Chehab kfree(map);
1245bc3cb74SMauro Carvalho Chehab
125a242f426SAl Viro videobuf_queue_unlock(q);
1265bc3cb74SMauro Carvalho Chehab }
127cca36e2eSHans Verkuil }
1285bc3cb74SMauro Carvalho Chehab
1295bc3cb74SMauro Carvalho Chehab static const struct vm_operations_struct videobuf_vm_ops = {
1305bc3cb74SMauro Carvalho Chehab .open = videobuf_vm_open,
1315bc3cb74SMauro Carvalho Chehab .close = videobuf_vm_close,
1325bc3cb74SMauro Carvalho Chehab };
1335bc3cb74SMauro Carvalho Chehab
1345bc3cb74SMauro Carvalho Chehab /**
1355bc3cb74SMauro Carvalho Chehab * videobuf_dma_contig_user_put() - reset pointer to user space buffer
1365bc3cb74SMauro Carvalho Chehab * @mem: per-buffer private videobuf-dma-contig data
1375bc3cb74SMauro Carvalho Chehab *
1385bc3cb74SMauro Carvalho Chehab * This function resets the user space pointer
1395bc3cb74SMauro Carvalho Chehab */
videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory * mem)1405bc3cb74SMauro Carvalho Chehab static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
1415bc3cb74SMauro Carvalho Chehab {
1425bc3cb74SMauro Carvalho Chehab mem->dma_handle = 0;
1435bc3cb74SMauro Carvalho Chehab mem->size = 0;
1445bc3cb74SMauro Carvalho Chehab }
1455bc3cb74SMauro Carvalho Chehab
1465bc3cb74SMauro Carvalho Chehab /**
1475bc3cb74SMauro Carvalho Chehab * videobuf_dma_contig_user_get() - setup user space memory pointer
1485bc3cb74SMauro Carvalho Chehab * @mem: per-buffer private videobuf-dma-contig data
1495bc3cb74SMauro Carvalho Chehab * @vb: video buffer to map
1505bc3cb74SMauro Carvalho Chehab *
1515bc3cb74SMauro Carvalho Chehab * This function validates and sets up a pointer to user space memory.
1525bc3cb74SMauro Carvalho Chehab * Only physically contiguous pfn-mapped memory is accepted.
1535bc3cb74SMauro Carvalho Chehab *
1545bc3cb74SMauro Carvalho Chehab * Returns 0 if successful.
1555bc3cb74SMauro Carvalho Chehab */
videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory * mem,struct videobuf_buffer * vb)1565bc3cb74SMauro Carvalho Chehab static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
1575bc3cb74SMauro Carvalho Chehab struct videobuf_buffer *vb)
1585bc3cb74SMauro Carvalho Chehab {
159e275faf3SAndrey Konovalov unsigned long untagged_baddr = untagged_addr(vb->baddr);
1605bc3cb74SMauro Carvalho Chehab struct mm_struct *mm = current->mm;
1615bc3cb74SMauro Carvalho Chehab struct vm_area_struct *vma;
1625bc3cb74SMauro Carvalho Chehab unsigned long prev_pfn, this_pfn;
1635bc3cb74SMauro Carvalho Chehab unsigned long pages_done, user_address;
1645bc3cb74SMauro Carvalho Chehab unsigned int offset;
1655bc3cb74SMauro Carvalho Chehab int ret;
1665bc3cb74SMauro Carvalho Chehab
167e275faf3SAndrey Konovalov offset = untagged_baddr & ~PAGE_MASK;
1685bc3cb74SMauro Carvalho Chehab mem->size = PAGE_ALIGN(vb->size + offset);
1695bc3cb74SMauro Carvalho Chehab ret = -EINVAL;
1705bc3cb74SMauro Carvalho Chehab
171d8ed45c5SMichel Lespinasse mmap_read_lock(mm);
1725bc3cb74SMauro Carvalho Chehab
173e275faf3SAndrey Konovalov vma = find_vma(mm, untagged_baddr);
1745bc3cb74SMauro Carvalho Chehab if (!vma)
1755bc3cb74SMauro Carvalho Chehab goto out_up;
1765bc3cb74SMauro Carvalho Chehab
177e275faf3SAndrey Konovalov if ((untagged_baddr + mem->size) > vma->vm_end)
1785bc3cb74SMauro Carvalho Chehab goto out_up;
1795bc3cb74SMauro Carvalho Chehab
1805bc3cb74SMauro Carvalho Chehab pages_done = 0;
1815bc3cb74SMauro Carvalho Chehab prev_pfn = 0; /* kill warning */
182e275faf3SAndrey Konovalov user_address = untagged_baddr;
1835bc3cb74SMauro Carvalho Chehab
1845bc3cb74SMauro Carvalho Chehab while (pages_done < (mem->size >> PAGE_SHIFT)) {
1855bc3cb74SMauro Carvalho Chehab ret = follow_pfn(vma, user_address, &this_pfn);
1865bc3cb74SMauro Carvalho Chehab if (ret)
1875bc3cb74SMauro Carvalho Chehab break;
1885bc3cb74SMauro Carvalho Chehab
1895bc3cb74SMauro Carvalho Chehab if (pages_done == 0)
1905bc3cb74SMauro Carvalho Chehab mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
1915bc3cb74SMauro Carvalho Chehab else if (this_pfn != (prev_pfn + 1))
1925bc3cb74SMauro Carvalho Chehab ret = -EFAULT;
1935bc3cb74SMauro Carvalho Chehab
1945bc3cb74SMauro Carvalho Chehab if (ret)
1955bc3cb74SMauro Carvalho Chehab break;
1965bc3cb74SMauro Carvalho Chehab
1975bc3cb74SMauro Carvalho Chehab prev_pfn = this_pfn;
1985bc3cb74SMauro Carvalho Chehab user_address += PAGE_SIZE;
1995bc3cb74SMauro Carvalho Chehab pages_done++;
2005bc3cb74SMauro Carvalho Chehab }
2015bc3cb74SMauro Carvalho Chehab
2025bc3cb74SMauro Carvalho Chehab out_up:
203d8ed45c5SMichel Lespinasse mmap_read_unlock(current->mm);
2045bc3cb74SMauro Carvalho Chehab
2055bc3cb74SMauro Carvalho Chehab return ret;
2065bc3cb74SMauro Carvalho Chehab }
2075bc3cb74SMauro Carvalho Chehab
__videobuf_alloc(size_t size)208cb132cd5SMauro Carvalho Chehab static struct videobuf_buffer *__videobuf_alloc(size_t size)
2095bc3cb74SMauro Carvalho Chehab {
2105bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem;
2115bc3cb74SMauro Carvalho Chehab struct videobuf_buffer *vb;
2125bc3cb74SMauro Carvalho Chehab
2135bc3cb74SMauro Carvalho Chehab vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
2145bc3cb74SMauro Carvalho Chehab if (vb) {
2155bc3cb74SMauro Carvalho Chehab vb->priv = ((char *)vb) + size;
2165bc3cb74SMauro Carvalho Chehab mem = vb->priv;
2175bc3cb74SMauro Carvalho Chehab mem->magic = MAGIC_DC_MEM;
2185bc3cb74SMauro Carvalho Chehab }
2195bc3cb74SMauro Carvalho Chehab
2205bc3cb74SMauro Carvalho Chehab return vb;
2215bc3cb74SMauro Carvalho Chehab }
2225bc3cb74SMauro Carvalho Chehab
__videobuf_to_vaddr(struct videobuf_buffer * buf)2235bc3cb74SMauro Carvalho Chehab static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
2245bc3cb74SMauro Carvalho Chehab {
2255bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem = buf->priv;
2265bc3cb74SMauro Carvalho Chehab
2275bc3cb74SMauro Carvalho Chehab BUG_ON(!mem);
2285bc3cb74SMauro Carvalho Chehab MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
2295bc3cb74SMauro Carvalho Chehab
2305bc3cb74SMauro Carvalho Chehab return mem->vaddr;
2315bc3cb74SMauro Carvalho Chehab }
2325bc3cb74SMauro Carvalho Chehab
__videobuf_iolock(struct videobuf_queue * q,struct videobuf_buffer * vb,struct v4l2_framebuffer * fbuf)2335bc3cb74SMauro Carvalho Chehab static int __videobuf_iolock(struct videobuf_queue *q,
2345bc3cb74SMauro Carvalho Chehab struct videobuf_buffer *vb,
2355bc3cb74SMauro Carvalho Chehab struct v4l2_framebuffer *fbuf)
2365bc3cb74SMauro Carvalho Chehab {
2375bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem = vb->priv;
2385bc3cb74SMauro Carvalho Chehab
2395bc3cb74SMauro Carvalho Chehab BUG_ON(!mem);
2405bc3cb74SMauro Carvalho Chehab MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
2415bc3cb74SMauro Carvalho Chehab
2425bc3cb74SMauro Carvalho Chehab switch (vb->memory) {
2435bc3cb74SMauro Carvalho Chehab case V4L2_MEMORY_MMAP:
2445bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
2455bc3cb74SMauro Carvalho Chehab
2465bc3cb74SMauro Carvalho Chehab /* All handling should be done by __videobuf_mmap_mapper() */
2475bc3cb74SMauro Carvalho Chehab if (!mem->vaddr) {
2484faf7066SMauro Carvalho Chehab dev_err(q->dev, "memory is not allocated/mmapped.\n");
2495bc3cb74SMauro Carvalho Chehab return -EINVAL;
2505bc3cb74SMauro Carvalho Chehab }
2515bc3cb74SMauro Carvalho Chehab break;
2525bc3cb74SMauro Carvalho Chehab case V4L2_MEMORY_USERPTR:
2535bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
2545bc3cb74SMauro Carvalho Chehab
2555bc3cb74SMauro Carvalho Chehab /* handle pointer from user space */
2565bc3cb74SMauro Carvalho Chehab if (vb->baddr)
2575bc3cb74SMauro Carvalho Chehab return videobuf_dma_contig_user_get(mem, vb);
2585bc3cb74SMauro Carvalho Chehab
2595bc3cb74SMauro Carvalho Chehab /* allocate memory for the read() method */
260b3dc3f8eSChristoph Hellwig if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size)))
2615bc3cb74SMauro Carvalho Chehab return -ENOMEM;
2625bc3cb74SMauro Carvalho Chehab break;
2635bc3cb74SMauro Carvalho Chehab case V4L2_MEMORY_OVERLAY:
2645bc3cb74SMauro Carvalho Chehab default:
2655bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__);
2665bc3cb74SMauro Carvalho Chehab return -EINVAL;
2675bc3cb74SMauro Carvalho Chehab }
2685bc3cb74SMauro Carvalho Chehab
2695bc3cb74SMauro Carvalho Chehab return 0;
2705bc3cb74SMauro Carvalho Chehab }
2715bc3cb74SMauro Carvalho Chehab
__videobuf_mmap_mapper(struct videobuf_queue * q,struct videobuf_buffer * buf,struct vm_area_struct * vma)2725bc3cb74SMauro Carvalho Chehab static int __videobuf_mmap_mapper(struct videobuf_queue *q,
2735bc3cb74SMauro Carvalho Chehab struct videobuf_buffer *buf,
2745bc3cb74SMauro Carvalho Chehab struct vm_area_struct *vma)
2755bc3cb74SMauro Carvalho Chehab {
2765bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem;
2775bc3cb74SMauro Carvalho Chehab struct videobuf_mapping *map;
2785bc3cb74SMauro Carvalho Chehab int retval;
2795bc3cb74SMauro Carvalho Chehab
2805bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "%s\n", __func__);
2815bc3cb74SMauro Carvalho Chehab
2825bc3cb74SMauro Carvalho Chehab /* create mapping + update buffer list */
2835bc3cb74SMauro Carvalho Chehab map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
2845bc3cb74SMauro Carvalho Chehab if (!map)
2855bc3cb74SMauro Carvalho Chehab return -ENOMEM;
2865bc3cb74SMauro Carvalho Chehab
2875bc3cb74SMauro Carvalho Chehab buf->map = map;
2885bc3cb74SMauro Carvalho Chehab map->q = q;
2895bc3cb74SMauro Carvalho Chehab
2905bc3cb74SMauro Carvalho Chehab buf->baddr = vma->vm_start;
2915bc3cb74SMauro Carvalho Chehab
2925bc3cb74SMauro Carvalho Chehab mem = buf->priv;
2935bc3cb74SMauro Carvalho Chehab BUG_ON(!mem);
2945bc3cb74SMauro Carvalho Chehab MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
2955bc3cb74SMauro Carvalho Chehab
296b3dc3f8eSChristoph Hellwig if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize)))
2975bc3cb74SMauro Carvalho Chehab goto error;
2985bc3cb74SMauro Carvalho Chehab
2998a6a547fSFancy Fang /* the "vm_pgoff" is just used in v4l2 to find the
3008a6a547fSFancy Fang * corresponding buffer data structure which is allocated
3018a6a547fSFancy Fang * earlier and it does not mean the offset from the physical
3028a6a547fSFancy Fang * buffer start address as usual. So set it to 0 to pass
303b3dc3f8eSChristoph Hellwig * the sanity check in dma_mmap_coherent().
3048a6a547fSFancy Fang */
3058a6a547fSFancy Fang vma->vm_pgoff = 0;
306b3dc3f8eSChristoph Hellwig retval = dma_mmap_coherent(q->dev, vma, mem->vaddr, mem->dma_handle,
307b3dc3f8eSChristoph Hellwig mem->size);
3085bc3cb74SMauro Carvalho Chehab if (retval) {
3095bc3cb74SMauro Carvalho Chehab dev_err(q->dev, "mmap: remap failed with error %d. ",
3105bc3cb74SMauro Carvalho Chehab retval);
3115bc3cb74SMauro Carvalho Chehab dma_free_coherent(q->dev, mem->size,
3125bc3cb74SMauro Carvalho Chehab mem->vaddr, mem->dma_handle);
3135bc3cb74SMauro Carvalho Chehab goto error;
3145bc3cb74SMauro Carvalho Chehab }
3155bc3cb74SMauro Carvalho Chehab
3165bc3cb74SMauro Carvalho Chehab vma->vm_ops = &videobuf_vm_ops;
317*1c71222eSSuren Baghdasaryan vm_flags_set(vma, VM_DONTEXPAND);
3185bc3cb74SMauro Carvalho Chehab vma->vm_private_data = map;
3195bc3cb74SMauro Carvalho Chehab
3205bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
3215bc3cb74SMauro Carvalho Chehab map, q, vma->vm_start, vma->vm_end,
3225bc3cb74SMauro Carvalho Chehab (long int)buf->bsize, vma->vm_pgoff, buf->i);
3235bc3cb74SMauro Carvalho Chehab
3245bc3cb74SMauro Carvalho Chehab videobuf_vm_open(vma);
3255bc3cb74SMauro Carvalho Chehab
3265bc3cb74SMauro Carvalho Chehab return 0;
3275bc3cb74SMauro Carvalho Chehab
3285bc3cb74SMauro Carvalho Chehab error:
3295bc3cb74SMauro Carvalho Chehab kfree(map);
3305bc3cb74SMauro Carvalho Chehab return -ENOMEM;
3315bc3cb74SMauro Carvalho Chehab }
3325bc3cb74SMauro Carvalho Chehab
3335bc3cb74SMauro Carvalho Chehab static struct videobuf_qtype_ops qops = {
3345bc3cb74SMauro Carvalho Chehab .magic = MAGIC_QTYPE_OPS,
335cb132cd5SMauro Carvalho Chehab .alloc_vb = __videobuf_alloc,
3365bc3cb74SMauro Carvalho Chehab .iolock = __videobuf_iolock,
3375bc3cb74SMauro Carvalho Chehab .mmap_mapper = __videobuf_mmap_mapper,
3385bc3cb74SMauro Carvalho Chehab .vaddr = __videobuf_to_vaddr,
3395bc3cb74SMauro Carvalho Chehab };
3405bc3cb74SMauro Carvalho Chehab
videobuf_queue_dma_contig_init(struct videobuf_queue * q,const struct videobuf_queue_ops * ops,struct device * dev,spinlock_t * irqlock,enum v4l2_buf_type type,enum v4l2_field field,unsigned int msize,void * priv,struct mutex * ext_lock)3415bc3cb74SMauro Carvalho Chehab void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
3425bc3cb74SMauro Carvalho Chehab const struct videobuf_queue_ops *ops,
3435bc3cb74SMauro Carvalho Chehab struct device *dev,
3445bc3cb74SMauro Carvalho Chehab spinlock_t *irqlock,
3455bc3cb74SMauro Carvalho Chehab enum v4l2_buf_type type,
3465bc3cb74SMauro Carvalho Chehab enum v4l2_field field,
3475bc3cb74SMauro Carvalho Chehab unsigned int msize,
3485bc3cb74SMauro Carvalho Chehab void *priv,
3495bc3cb74SMauro Carvalho Chehab struct mutex *ext_lock)
3505bc3cb74SMauro Carvalho Chehab {
3515bc3cb74SMauro Carvalho Chehab videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
3525bc3cb74SMauro Carvalho Chehab priv, &qops, ext_lock);
3535bc3cb74SMauro Carvalho Chehab }
3545bc3cb74SMauro Carvalho Chehab EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
3555bc3cb74SMauro Carvalho Chehab
videobuf_to_dma_contig(struct videobuf_buffer * buf)3565bc3cb74SMauro Carvalho Chehab dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
3575bc3cb74SMauro Carvalho Chehab {
3585bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem = buf->priv;
3595bc3cb74SMauro Carvalho Chehab
3605bc3cb74SMauro Carvalho Chehab BUG_ON(!mem);
3615bc3cb74SMauro Carvalho Chehab MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
3625bc3cb74SMauro Carvalho Chehab
3635bc3cb74SMauro Carvalho Chehab return mem->dma_handle;
3645bc3cb74SMauro Carvalho Chehab }
3655bc3cb74SMauro Carvalho Chehab EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
3665bc3cb74SMauro Carvalho Chehab
videobuf_dma_contig_free(struct videobuf_queue * q,struct videobuf_buffer * buf)3675bc3cb74SMauro Carvalho Chehab void videobuf_dma_contig_free(struct videobuf_queue *q,
3685bc3cb74SMauro Carvalho Chehab struct videobuf_buffer *buf)
3695bc3cb74SMauro Carvalho Chehab {
3705bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem = buf->priv;
3715bc3cb74SMauro Carvalho Chehab
3725bc3cb74SMauro Carvalho Chehab /* mmapped memory can't be freed here, otherwise mmapped region
3735bc3cb74SMauro Carvalho Chehab would be released, while still needed. In this case, the memory
3745bc3cb74SMauro Carvalho Chehab release should happen inside videobuf_vm_close().
3755bc3cb74SMauro Carvalho Chehab So, it should free memory only if the memory were allocated for
3765bc3cb74SMauro Carvalho Chehab read() operation.
3775bc3cb74SMauro Carvalho Chehab */
3785bc3cb74SMauro Carvalho Chehab if (buf->memory != V4L2_MEMORY_USERPTR)
3795bc3cb74SMauro Carvalho Chehab return;
3805bc3cb74SMauro Carvalho Chehab
3815bc3cb74SMauro Carvalho Chehab if (!mem)
3825bc3cb74SMauro Carvalho Chehab return;
3835bc3cb74SMauro Carvalho Chehab
3845bc3cb74SMauro Carvalho Chehab MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
3855bc3cb74SMauro Carvalho Chehab
3865bc3cb74SMauro Carvalho Chehab /* handle user space pointer case */
3875bc3cb74SMauro Carvalho Chehab if (buf->baddr) {
3885bc3cb74SMauro Carvalho Chehab videobuf_dma_contig_user_put(mem);
3895bc3cb74SMauro Carvalho Chehab return;
3905bc3cb74SMauro Carvalho Chehab }
3915bc3cb74SMauro Carvalho Chehab
3925bc3cb74SMauro Carvalho Chehab /* read() method */
3935bc3cb74SMauro Carvalho Chehab if (mem->vaddr) {
3945bc3cb74SMauro Carvalho Chehab __videobuf_dc_free(q->dev, mem);
3955bc3cb74SMauro Carvalho Chehab mem->vaddr = NULL;
3965bc3cb74SMauro Carvalho Chehab }
3975bc3cb74SMauro Carvalho Chehab }
3985bc3cb74SMauro Carvalho Chehab EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
3995bc3cb74SMauro Carvalho Chehab
4005bc3cb74SMauro Carvalho Chehab MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
4015bc3cb74SMauro Carvalho Chehab MODULE_AUTHOR("Magnus Damm");
4025bc3cb74SMauro Carvalho Chehab MODULE_LICENSE("GPL");
403