cregit-Linux how code gets into the kernel

Release 4.7 drivers/media/v4l2-core/videobuf2-vmalloc.c

/*
 * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
 *
 * Copyright (C) 2010 Samsung Electronics
 *
 * Author: Pawel Osciak <pawel@osciak.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 */

#include <linux/io.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>

#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>
#include <media/videobuf2-memops.h>


struct vb2_vmalloc_buf {
	
void				*vaddr;
	
struct frame_vector		*vec;
	
enum dma_data_direction		dma_dir;
	
unsigned long			size;
	
atomic_t			refcount;
	
struct vb2_vmarea_handler	handler;
	
struct dma_buf			*dbuf;
};

static void vb2_vmalloc_put(void *buf_priv);


static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size, enum dma_data_direction dma_dir, gfp_t gfp_flags) { struct vb2_vmalloc_buf *buf; buf = kzalloc(sizeof(*buf), GFP_KERNEL | gfp_flags); if (!buf) return NULL; buf->size = size; buf->vaddr = vmalloc_user(buf->size); buf->dma_dir = dma_dir; buf->handler.refcount = &buf->refcount; buf->handler.put = vb2_vmalloc_put; buf->handler.arg = buf; if (!buf->vaddr) { pr_debug("vmalloc of size %ld failed\n", buf->size); kfree(buf); return NULL; } atomic_inc(&buf->refcount); return buf; }

Contributors

PersonTokensPropCommitsCommitProp
pawel osciakpawel osciak11886.13%125.00%
hans verkuilhans verkuil1510.95%250.00%
andrzej pietrasiewiczandrzej pietrasiewicz42.92%125.00%
Total137100.00%4100.00%


static void vb2_vmalloc_put(void *buf_priv) { struct vb2_vmalloc_buf *buf = buf_priv; if (atomic_dec_and_test(&buf->refcount)) { vfree(buf->vaddr); kfree(buf); } }

Contributors

PersonTokensPropCommitsCommitProp
pawel osciakpawel osciak2765.85%150.00%
andrzej pietrasiewiczandrzej pietrasiewicz1434.15%150.00%
Total41100.00%2100.00%


static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, unsigned long size, enum dma_data_direction dma_dir) { struct vb2_vmalloc_buf *buf; struct frame_vector *vec; int n_pages, offset, i; buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (!buf) return NULL; buf->dma_dir = dma_dir; offset = vaddr & ~PAGE_MASK; buf->size = size; vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE); if (IS_ERR(vec)) goto fail_pfnvec_create; buf->vec = vec; n_pages = frame_vector_count(vec); if (frame_vector_to_pages(vec) < 0) { unsigned long *nums = frame_vector_pfns(vec); /* * We cannot get page pointers for these pfns. Check memory is * physically contiguous and use direct mapping. */ for (i = 1; i < n_pages; i++) if (nums[i-1] + 1 != nums[i]) goto fail_map; buf->vaddr = (__force void *) ioremap_nocache(nums[0] << PAGE_SHIFT, size); } else { buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1, PAGE_KERNEL); } if (!buf->vaddr) goto fail_map; buf->vaddr += offset; return buf; fail_map: vb2_destroy_framevec(vec); fail_pfnvec_create: kfree(buf); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
andrzej pietrasiewiczandrzej pietrasiewicz11847.39%120.00%
jan karajan kara9136.55%120.00%
javier martinjavier martin2510.04%120.00%
pawel osciakpawel osciak104.02%120.00%
hans verkuilhans verkuil52.01%120.00%
Total249100.00%5100.00%


static void vb2_vmalloc_put_userptr(void *buf_priv) { struct vb2_vmalloc_buf *buf = buf_priv; unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK; unsigned int i; struct page **pages; unsigned int n_pages; if (!buf->vec->is_pfns) { n_pages = frame_vector_count(buf->vec); pages = frame_vector_pages(buf->vec); if (vaddr) vm_unmap_ram((void *)vaddr, n_pages); if (buf->dma_dir == DMA_FROM_DEVICE) for (i = 0; i < n_pages; i++) set_page_dirty_lock(pages[i]); } else { iounmap((__force void __iomem *)buf->vaddr); } vb2_destroy_framevec(buf->vec); kfree(buf); }

Contributors

PersonTokensPropCommitsCommitProp
andrzej pietrasiewiczandrzej pietrasiewicz5739.04%120.00%
jan karajan kara4832.88%120.00%
pawel osciakpawel osciak1913.01%120.00%
javier martinjavier martin1610.96%120.00%
hans verkuilhans verkuil64.11%120.00%
Total146100.00%5100.00%


static void *vb2_vmalloc_vaddr(void *buf_priv) { struct vb2_vmalloc_buf *buf = buf_priv; if (!buf->vaddr) { pr_err("Address of an unallocated plane requested " "or cannot map user pointer\n"); return NULL; } return buf->vaddr; }

Contributors

PersonTokensPropCommitsCommitProp
pawel osciakpawel osciak2151.22%150.00%
andrzej pietrasiewiczandrzej pietrasiewicz2048.78%150.00%
Total41100.00%2100.00%


