linux/drivers/media/v4l2-core/videobuf-dma-contig.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * helper functions for physically contiguous capture buffers
   4 *
   5 * The functions support hardware lacking scatter gather support
   6 * (i.e. the buffers must be linear in physical memory)
   7 *
   8 * Copyright (c) 2008 Magnus Damm
   9 *
  10 * Based on videobuf-vmalloc.c,
  11 * (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org>
  12 */
  13
  14#include <linux/init.h>
  15#include <linux/module.h>
  16#include <linux/mm.h>
  17#include <linux/pagemap.h>
  18#include <linux/dma-mapping.h>
  19#include <linux/sched.h>
  20#include <linux/slab.h>
  21#include <media/videobuf-dma-contig.h>
  22
  23struct videobuf_dma_contig_memory {
  24        u32 magic;
  25        void *vaddr;
  26        dma_addr_t dma_handle;
  27        unsigned long size;
  28};
  29
  30#define MAGIC_DC_MEM 0x0733ac61
  31#define MAGIC_CHECK(is, should)                                             \
  32        if (unlikely((is) != (should))) {                                   \
  33                pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
  34                BUG();                                                      \
  35        }
  36
  37static int __videobuf_dc_alloc(struct device *dev,
  38                               struct videobuf_dma_contig_memory *mem,
  39                               unsigned long size, gfp_t flags)
  40{
  41        mem->size = size;
  42        mem->vaddr = dma_alloc_coherent(dev, mem->size,
  43                                        &mem->dma_handle, flags);
  44
  45        if (!mem->vaddr) {
  46                dev_err(dev, "memory alloc size %ld failed\n", mem->size);
  47                return -ENOMEM;
  48        }
  49
  50        dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size);
  51
  52        return 0;
  53}
  54
  55static void __videobuf_dc_free(struct device *dev,
  56                               struct videobuf_dma_contig_memory *mem)
  57{
  58        dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
  59
  60        mem->vaddr = NULL;
  61}
  62
  63static void videobuf_vm_open(struct vm_area_struct *vma)
  64{
  65        struct videobuf_mapping *map = vma->vm_private_data;
  66
  67        dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
  68                map, map->count, vma->vm_start, vma->vm_end);
  69
  70        map->count++;
  71}
  72
  73static void videobuf_vm_close(struct vm_area_struct *vma)
  74{
  75        struct videobuf_mapping *map = vma->vm_private_data;
  76        struct videobuf_queue *q = map->q;
  77        int i;
  78
  79        dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
  80                map, map->count, vma->vm_start, vma->vm_end);
  81
  82        map->count--;
  83        if (0 == map->count) {
  84                struct videobuf_dma_contig_memory *mem;
  85
  86                dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
  87                videobuf_queue_lock(q);
  88
  89                /* We need first to cancel streams, before unmapping */
  90                if (q->streaming)
  91                        videobuf_queue_cancel(q);
  92
  93                for (i = 0; i < VIDEO_MAX_FRAME; i++) {
  94                        if (NULL == q->bufs[i])
  95                                continue;
  96
  97                        if (q->bufs[i]->map != map)
  98                                continue;
  99
 100                        mem = q->bufs[i]->priv;
 101                        if (mem) {
 102                                /* This callback is called only if kernel has
 103                                   allocated memory and this memory is mmapped.
 104                                   In this case, memory should be freed,
 105                                   in order to do memory unmap.
 106                                 */
 107
 108                                MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
 109
 110                                /* vfree is not atomic - can't be
 111                                   called with IRQ's disabled
 112                                 */
 113                                dev_dbg(q->dev, "buf[%d] freeing %p\n",
 114                                        i, mem->vaddr);
 115
 116                                __videobuf_dc_free(q->dev, mem);
 117                                mem->vaddr = NULL;
 118                        }
 119
 120                        q->bufs[i]->map = NULL;
 121                        q->bufs[i]->baddr = 0;
 122                }
 123
 124                kfree(map);
 125
 126                videobuf_queue_unlock(q);
 127        }
 128}
 129
 130static const struct vm_operations_struct videobuf_vm_ops = {
 131        .open   = videobuf_vm_open,
 132        .close  = videobuf_vm_close,
 133};
 134
 135/**
 136 * videobuf_dma_contig_user_put() - reset pointer to user space buffer
 137 * @mem: per-buffer private videobuf-dma-contig data
 138 *
 139 * This function resets the user space pointer
 140 */
 141static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
 142{
 143        mem->dma_handle = 0;
 144        mem->size = 0;
 145}
 146
 147/**
 148 * videobuf_dma_contig_user_get() - setup user space memory pointer
 149 * @mem: per-buffer private videobuf-dma-contig data
 150 * @vb: video buffer to map
 151 *
 152 * This function validates and sets up a pointer to user space memory.
 153 * Only physically contiguous pfn-mapped memory is accepted.
 154 *
 155 * Returns 0 if successful.
 156 */
 157static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
 158                                        struct videobuf_buffer *vb)
 159{
 160        unsigned long untagged_baddr = untagged_addr(vb->baddr);
 161        struct mm_struct *mm = current->mm;
 162        struct vm_area_struct *vma;
 163        unsigned long prev_pfn, this_pfn;
 164        unsigned long pages_done, user_address;
 165        unsigned int offset;
 166        int ret;
 167
 168        offset = untagged_baddr & ~PAGE_MASK;
 169        mem->size = PAGE_ALIGN(vb->size + offset);
 170        ret = -EINVAL;
 171
 172        mmap_read_lock(mm);
 173
 174        vma = find_vma(mm, untagged_baddr);
 175        if (!vma)
 176                goto out_up;
 177
 178        if ((untagged_baddr + mem->size) > vma->vm_end)
 179                goto out_up;
 180
 181        pages_done = 0;
 182        prev_pfn = 0; /* kill warning */
 183        user_address = untagged_baddr;
 184
 185        while (pages_done < (mem->size >> PAGE_SHIFT)) {
 186                ret = follow_pfn(vma, user_address, &this_pfn);
 187                if (ret)
 188                        break;
 189
 190                if (pages_done == 0)
 191                        mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
 192                else if (this_pfn != (prev_pfn + 1))
 193                        ret = -EFAULT;
 194
 195                if (ret)
 196                        break;
 197
 198                prev_pfn = this_pfn;
 199                user_address += PAGE_SIZE;
 200                pages_done++;
 201        }
 202
 203out_up:
 204        mmap_read_unlock(current->mm);
 205
 206        return ret;
 207}
 208
 209static struct videobuf_buffer *__videobuf_alloc(size_t size)
 210{
 211        struct videobuf_dma_contig_memory *mem;
 212        struct videobuf_buffer *vb;
 213
 214        vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
 215        if (vb) {
 216                vb->priv = ((char *)vb) + size;
 217                mem = vb->priv;
 218                mem->magic = MAGIC_DC_MEM;
 219        }
 220
 221        return vb;
 222}
 223
 224static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
 225{
 226        struct videobuf_dma_contig_memory *mem = buf->priv;
 227
 228        BUG_ON(!mem);
 229        MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
 230
 231        return mem->vaddr;
 232}
 233
 234static int __videobuf_iolock(struct videobuf_queue *q,
 235                             struct videobuf_buffer *vb,
 236                             struct v4l2_framebuffer *fbuf)
 237{
 238        struct videobuf_dma_contig_memory *mem = vb->priv;
 239
 240        BUG_ON(!mem);
 241        MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
 242
 243        switch (vb->memory) {
 244        case V4L2_MEMORY_MMAP:
 245                dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
 246
 247                /* All handling should be done by __videobuf_mmap_mapper() */
 248                if (!mem->vaddr) {
 249                        dev_err(q->dev, "memory is not allocated/mmapped.\n");
 250                        return -EINVAL;
 251                }
 252                break;
 253        case V4L2_MEMORY_USERPTR:
 254                dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
 255
 256                /* handle pointer from user space */
 257                if (vb->baddr)
 258                        return videobuf_dma_contig_user_get(mem, vb);
 259
 260                /* allocate memory for the read() method */
 261                if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size),
 262                                        GFP_KERNEL))
 263                        return -ENOMEM;
 264                break;
 265        case V4L2_MEMORY_OVERLAY:
 266        default:
 267                dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__);
 268                return -EINVAL;
 269        }
 270
 271        return 0;
 272}
 273
 274static int __videobuf_mmap_mapper(struct videobuf_queue *q,
 275                                  struct videobuf_buffer *buf,
 276                                  struct vm_area_struct *vma)
 277{
 278        struct videobuf_dma_contig_memory *mem;
 279        struct videobuf_mapping *map;
 280        int retval;
 281
 282        dev_dbg(q->dev, "%s\n", __func__);
 283
 284        /* create mapping + update buffer list */
 285        map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
 286        if (!map)
 287                return -ENOMEM;
 288
 289        buf->map = map;
 290        map->q = q;
 291
 292        buf->baddr = vma->vm_start;
 293
 294        mem = buf->priv;
 295        BUG_ON(!mem);
 296        MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
 297
 298        if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize),
 299                                GFP_KERNEL | __GFP_COMP))
 300                goto error;
 301
 302        /* Try to remap memory */
 303        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 304
 305        /* the "vm_pgoff" is just used in v4l2 to find the
 306         * corresponding buffer data structure which is allocated
 307         * earlier and it does not mean the offset from the physical
 308         * buffer start address as usual. So set it to 0 to pass
 309         * the sanity check in vm_iomap_memory().
 310         */
 311        vma->vm_pgoff = 0;
 312
 313        retval = vm_iomap_memory(vma, mem->dma_handle, mem->size);
 314        if (retval) {
 315                dev_err(q->dev, "mmap: remap failed with error %d. ",
 316                        retval);
 317                dma_free_coherent(q->dev, mem->size,
 318                                  mem->vaddr, mem->dma_handle);
 319                goto error;
 320        }
 321
 322        vma->vm_ops = &videobuf_vm_ops;
 323        vma->vm_flags |= VM_DONTEXPAND;
 324        vma->vm_private_data = map;
 325
 326        dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
 327                map, q, vma->vm_start, vma->vm_end,
 328                (long int)buf->bsize, vma->vm_pgoff, buf->i);
 329
 330        videobuf_vm_open(vma);
 331
 332        return 0;
 333
 334error:
 335        kfree(map);
 336        return -ENOMEM;
 337}
 338
 339static struct videobuf_qtype_ops qops = {
 340        .magic          = MAGIC_QTYPE_OPS,
 341        .alloc_vb       = __videobuf_alloc,
 342        .iolock         = __videobuf_iolock,
 343        .mmap_mapper    = __videobuf_mmap_mapper,
 344        .vaddr          = __videobuf_to_vaddr,
 345};
 346
 347void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
 348                                    const struct videobuf_queue_ops *ops,
 349                                    struct device *dev,
 350                                    spinlock_t *irqlock,
 351                                    enum v4l2_buf_type type,
 352                                    enum v4l2_field field,
 353                                    unsigned int msize,
 354                                    void *priv,
 355                                    struct mutex *ext_lock)
 356{
 357        videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
 358                                 priv, &qops, ext_lock);
 359}
 360EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
 361
 362dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
 363{
 364        struct videobuf_dma_contig_memory *mem = buf->priv;
 365
 366        BUG_ON(!mem);
 367        MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
 368
 369        return mem->dma_handle;
 370}
 371EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
 372
 373void videobuf_dma_contig_free(struct videobuf_queue *q,
 374                              struct videobuf_buffer *buf)
 375{
 376        struct videobuf_dma_contig_memory *mem = buf->priv;
 377
 378        /* mmapped memory can't be freed here, otherwise mmapped region
 379           would be released, while still needed. In this case, the memory
 380           release should happen inside videobuf_vm_close().
 381           So, it should free memory only if the memory were allocated for
 382           read() operation.
 383         */
 384        if (buf->memory != V4L2_MEMORY_USERPTR)
 385                return;
 386
 387        if (!mem)
 388                return;
 389
 390        MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
 391
 392        /* handle user space pointer case */
 393        if (buf->baddr) {
 394                videobuf_dma_contig_user_put(mem);
 395                return;
 396        }
 397
 398        /* read() method */
 399        if (mem->vaddr) {
 400                __videobuf_dc_free(q->dev, mem);
 401                mem->vaddr = NULL;
 402        }
 403}
 404EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
 405
 406MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
 407MODULE_AUTHOR("Magnus Damm");
 408MODULE_LICENSE("GPL");
 409