Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * helper functions for physically contiguous capture buffers
0004  *
0005  * The functions support hardware lacking scatter gather support
0006  * (i.e. the buffers must be linear in physical memory)
0007  *
0008  * Copyright (c) 2008 Magnus Damm
0009  *
0010  * Based on videobuf-vmalloc.c,
0011  * (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org>
0012  */
0013 
0014 #include <linux/init.h>
0015 #include <linux/module.h>
0016 #include <linux/mm.h>
0017 #include <linux/pagemap.h>
0018 #include <linux/dma-mapping.h>
0019 #include <linux/sched.h>
0020 #include <linux/slab.h>
0021 #include <media/videobuf-dma-contig.h>
0022 
0023 struct videobuf_dma_contig_memory {
0024     u32 magic;
0025     void *vaddr;
0026     dma_addr_t dma_handle;
0027     unsigned long size;
0028 };
0029 
0030 #define MAGIC_DC_MEM 0x0733ac61
0031 #define MAGIC_CHECK(is, should)                         \
0032     if (unlikely((is) != (should))) {                   \
0033         pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
0034         BUG();                              \
0035     }
0036 
0037 static int __videobuf_dc_alloc(struct device *dev,
0038                    struct videobuf_dma_contig_memory *mem,
0039                    unsigned long size, gfp_t flags)
0040 {
0041     mem->size = size;
0042     mem->vaddr = dma_alloc_coherent(dev, mem->size,
0043                     &mem->dma_handle, flags);
0044 
0045     if (!mem->vaddr) {
0046         dev_err(dev, "memory alloc size %ld failed\n", mem->size);
0047         return -ENOMEM;
0048     }
0049 
0050     dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size);
0051 
0052     return 0;
0053 }
0054 
0055 static void __videobuf_dc_free(struct device *dev,
0056                    struct videobuf_dma_contig_memory *mem)
0057 {
0058     dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
0059 
0060     mem->vaddr = NULL;
0061 }
0062 
0063 static void videobuf_vm_open(struct vm_area_struct *vma)
0064 {
0065     struct videobuf_mapping *map = vma->vm_private_data;
0066 
0067     dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
0068         map, map->count, vma->vm_start, vma->vm_end);
0069 
0070     map->count++;
0071 }
0072 
0073 static void videobuf_vm_close(struct vm_area_struct *vma)
0074 {
0075     struct videobuf_mapping *map = vma->vm_private_data;
0076     struct videobuf_queue *q = map->q;
0077     int i;
0078 
0079     dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
0080         map, map->count, vma->vm_start, vma->vm_end);
0081 
0082     map->count--;
0083     if (0 == map->count) {
0084         struct videobuf_dma_contig_memory *mem;
0085 
0086         dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
0087         videobuf_queue_lock(q);
0088 
0089         /* We need first to cancel streams, before unmapping */
0090         if (q->streaming)
0091             videobuf_queue_cancel(q);
0092 
0093         for (i = 0; i < VIDEO_MAX_FRAME; i++) {
0094             if (NULL == q->bufs[i])
0095                 continue;
0096 
0097             if (q->bufs[i]->map != map)
0098                 continue;
0099 
0100             mem = q->bufs[i]->priv;
0101             if (mem) {
0102                 /* This callback is called only if kernel has
0103                    allocated memory and this memory is mmapped.
0104                    In this case, memory should be freed,
0105                    in order to do memory unmap.
0106                  */
0107 
0108                 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
0109 
0110                 /* vfree is not atomic - can't be
0111                    called with IRQ's disabled
0112                  */
0113                 dev_dbg(q->dev, "buf[%d] freeing %p\n",
0114                     i, mem->vaddr);
0115 
0116                 __videobuf_dc_free(q->dev, mem);
0117                 mem->vaddr = NULL;
0118             }
0119 
0120             q->bufs[i]->map = NULL;
0121             q->bufs[i]->baddr = 0;
0122         }
0123 
0124         kfree(map);
0125 
0126         videobuf_queue_unlock(q);
0127     }
0128 }
0129 
0130 static const struct vm_operations_struct videobuf_vm_ops = {
0131     .open   = videobuf_vm_open,
0132     .close  = videobuf_vm_close,
0133 };
0134 
0135 /**
0136  * videobuf_dma_contig_user_put() - reset pointer to user space buffer
0137  * @mem: per-buffer private videobuf-dma-contig data
0138  *
0139  * This function resets the user space pointer
0140  */
0141 static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
0142 {
0143     mem->dma_handle = 0;
0144     mem->size = 0;
0145 }
0146 
0147 /**
0148  * videobuf_dma_contig_user_get() - setup user space memory pointer
0149  * @mem: per-buffer private videobuf-dma-contig data
0150  * @vb: video buffer to map
0151  *
0152  * This function validates and sets up a pointer to user space memory.
0153  * Only physically contiguous pfn-mapped memory is accepted.
0154  *
0155  * Returns 0 if successful.
0156  */
0157 static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
0158                     struct videobuf_buffer *vb)
0159 {
0160     unsigned long untagged_baddr = untagged_addr(vb->baddr);
0161     struct mm_struct *mm = current->mm;
0162     struct vm_area_struct *vma;
0163     unsigned long prev_pfn, this_pfn;
0164     unsigned long pages_done, user_address;
0165     unsigned int offset;
0166     int ret;
0167 
0168     offset = untagged_baddr & ~PAGE_MASK;
0169     mem->size = PAGE_ALIGN(vb->size + offset);
0170     ret = -EINVAL;
0171 
0172     mmap_read_lock(mm);
0173 
0174     vma = find_vma(mm, untagged_baddr);
0175     if (!vma)
0176         goto out_up;
0177 
0178     if ((untagged_baddr + mem->size) > vma->vm_end)
0179         goto out_up;
0180 
0181     pages_done = 0;
0182     prev_pfn = 0; /* kill warning */
0183     user_address = untagged_baddr;
0184 
0185     while (pages_done < (mem->size >> PAGE_SHIFT)) {
0186         ret = follow_pfn(vma, user_address, &this_pfn);
0187         if (ret)
0188             break;
0189 
0190         if (pages_done == 0)
0191             mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
0192         else if (this_pfn != (prev_pfn + 1))
0193             ret = -EFAULT;
0194 
0195         if (ret)
0196             break;
0197 
0198         prev_pfn = this_pfn;
0199         user_address += PAGE_SIZE;
0200         pages_done++;
0201     }
0202 
0203 out_up:
0204     mmap_read_unlock(current->mm);
0205 
0206     return ret;
0207 }
0208 
0209 static struct videobuf_buffer *__videobuf_alloc(size_t size)
0210 {
0211     struct videobuf_dma_contig_memory *mem;
0212     struct videobuf_buffer *vb;
0213 
0214     vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
0215     if (vb) {
0216         vb->priv = ((char *)vb) + size;
0217         mem = vb->priv;
0218         mem->magic = MAGIC_DC_MEM;
0219     }
0220 
0221     return vb;
0222 }
0223 
0224 static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
0225 {
0226     struct videobuf_dma_contig_memory *mem = buf->priv;
0227 
0228     BUG_ON(!mem);
0229     MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
0230 
0231     return mem->vaddr;
0232 }
0233 
0234 static int __videobuf_iolock(struct videobuf_queue *q,
0235                  struct videobuf_buffer *vb,
0236                  struct v4l2_framebuffer *fbuf)
0237 {
0238     struct videobuf_dma_contig_memory *mem = vb->priv;
0239 
0240     BUG_ON(!mem);
0241     MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
0242 
0243     switch (vb->memory) {
0244     case V4L2_MEMORY_MMAP:
0245         dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
0246 
0247         /* All handling should be done by __videobuf_mmap_mapper() */
0248         if (!mem->vaddr) {
0249             dev_err(q->dev, "memory is not allocated/mmapped.\n");
0250             return -EINVAL;
0251         }
0252         break;
0253     case V4L2_MEMORY_USERPTR:
0254         dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
0255 
0256         /* handle pointer from user space */
0257         if (vb->baddr)
0258             return videobuf_dma_contig_user_get(mem, vb);
0259 
0260         /* allocate memory for the read() method */
0261         if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size),
0262                     GFP_KERNEL))
0263             return -ENOMEM;
0264         break;
0265     case V4L2_MEMORY_OVERLAY:
0266     default:
0267         dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__);
0268         return -EINVAL;
0269     }
0270 
0271     return 0;
0272 }
0273 
0274 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
0275                   struct videobuf_buffer *buf,
0276                   struct vm_area_struct *vma)
0277 {
0278     struct videobuf_dma_contig_memory *mem;
0279     struct videobuf_mapping *map;
0280     int retval;
0281 
0282     dev_dbg(q->dev, "%s\n", __func__);
0283 
0284     /* create mapping + update buffer list */
0285     map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
0286     if (!map)
0287         return -ENOMEM;
0288 
0289     buf->map = map;
0290     map->q = q;
0291 
0292     buf->baddr = vma->vm_start;
0293 
0294     mem = buf->priv;
0295     BUG_ON(!mem);
0296     MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
0297 
0298     if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize),
0299                 GFP_KERNEL | __GFP_COMP))
0300         goto error;
0301 
0302     /* Try to remap memory */
0303     vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
0304 
0305     /* the "vm_pgoff" is just used in v4l2 to find the
0306      * corresponding buffer data structure which is allocated
0307      * earlier and it does not mean the offset from the physical
0308      * buffer start address as usual. So set it to 0 to pass
0309      * the sanity check in vm_iomap_memory().
0310      */
0311     vma->vm_pgoff = 0;
0312 
0313     retval = vm_iomap_memory(vma, mem->dma_handle, mem->size);
0314     if (retval) {
0315         dev_err(q->dev, "mmap: remap failed with error %d. ",
0316             retval);
0317         dma_free_coherent(q->dev, mem->size,
0318                   mem->vaddr, mem->dma_handle);
0319         goto error;
0320     }
0321 
0322     vma->vm_ops = &videobuf_vm_ops;
0323     vma->vm_flags |= VM_DONTEXPAND;
0324     vma->vm_private_data = map;
0325 
0326     dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
0327         map, q, vma->vm_start, vma->vm_end,
0328         (long int)buf->bsize, vma->vm_pgoff, buf->i);
0329 
0330     videobuf_vm_open(vma);
0331 
0332     return 0;
0333 
0334 error:
0335     kfree(map);
0336     return -ENOMEM;
0337 }
0338 
0339 static struct videobuf_qtype_ops qops = {
0340     .magic      = MAGIC_QTYPE_OPS,
0341     .alloc_vb   = __videobuf_alloc,
0342     .iolock     = __videobuf_iolock,
0343     .mmap_mapper    = __videobuf_mmap_mapper,
0344     .vaddr      = __videobuf_to_vaddr,
0345 };
0346 
0347 void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
0348                     const struct videobuf_queue_ops *ops,
0349                     struct device *dev,
0350                     spinlock_t *irqlock,
0351                     enum v4l2_buf_type type,
0352                     enum v4l2_field field,
0353                     unsigned int msize,
0354                     void *priv,
0355                     struct mutex *ext_lock)
0356 {
0357     videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
0358                  priv, &qops, ext_lock);
0359 }
0360 EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
0361 
0362 dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
0363 {
0364     struct videobuf_dma_contig_memory *mem = buf->priv;
0365 
0366     BUG_ON(!mem);
0367     MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
0368 
0369     return mem->dma_handle;
0370 }
0371 EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
0372 
0373 void videobuf_dma_contig_free(struct videobuf_queue *q,
0374                   struct videobuf_buffer *buf)
0375 {
0376     struct videobuf_dma_contig_memory *mem = buf->priv;
0377 
0378     /* mmapped memory can't be freed here, otherwise mmapped region
0379        would be released, while still needed. In this case, the memory
0380        release should happen inside videobuf_vm_close().
0381        So, it should free memory only if the memory were allocated for
0382        read() operation.
0383      */
0384     if (buf->memory != V4L2_MEMORY_USERPTR)
0385         return;
0386 
0387     if (!mem)
0388         return;
0389 
0390     MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
0391 
0392     /* handle user space pointer case */
0393     if (buf->baddr) {
0394         videobuf_dma_contig_user_put(mem);
0395         return;
0396     }
0397 
0398     /* read() method */
0399     if (mem->vaddr) {
0400         __videobuf_dc_free(q->dev, mem);
0401         mem->vaddr = NULL;
0402     }
0403 }
0404 EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
0405 
0406 MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
0407 MODULE_AUTHOR("Magnus Damm");
0408 MODULE_LICENSE("GPL");