static unsigned int vb2_vmalloc_num_users(void *buf_priv) { struct vb2_vmalloc_buf *buf = buf_priv; return atomic_read(&buf->refcount); }

Contributors

PersonTokensPropCommitsCommitProp
pawel osciakpawel osciak27100.00%1100.00%
Total27100.00%1100.00%


static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) { struct vb2_vmalloc_buf *buf = buf_priv; int ret; if (!buf) { pr_err("No memory to map\n"); return -EINVAL; } ret = remap_vmalloc_range(vma, buf->vaddr, 0); if (ret) { pr_err("Remapping vmalloc memory, error: %d\n", ret); return ret; } /* * Make sure that vm_areas for 2 buffers won't be merged together */ vma->vm_flags |= VM_DONTEXPAND; /* * Use common vm_area operations to track buffer refcount. */ vma->vm_private_data = &buf->handler; vma->vm_ops = &vb2_common_vm_ops; vma->vm_ops->open(vma); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pawel osciakpawel osciak10498.11%150.00%
andrzej pietrasiewiczandrzej pietrasiewicz21.89%150.00%
Total106100.00%2100.00%

#ifdef CONFIG_HAS_DMA /*********************************************/ /* DMABUF ops for exporters */ /*********************************************/ struct vb2_vmalloc_attachment { struct sg_table sgt; enum dma_data_direction dma_dir; };
static int vb2_vmalloc_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev, struct dma_buf_attachment *dbuf_attach) { struct vb2_vmalloc_attachment *attach; struct vb2_vmalloc_buf *buf = dbuf->priv; int num_pages = PAGE_ALIGN(buf->size) / PAGE_SIZE; struct sg_table *sgt; struct scatterlist *sg; void *vaddr = buf->vaddr; int ret; int i; attach = kzalloc(sizeof(*attach), GFP_KERNEL); if (!attach) return -ENOMEM; sgt = &attach->sgt; ret = sg_alloc_table(sgt, num_pages, GFP_KERNEL); if (ret) { kfree(attach); return ret; } for_each_sg(sgt->sgl, sg, sgt->nents, i) { struct page *page = vmalloc_to_page(vaddr); if (!page) { sg_free_table(sgt); kfree(attach); return -ENOMEM; } sg_set_page(sg, page, PAGE_SIZE, 0); vaddr += PAGE_SIZE; } attach->dma_dir = DMA_NONE; dbuf_attach->priv = attach; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil198100.00%1100.00%
Total198100.00%1100.00%


static void vb2_vmalloc_dmabuf_ops_detach(struct dma_buf *dbuf, struct dma_buf_attachment *db_attach) { struct vb2_vmalloc_attachment *attach = db_attach->priv; struct sg_table *sgt; if (!attach) return; sgt = &attach->sgt; /* release the scatterlist cache */ if (attach->dma_dir != DMA_NONE) dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, attach->dma_dir); sg_free_table(sgt); kfree(attach); db_attach->priv = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil87100.00%1100.00%
Total87100.00%1100.00%


static struct sg_table *vb2_vmalloc_dmabuf_ops_map( struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) { struct vb2_vmalloc_attachment *attach = db_attach->priv; /* stealing dmabuf mutex to serialize map/unmap operations */ struct mutex *lock = &db_attach->dmabuf->lock; struct sg_table *sgt; mutex_lock(lock); sgt = &attach->sgt; /* return previously mapped sg table */ if (attach->dma_dir == dma_dir) { mutex_unlock(lock); return sgt; } /* release any previous cache */ if (attach->dma_dir != DMA_NONE) { dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, attach->dma_dir); attach->dma_dir = DMA_NONE; } /* mapping to the client with new direction */ sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, dma_dir); if (!sgt->nents) { pr_err("failed to map scatterlist\n"); mutex_unlock(lock); return ERR_PTR(-EIO); } attach->dma_dir = dma_dir; mutex_unlock(lock); return sgt; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil16695.95%150.00%
ricardo ribaldaricardo ribalda74.05%150.00%
Total173100.00%2100.00%


static void vb2_vmalloc_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach, struct sg_table *sgt, enum dma_data_direction dma_dir) { /* nothing to be done here */ }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil21100.00%1100.00%
Total21100.00%1100.00%


static void vb2_vmalloc_dmabuf_ops_release(struct dma_buf *dbuf) { /* drop reference obtained in vb2_vmalloc_get_dmabuf */ vb2_vmalloc_put(dbuf->priv); }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil19100.00%1100.00%
Total19100.00%1100.00%


