Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * helper functions for vmalloc video4linux capture buffers
0004  *
0005  * The functions expect the hardware being able to scatter gather
0006  * (i.e. the buffers are not linear in physical memory, but fragmented
0007  * into PAGE_SIZE chunks).  They also assume the driver does not need
0008  * to touch the video data.
0009  *
0010  * (c) 2007 Mauro Carvalho Chehab <mchehab@kernel.org>
0011  */
0012 
0013 #include <linux/init.h>
0014 #include <linux/module.h>
0015 #include <linux/moduleparam.h>
0016 #include <linux/slab.h>
0017 #include <linux/interrupt.h>
0018 #include <linux/pgtable.h>
0019 
0020 #include <linux/pci.h>
0021 #include <linux/vmalloc.h>
0022 #include <linux/pagemap.h>
0023 #include <asm/page.h>
0024 
0025 #include <media/videobuf-vmalloc.h>
0026 
0027 #define MAGIC_DMABUF   0x17760309
0028 #define MAGIC_VMAL_MEM 0x18221223
0029 
0030 #define MAGIC_CHECK(is, should)                     \
0031     if (unlikely((is) != (should))) {               \
0032         printk(KERN_ERR "magic mismatch: %x (expected %x)\n",   \
0033                 is, should);                \
0034         BUG();                          \
0035     }
0036 
0037 static int debug;
0038 module_param(debug, int, 0644);
0039 
0040 MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
0041 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>");
0042 MODULE_LICENSE("GPL");
0043 
0044 #define dprintk(level, fmt, arg...)                 \
0045     if (debug >= level)                     \
0046         printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
0047 
0048 
0049 /***************************************************************************/
0050 
0051 static void videobuf_vm_open(struct vm_area_struct *vma)
0052 {
0053     struct videobuf_mapping *map = vma->vm_private_data;
0054 
0055     dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map,
0056         map->count, vma->vm_start, vma->vm_end);
0057 
0058     map->count++;
0059 }
0060 
0061 static void videobuf_vm_close(struct vm_area_struct *vma)
0062 {
0063     struct videobuf_mapping *map = vma->vm_private_data;
0064     struct videobuf_queue *q = map->q;
0065     int i;
0066 
0067     dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
0068         map->count, vma->vm_start, vma->vm_end);
0069 
0070     map->count--;
0071     if (0 == map->count) {
0072         struct videobuf_vmalloc_memory *mem;
0073 
0074         dprintk(1, "munmap %p q=%p\n", map, q);
0075         videobuf_queue_lock(q);
0076 
0077         /* We need first to cancel streams, before unmapping */
0078         if (q->streaming)
0079             videobuf_queue_cancel(q);
0080 
0081         for (i = 0; i < VIDEO_MAX_FRAME; i++) {
0082             if (NULL == q->bufs[i])
0083                 continue;
0084 
0085             if (q->bufs[i]->map != map)
0086                 continue;
0087 
0088             mem = q->bufs[i]->priv;
0089             if (mem) {
0090                 /* This callback is called only if kernel has
0091                    allocated memory and this memory is mmapped.
0092                    In this case, memory should be freed,
0093                    in order to do memory unmap.
0094                  */
0095 
0096                 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
0097 
0098                 /* vfree is not atomic - can't be
0099                    called with IRQ's disabled
0100                  */
0101                 dprintk(1, "%s: buf[%d] freeing (%p)\n",
0102                     __func__, i, mem->vaddr);
0103 
0104                 vfree(mem->vaddr);
0105                 mem->vaddr = NULL;
0106             }
0107 
0108             q->bufs[i]->map   = NULL;
0109             q->bufs[i]->baddr = 0;
0110         }
0111 
0112         kfree(map);
0113 
0114         videobuf_queue_unlock(q);
0115     }
0116 
0117     return;
0118 }
0119 
0120 static const struct vm_operations_struct videobuf_vm_ops = {
0121     .open     = videobuf_vm_open,
0122     .close    = videobuf_vm_close,
0123 };
0124 
0125 /* ---------------------------------------------------------------------
0126  * vmalloc handlers for the generic methods
0127  */
0128 
0129 /* Allocated area consists on 3 parts:
0130     struct video_buffer
0131     struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
0132     struct videobuf_dma_sg_memory
0133  */
0134 
0135 static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
0136 {
0137     struct videobuf_vmalloc_memory *mem;
0138     struct videobuf_buffer *vb;
0139 
0140     vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
0141     if (!vb)
0142         return vb;
0143 
0144     mem = vb->priv = ((char *)vb) + size;
0145     mem->magic = MAGIC_VMAL_MEM;
0146 
0147     dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
0148         __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb),
0149         mem, (long)sizeof(*mem));
0150 
0151     return vb;
0152 }
0153 
0154 static int __videobuf_iolock(struct videobuf_queue *q,
0155                  struct videobuf_buffer *vb,
0156                  struct v4l2_framebuffer *fbuf)
0157 {
0158     struct videobuf_vmalloc_memory *mem = vb->priv;
0159     int pages;
0160 
0161     BUG_ON(!mem);
0162 
0163     MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
0164 
0165     switch (vb->memory) {
0166     case V4L2_MEMORY_MMAP:
0167         dprintk(1, "%s memory method MMAP\n", __func__);
0168 
0169         /* All handling should be done by __videobuf_mmap_mapper() */
0170         if (!mem->vaddr) {
0171             printk(KERN_ERR "memory is not allocated/mmapped.\n");
0172             return -EINVAL;
0173         }
0174         break;
0175     case V4L2_MEMORY_USERPTR:
0176         pages = PAGE_ALIGN(vb->size);
0177 
0178         dprintk(1, "%s memory method USERPTR\n", __func__);
0179 
0180         if (vb->baddr) {
0181             printk(KERN_ERR "USERPTR is currently not supported\n");
0182             return -EINVAL;
0183         }
0184 
0185         /* The only USERPTR currently supported is the one needed for
0186          * read() method.
0187          */
0188 
0189         mem->vaddr = vmalloc_user(pages);
0190         if (!mem->vaddr) {
0191             printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
0192             return -ENOMEM;
0193         }
0194         dprintk(1, "vmalloc is at addr %p (%d pages)\n",
0195             mem->vaddr, pages);
0196         break;
0197     case V4L2_MEMORY_OVERLAY:
0198     default:
0199         dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
0200 
0201         /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
0202         printk(KERN_ERR "Memory method currently unsupported.\n");
0203         return -EINVAL;
0204     }
0205 
0206     return 0;
0207 }
0208 
0209 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
0210                   struct videobuf_buffer *buf,
0211                   struct vm_area_struct *vma)
0212 {
0213     struct videobuf_vmalloc_memory *mem;
0214     struct videobuf_mapping *map;
0215     int retval, pages;
0216 
0217     dprintk(1, "%s\n", __func__);
0218 
0219     /* create mapping + update buffer list */
0220     map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
0221     if (NULL == map)
0222         return -ENOMEM;
0223 
0224     buf->map = map;
0225     map->q     = q;
0226 
0227     buf->baddr = vma->vm_start;
0228 
0229     mem = buf->priv;
0230     BUG_ON(!mem);
0231     MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
0232 
0233     pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
0234     mem->vaddr = vmalloc_user(pages);
0235     if (!mem->vaddr) {
0236         printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
0237         goto error;
0238     }
0239     dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages);
0240 
0241     /* Try to remap memory */
0242     retval = remap_vmalloc_range(vma, mem->vaddr, 0);
0243     if (retval < 0) {
0244         printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
0245         vfree(mem->vaddr);
0246         goto error;
0247     }
0248 
0249     vma->vm_ops          = &videobuf_vm_ops;
0250     vma->vm_flags       |= VM_DONTEXPAND | VM_DONTDUMP;
0251     vma->vm_private_data = map;
0252 
0253     dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
0254         map, q, vma->vm_start, vma->vm_end,
0255         (long int)buf->bsize,
0256         vma->vm_pgoff, buf->i);
0257 
0258     videobuf_vm_open(vma);
0259 
0260     return 0;
0261 
0262 error:
0263     mem = NULL;
0264     kfree(map);
0265     return -ENOMEM;
0266 }
0267 
0268 static struct videobuf_qtype_ops qops = {
0269     .magic        = MAGIC_QTYPE_OPS,
0270 
0271     .alloc_vb     = __videobuf_alloc_vb,
0272     .iolock       = __videobuf_iolock,
0273     .mmap_mapper  = __videobuf_mmap_mapper,
0274     .vaddr        = videobuf_to_vmalloc,
0275 };
0276 
0277 void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
0278              const struct videobuf_queue_ops *ops,
0279              struct device *dev,
0280              spinlock_t *irqlock,
0281              enum v4l2_buf_type type,
0282              enum v4l2_field field,
0283              unsigned int msize,
0284              void *priv,
0285              struct mutex *ext_lock)
0286 {
0287     videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
0288                  priv, &qops, ext_lock);
0289 }
0290 EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
0291 
0292 void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
0293 {
0294     struct videobuf_vmalloc_memory *mem = buf->priv;
0295     BUG_ON(!mem);
0296     MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
0297 
0298     return mem->vaddr;
0299 }
0300 EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
0301 
0302 void videobuf_vmalloc_free(struct videobuf_buffer *buf)
0303 {
0304     struct videobuf_vmalloc_memory *mem = buf->priv;
0305 
0306     /* mmapped memory can't be freed here, otherwise mmapped region
0307        would be released, while still needed. In this case, the memory
0308        release should happen inside videobuf_vm_close().
0309        So, it should free memory only if the memory were allocated for
0310        read() operation.
0311      */
0312     if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
0313         return;
0314 
0315     if (!mem)
0316         return;
0317 
0318     MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
0319 
0320     vfree(mem->vaddr);
0321     mem->vaddr = NULL;
0322 
0323     return;
0324 }
0325 EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
0326