linux/drivers/media/v4l2-core/videobuf-vmalloc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * helper functions for vmalloc video4linux capture buffers
   4 *
   5 * The functions expect the hardware being able to scatter gather
   6 * (i.e. the buffers are not linear in physical memory, but fragmented
   7 * into PAGE_SIZE chunks).  They also assume the driver does not need
   8 * to touch the video data.
   9 *
  10 * (c) 2007 Mauro Carvalho Chehab <mchehab@kernel.org>
  11 */
  12
  13#include <linux/init.h>
  14#include <linux/module.h>
  15#include <linux/moduleparam.h>
  16#include <linux/slab.h>
  17#include <linux/interrupt.h>
  18#include <linux/pgtable.h>
  19
  20#include <linux/pci.h>
  21#include <linux/vmalloc.h>
  22#include <linux/pagemap.h>
  23#include <asm/page.h>
  24
  25#include <media/videobuf-vmalloc.h>
  26
  27#define MAGIC_DMABUF   0x17760309
  28#define MAGIC_VMAL_MEM 0x18221223
  29
  30#define MAGIC_CHECK(is, should)                                         \
  31        if (unlikely((is) != (should))) {                               \
  32                printk(KERN_ERR "magic mismatch: %x (expected %x)\n",   \
  33                                is, should);                            \
  34                BUG();                                                  \
  35        }
  36
  37static int debug;
  38module_param(debug, int, 0644);
  39
  40MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
  41MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>");
  42MODULE_LICENSE("GPL");
  43
  44#define dprintk(level, fmt, arg...)                                     \
  45        if (debug >= level)                                             \
  46                printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
  47
  48
  49/***************************************************************************/
  50
  51static void videobuf_vm_open(struct vm_area_struct *vma)
  52{
  53        struct videobuf_mapping *map = vma->vm_private_data;
  54
  55        dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map,
  56                map->count, vma->vm_start, vma->vm_end);
  57
  58        map->count++;
  59}
  60
  61static void videobuf_vm_close(struct vm_area_struct *vma)
  62{
  63        struct videobuf_mapping *map = vma->vm_private_data;
  64        struct videobuf_queue *q = map->q;
  65        int i;
  66
  67        dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
  68                map->count, vma->vm_start, vma->vm_end);
  69
  70        map->count--;
  71        if (0 == map->count) {
  72                struct videobuf_vmalloc_memory *mem;
  73
  74                dprintk(1, "munmap %p q=%p\n", map, q);
  75                videobuf_queue_lock(q);
  76
  77                /* We need first to cancel streams, before unmapping */
  78                if (q->streaming)
  79                        videobuf_queue_cancel(q);
  80
  81                for (i = 0; i < VIDEO_MAX_FRAME; i++) {
  82                        if (NULL == q->bufs[i])
  83                                continue;
  84
  85                        if (q->bufs[i]->map != map)
  86                                continue;
  87
  88                        mem = q->bufs[i]->priv;
  89                        if (mem) {
  90                                /* This callback is called only if kernel has
  91                                   allocated memory and this memory is mmapped.
  92                                   In this case, memory should be freed,
  93                                   in order to do memory unmap.
  94                                 */
  95
  96                                MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
  97
  98                                /* vfree is not atomic - can't be
  99                                   called with IRQ's disabled
 100                                 */
 101                                dprintk(1, "%s: buf[%d] freeing (%p)\n",
 102                                        __func__, i, mem->vaddr);
 103
 104                                vfree(mem->vaddr);
 105                                mem->vaddr = NULL;
 106                        }
 107
 108                        q->bufs[i]->map   = NULL;
 109                        q->bufs[i]->baddr = 0;
 110                }
 111
 112                kfree(map);
 113
 114                videobuf_queue_unlock(q);
 115        }
 116
 117        return;
 118}
 119
 120static const struct vm_operations_struct videobuf_vm_ops = {
 121        .open     = videobuf_vm_open,
 122        .close    = videobuf_vm_close,
 123};
 124
 125/* ---------------------------------------------------------------------
 126 * vmalloc handlers for the generic methods
 127 */
 128
 129/* Allocated area consists on 3 parts:
 130        struct video_buffer
 131        struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
 132        struct videobuf_dma_sg_memory
 133 */
 134
 135static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
 136{
 137        struct videobuf_vmalloc_memory *mem;
 138        struct videobuf_buffer *vb;
 139
 140        vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
 141        if (!vb)
 142                return vb;
 143
 144        mem = vb->priv = ((char *)vb) + size;
 145        mem->magic = MAGIC_VMAL_MEM;
 146
 147        dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
 148                __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb),
 149                mem, (long)sizeof(*mem));
 150
 151        return vb;
 152}
 153
 154static int __videobuf_iolock(struct videobuf_queue *q,
 155                             struct videobuf_buffer *vb,
 156                             struct v4l2_framebuffer *fbuf)
 157{
 158        struct videobuf_vmalloc_memory *mem = vb->priv;
 159        int pages;
 160
 161        BUG_ON(!mem);
 162
 163        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 164
 165        switch (vb->memory) {
 166        case V4L2_MEMORY_MMAP:
 167                dprintk(1, "%s memory method MMAP\n", __func__);
 168
 169                /* All handling should be done by __videobuf_mmap_mapper() */
 170                if (!mem->vaddr) {
 171                        printk(KERN_ERR "memory is not allocated/mmapped.\n");
 172                        return -EINVAL;
 173                }
 174                break;
 175        case V4L2_MEMORY_USERPTR:
 176                pages = PAGE_ALIGN(vb->size);
 177
 178                dprintk(1, "%s memory method USERPTR\n", __func__);
 179
 180                if (vb->baddr) {
 181                        printk(KERN_ERR "USERPTR is currently not supported\n");
 182                        return -EINVAL;
 183                }
 184
 185                /* The only USERPTR currently supported is the one needed for
 186                 * read() method.
 187                 */
 188
 189                mem->vaddr = vmalloc_user(pages);
 190                if (!mem->vaddr) {
 191                        printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
 192                        return -ENOMEM;
 193                }
 194                dprintk(1, "vmalloc is at addr %p (%d pages)\n",
 195                        mem->vaddr, pages);
 196                break;
 197        case V4L2_MEMORY_OVERLAY:
 198        default:
 199                dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
 200
 201                /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
 202                printk(KERN_ERR "Memory method currently unsupported.\n");
 203                return -EINVAL;
 204        }
 205
 206        return 0;
 207}
 208
 209static int __videobuf_mmap_mapper(struct videobuf_queue *q,
 210                                  struct videobuf_buffer *buf,
 211                                  struct vm_area_struct *vma)
 212{
 213        struct videobuf_vmalloc_memory *mem;
 214        struct videobuf_mapping *map;
 215        int retval, pages;
 216
 217        dprintk(1, "%s\n", __func__);
 218
 219        /* create mapping + update buffer list */
 220        map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
 221        if (NULL == map)
 222                return -ENOMEM;
 223
 224        buf->map = map;
 225        map->q     = q;
 226
 227        buf->baddr = vma->vm_start;
 228
 229        mem = buf->priv;
 230        BUG_ON(!mem);
 231        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 232
 233        pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
 234        mem->vaddr = vmalloc_user(pages);
 235        if (!mem->vaddr) {
 236                printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
 237                goto error;
 238        }
 239        dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages);
 240
 241        /* Try to remap memory */
 242        retval = remap_vmalloc_range(vma, mem->vaddr, 0);
 243        if (retval < 0) {
 244                printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
 245                vfree(mem->vaddr);
 246                goto error;
 247        }
 248
 249        vma->vm_ops          = &videobuf_vm_ops;
 250        vma->vm_flags       |= VM_DONTEXPAND | VM_DONTDUMP;
 251        vma->vm_private_data = map;
 252
 253        dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
 254                map, q, vma->vm_start, vma->vm_end,
 255                (long int)buf->bsize,
 256                vma->vm_pgoff, buf->i);
 257
 258        videobuf_vm_open(vma);
 259
 260        return 0;
 261
 262error:
 263        mem = NULL;
 264        kfree(map);
 265        return -ENOMEM;
 266}
 267
 268static struct videobuf_qtype_ops qops = {
 269        .magic        = MAGIC_QTYPE_OPS,
 270
 271        .alloc_vb     = __videobuf_alloc_vb,
 272        .iolock       = __videobuf_iolock,
 273        .mmap_mapper  = __videobuf_mmap_mapper,
 274        .vaddr        = videobuf_to_vmalloc,
 275};
 276
 277void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
 278                         const struct videobuf_queue_ops *ops,
 279                         struct device *dev,
 280                         spinlock_t *irqlock,
 281                         enum v4l2_buf_type type,
 282                         enum v4l2_field field,
 283                         unsigned int msize,
 284                         void *priv,
 285                         struct mutex *ext_lock)
 286{
 287        videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
 288                                 priv, &qops, ext_lock);
 289}
 290EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
 291
 292void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
 293{
 294        struct videobuf_vmalloc_memory *mem = buf->priv;
 295        BUG_ON(!mem);
 296        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 297
 298        return mem->vaddr;
 299}
 300EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
 301
 302void videobuf_vmalloc_free(struct videobuf_buffer *buf)
 303{
 304        struct videobuf_vmalloc_memory *mem = buf->priv;
 305
 306        /* mmapped memory can't be freed here, otherwise mmapped region
 307           would be released, while still needed. In this case, the memory
 308           release should happen inside videobuf_vm_close().
 309           So, it should free memory only if the memory were allocated for
 310           read() operation.
 311         */
 312        if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
 313                return;
 314
 315        if (!mem)
 316                return;
 317
 318        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 319
 320        vfree(mem->vaddr);
 321        mem->vaddr = NULL;
 322
 323        return;
 324}
 325EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
 326
 327