static void *vb2_vmalloc_dmabuf_ops_kmap(struct dma_buf *dbuf, unsigned long pgnum) { struct vb2_vmalloc_buf *buf = dbuf->priv; return buf->vaddr + pgnum * PAGE_SIZE; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil34100.00%1100.00%
Total34100.00%1100.00%


static void *vb2_vmalloc_dmabuf_ops_vmap(struct dma_buf *dbuf) { struct vb2_vmalloc_buf *buf = dbuf->priv; return buf->vaddr; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil26100.00%1100.00%
Total26100.00%1100.00%


static int vb2_vmalloc_dmabuf_ops_mmap(struct dma_buf *dbuf, struct vm_area_struct *vma) { return vb2_vmalloc_mmap(dbuf->priv, vma); }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil26100.00%1100.00%
Total26100.00%1100.00%

static struct dma_buf_ops vb2_vmalloc_dmabuf_ops = { .attach = vb2_vmalloc_dmabuf_ops_attach, .detach = vb2_vmalloc_dmabuf_ops_detach, .map_dma_buf = vb2_vmalloc_dmabuf_ops_map, .unmap_dma_buf = vb2_vmalloc_dmabuf_ops_unmap, .kmap = vb2_vmalloc_dmabuf_ops_kmap, .kmap_atomic = vb2_vmalloc_dmabuf_ops_kmap, .vmap = vb2_vmalloc_dmabuf_ops_vmap, .mmap = vb2_vmalloc_dmabuf_ops_mmap, .release = vb2_vmalloc_dmabuf_ops_release, };
static struct dma_buf *vb2_vmalloc_get_dmabuf(void *buf_priv, unsigned long flags) { struct vb2_vmalloc_buf *buf = buf_priv; struct dma_buf *dbuf; DEFINE_DMA_BUF_EXPORT_INFO(exp_info); exp_info.ops = &vb2_vmalloc_dmabuf_ops; exp_info.size = buf->size; exp_info.flags = flags; exp_info.priv = buf; if (WARN_ON(!buf->vaddr)) return NULL; dbuf = dma_buf_export(&exp_info); if (IS_ERR(dbuf)) return NULL; /* dmabuf keeps reference to vb2 buffer */ atomic_inc(&buf->refcount); return dbuf; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil7067.96%150.00%
sumit semwalsumit semwal3332.04%150.00%
Total103100.00%2100.00%

#endif /* CONFIG_HAS_DMA */ /*********************************************/ /* callbacks for DMABUF buffers */ /*********************************************/
static int vb2_vmalloc_map_dmabuf(void *mem_priv) { struct vb2_vmalloc_buf *buf = mem_priv; buf->vaddr = dma_buf_vmap(buf->dbuf); return buf->vaddr ? 0 : -EFAULT; }

Contributors

PersonTokensPropCommitsCommitProp
tomasz stanislawskitomasz stanislawski38100.00%1100.00%
Total38100.00%1100.00%


static void vb2_vmalloc_unmap_dmabuf(void *mem_priv) { struct vb2_vmalloc_buf *buf = mem_priv; dma_buf_vunmap(buf->dbuf, buf->vaddr); buf->vaddr = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
tomasz stanislawskitomasz stanislawski34100.00%1100.00%
Total34100.00%1100.00%


static void vb2_vmalloc_detach_dmabuf(void *mem_priv) { struct vb2_vmalloc_buf *buf = mem_priv; if (buf->vaddr) dma_buf_vunmap(buf->dbuf, buf->vaddr); kfree(buf); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz stanislawskitomasz stanislawski39100.00%1100.00%
Total39100.00%1100.00%


static void *vb2_vmalloc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, unsigned long size, enum dma_data_direction dma_dir) { struct vb2_vmalloc_buf *buf; if (dbuf->size < size) return ERR_PTR(-EFAULT); buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (!buf) return ERR_PTR(-ENOMEM); buf->dbuf = dbuf; buf->dma_dir = dma_dir; buf->size = size; return buf; }

Contributors

PersonTokensPropCommitsCommitProp
tomasz stanislawskitomasz stanislawski8594.44%150.00%
hans verkuilhans verkuil55.56%150.00%
Total90100.00%2100.00%

const struct vb2_mem_ops vb2_vmalloc_memops = { .alloc = vb2_vmalloc_alloc, .put = vb2_vmalloc_put, .get_userptr = vb2_vmalloc_get_userptr, .put_userptr = vb2_vmalloc_put_userptr, #ifdef CONFIG_HAS_DMA .get_dmabuf = vb2_vmalloc_get_dmabuf, #endif .map_dmabuf = vb2_vmalloc_map_dmabuf, .unmap_dmabuf = vb2_vmalloc_unmap_dmabuf, .attach_dmabuf = vb2_vmalloc_attach_dmabuf, .detach_dmabuf = vb2_vmalloc_detach_dmabuf, .vaddr = vb2_vmalloc_vaddr, .mmap = vb2_vmalloc_mmap, .num_users = vb2_vmalloc_num_users, }; EXPORT_SYMBOL_GPL(vb2_vmalloc_memops); MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2"); MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil75440.21%531.25%
pawel osciakpawel osciak42522.67%212.50%
andrzej pietrasiewiczandrzej pietrasiewicz23012.27%16.25%
tomasz stanislawskitomasz stanislawski22411.95%16.25%
jan karajan kara1417.52%16.25%
javier martinjavier martin462.45%16.25%
sumit semwalsumit semwal331.76%16.25%
geert uytterhoevengeert uytterhoeven110.59%16.25%
ricardo ribaldaricardo ribalda70.37%16.25%
nicolas therynicolas thery30.16%16.25%
junghak sungjunghak sung10.05%16.25%
Total1875100.00%16100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}