162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2010 Samsung Electronics 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Author: Pawel Osciak <pawel@osciak.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 962306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 1062306a36Sopenharmony_ci * the Free Software Foundation. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/mm.h> 1662306a36Sopenharmony_ci#include <linux/refcount.h> 1762306a36Sopenharmony_ci#include <linux/sched.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/vmalloc.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <media/videobuf2-v4l2.h> 2262306a36Sopenharmony_ci#include <media/videobuf2-vmalloc.h> 2362306a36Sopenharmony_ci#include <media/videobuf2-memops.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct vb2_vmalloc_buf { 2662306a36Sopenharmony_ci void *vaddr; 2762306a36Sopenharmony_ci struct frame_vector *vec; 2862306a36Sopenharmony_ci enum dma_data_direction dma_dir; 2962306a36Sopenharmony_ci unsigned long size; 3062306a36Sopenharmony_ci refcount_t refcount; 3162306a36Sopenharmony_ci struct vb2_vmarea_handler handler; 3262306a36Sopenharmony_ci struct dma_buf *dbuf; 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic void vb2_vmalloc_put(void *buf_priv); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void *vb2_vmalloc_alloc(struct vb2_buffer *vb, struct device *dev, 3862306a36Sopenharmony_ci unsigned long size) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci buf = kzalloc(sizeof(*buf), GFP_KERNEL | vb->vb2_queue->gfp_flags); 4362306a36Sopenharmony_ci if (!buf) 4462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci buf->size = size; 4762306a36Sopenharmony_ci buf->vaddr = vmalloc_user(buf->size); 4862306a36Sopenharmony_ci if (!buf->vaddr) { 4962306a36Sopenharmony_ci pr_debug("vmalloc of size %ld failed\n", buf->size); 5062306a36Sopenharmony_ci kfree(buf); 5162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci buf->dma_dir = vb->vb2_queue->dma_dir; 5562306a36Sopenharmony_ci buf->handler.refcount = &buf->refcount; 5662306a36Sopenharmony_ci buf->handler.put = vb2_vmalloc_put; 5762306a36Sopenharmony_ci buf->handler.arg = buf; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci refcount_set(&buf->refcount, 1); 6062306a36Sopenharmony_ci return buf; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void vb2_vmalloc_put(void *buf_priv) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf = buf_priv; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (refcount_dec_and_test(&buf->refcount)) { 6862306a36Sopenharmony_ci vfree(buf->vaddr); 6962306a36Sopenharmony_ci kfree(buf); 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic void *vb2_vmalloc_get_userptr(struct vb2_buffer *vb, struct device *dev, 7462306a36Sopenharmony_ci unsigned long vaddr, unsigned long size) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf; 7762306a36Sopenharmony_ci struct frame_vector *vec; 7862306a36Sopenharmony_ci int n_pages, offset, i; 7962306a36Sopenharmony_ci int ret = -ENOMEM; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci buf = kzalloc(sizeof(*buf), GFP_KERNEL); 8262306a36Sopenharmony_ci if (!buf) 8362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci buf->dma_dir = vb->vb2_queue->dma_dir; 8662306a36Sopenharmony_ci offset = vaddr & ~PAGE_MASK; 8762306a36Sopenharmony_ci buf->size = size; 8862306a36Sopenharmony_ci vec = vb2_create_framevec(vaddr, size, 8962306a36Sopenharmony_ci buf->dma_dir == DMA_FROM_DEVICE || 9062306a36Sopenharmony_ci buf->dma_dir == DMA_BIDIRECTIONAL); 9162306a36Sopenharmony_ci if (IS_ERR(vec)) { 9262306a36Sopenharmony_ci ret = PTR_ERR(vec); 9362306a36Sopenharmony_ci goto fail_pfnvec_create; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci buf->vec = vec; 9662306a36Sopenharmony_ci n_pages = frame_vector_count(vec); 9762306a36Sopenharmony_ci if (frame_vector_to_pages(vec) < 0) { 9862306a36Sopenharmony_ci unsigned long *nums = frame_vector_pfns(vec); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* 10162306a36Sopenharmony_ci * We cannot get page pointers for these pfns. Check memory is 10262306a36Sopenharmony_ci * physically contiguous and use direct mapping. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci for (i = 1; i < n_pages; i++) 10562306a36Sopenharmony_ci if (nums[i-1] + 1 != nums[i]) 10662306a36Sopenharmony_ci goto fail_map; 10762306a36Sopenharmony_ci buf->vaddr = (__force void *) 10862306a36Sopenharmony_ci ioremap(__pfn_to_phys(nums[0]), size + offset); 10962306a36Sopenharmony_ci } else { 11062306a36Sopenharmony_ci buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1); 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (!buf->vaddr) 11462306a36Sopenharmony_ci goto fail_map; 11562306a36Sopenharmony_ci buf->vaddr += offset; 11662306a36Sopenharmony_ci return buf; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cifail_map: 11962306a36Sopenharmony_ci vb2_destroy_framevec(vec); 12062306a36Sopenharmony_cifail_pfnvec_create: 12162306a36Sopenharmony_ci kfree(buf); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return ERR_PTR(ret); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void vb2_vmalloc_put_userptr(void *buf_priv) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf = buf_priv; 12962306a36Sopenharmony_ci unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK; 13062306a36Sopenharmony_ci unsigned int i; 13162306a36Sopenharmony_ci struct page **pages; 13262306a36Sopenharmony_ci unsigned int n_pages; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (!buf->vec->is_pfns) { 13562306a36Sopenharmony_ci n_pages = frame_vector_count(buf->vec); 13662306a36Sopenharmony_ci pages = frame_vector_pages(buf->vec); 13762306a36Sopenharmony_ci if (vaddr) 13862306a36Sopenharmony_ci vm_unmap_ram((void *)vaddr, n_pages); 13962306a36Sopenharmony_ci if (buf->dma_dir == DMA_FROM_DEVICE || 14062306a36Sopenharmony_ci buf->dma_dir == DMA_BIDIRECTIONAL) 14162306a36Sopenharmony_ci for (i = 0; i < n_pages; i++) 14262306a36Sopenharmony_ci set_page_dirty_lock(pages[i]); 14362306a36Sopenharmony_ci } else { 14462306a36Sopenharmony_ci iounmap((__force void __iomem *)buf->vaddr); 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci vb2_destroy_framevec(buf->vec); 14762306a36Sopenharmony_ci kfree(buf); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic void *vb2_vmalloc_vaddr(struct vb2_buffer *vb, void *buf_priv) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf = buf_priv; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (!buf->vaddr) { 15562306a36Sopenharmony_ci pr_err("Address of an unallocated plane requested or cannot map user pointer\n"); 15662306a36Sopenharmony_ci return NULL; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return buf->vaddr; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic unsigned int vb2_vmalloc_num_users(void *buf_priv) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf = buf_priv; 16562306a36Sopenharmony_ci return refcount_read(&buf->refcount); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf = buf_priv; 17162306a36Sopenharmony_ci int ret; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (!buf) { 17462306a36Sopenharmony_ci pr_err("No memory to map\n"); 17562306a36Sopenharmony_ci return -EINVAL; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci ret = remap_vmalloc_range(vma, buf->vaddr, 0); 17962306a36Sopenharmony_ci if (ret) { 18062306a36Sopenharmony_ci pr_err("Remapping vmalloc memory, error: %d\n", ret); 18162306a36Sopenharmony_ci return ret; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* 18562306a36Sopenharmony_ci * Make sure that vm_areas for 2 buffers won't be merged together 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci vm_flags_set(vma, VM_DONTEXPAND); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* 19062306a36Sopenharmony_ci * Use common vm_area operations to track buffer refcount. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ci vma->vm_private_data = &buf->handler; 19362306a36Sopenharmony_ci vma->vm_ops = &vb2_common_vm_ops; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci vma->vm_ops->open(vma); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci#ifdef CONFIG_HAS_DMA 20162306a36Sopenharmony_ci/*********************************************/ 20262306a36Sopenharmony_ci/* DMABUF ops for exporters */ 20362306a36Sopenharmony_ci/*********************************************/ 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistruct vb2_vmalloc_attachment { 20662306a36Sopenharmony_ci struct sg_table sgt; 20762306a36Sopenharmony_ci enum dma_data_direction dma_dir; 20862306a36Sopenharmony_ci}; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic int vb2_vmalloc_dmabuf_ops_attach(struct dma_buf *dbuf, 21162306a36Sopenharmony_ci struct dma_buf_attachment *dbuf_attach) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct vb2_vmalloc_attachment *attach; 21462306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf = dbuf->priv; 21562306a36Sopenharmony_ci int num_pages = PAGE_ALIGN(buf->size) / PAGE_SIZE; 21662306a36Sopenharmony_ci struct sg_table *sgt; 21762306a36Sopenharmony_ci struct scatterlist *sg; 21862306a36Sopenharmony_ci void *vaddr = buf->vaddr; 21962306a36Sopenharmony_ci int ret; 22062306a36Sopenharmony_ci int i; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci attach = kzalloc(sizeof(*attach), GFP_KERNEL); 22362306a36Sopenharmony_ci if (!attach) 22462306a36Sopenharmony_ci return -ENOMEM; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci sgt = &attach->sgt; 22762306a36Sopenharmony_ci ret = sg_alloc_table(sgt, num_pages, GFP_KERNEL); 22862306a36Sopenharmony_ci if (ret) { 22962306a36Sopenharmony_ci kfree(attach); 23062306a36Sopenharmony_ci return ret; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci for_each_sgtable_sg(sgt, sg, i) { 23362306a36Sopenharmony_ci struct page *page = vmalloc_to_page(vaddr); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (!page) { 23662306a36Sopenharmony_ci sg_free_table(sgt); 23762306a36Sopenharmony_ci kfree(attach); 23862306a36Sopenharmony_ci return -ENOMEM; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci sg_set_page(sg, page, PAGE_SIZE, 0); 24162306a36Sopenharmony_ci vaddr += PAGE_SIZE; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci attach->dma_dir = DMA_NONE; 24562306a36Sopenharmony_ci dbuf_attach->priv = attach; 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic void vb2_vmalloc_dmabuf_ops_detach(struct dma_buf *dbuf, 25062306a36Sopenharmony_ci struct dma_buf_attachment *db_attach) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci struct vb2_vmalloc_attachment *attach = db_attach->priv; 25362306a36Sopenharmony_ci struct sg_table *sgt; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (!attach) 25662306a36Sopenharmony_ci return; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci sgt = &attach->sgt; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* release the scatterlist cache */ 26162306a36Sopenharmony_ci if (attach->dma_dir != DMA_NONE) 26262306a36Sopenharmony_ci dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir, 0); 26362306a36Sopenharmony_ci sg_free_table(sgt); 26462306a36Sopenharmony_ci kfree(attach); 26562306a36Sopenharmony_ci db_attach->priv = NULL; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic struct sg_table *vb2_vmalloc_dmabuf_ops_map( 26962306a36Sopenharmony_ci struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci struct vb2_vmalloc_attachment *attach = db_attach->priv; 27262306a36Sopenharmony_ci struct sg_table *sgt; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci sgt = &attach->sgt; 27562306a36Sopenharmony_ci /* return previously mapped sg table */ 27662306a36Sopenharmony_ci if (attach->dma_dir == dma_dir) 27762306a36Sopenharmony_ci return sgt; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* release any previous cache */ 28062306a36Sopenharmony_ci if (attach->dma_dir != DMA_NONE) { 28162306a36Sopenharmony_ci dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir, 0); 28262306a36Sopenharmony_ci attach->dma_dir = DMA_NONE; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* mapping to the client with new direction */ 28662306a36Sopenharmony_ci if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) { 28762306a36Sopenharmony_ci pr_err("failed to map scatterlist\n"); 28862306a36Sopenharmony_ci return ERR_PTR(-EIO); 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci attach->dma_dir = dma_dir; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return sgt; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic void vb2_vmalloc_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach, 29762306a36Sopenharmony_ci struct sg_table *sgt, enum dma_data_direction dma_dir) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci /* nothing to be done here */ 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic void vb2_vmalloc_dmabuf_ops_release(struct dma_buf *dbuf) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci /* drop reference obtained in vb2_vmalloc_get_dmabuf */ 30562306a36Sopenharmony_ci vb2_vmalloc_put(dbuf->priv); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic int vb2_vmalloc_dmabuf_ops_vmap(struct dma_buf *dbuf, 30962306a36Sopenharmony_ci struct iosys_map *map) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf = dbuf->priv; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci iosys_map_set_vaddr(map, buf->vaddr); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return 0; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int vb2_vmalloc_dmabuf_ops_mmap(struct dma_buf *dbuf, 31962306a36Sopenharmony_ci struct vm_area_struct *vma) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci return vb2_vmalloc_mmap(dbuf->priv, vma); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic const struct dma_buf_ops vb2_vmalloc_dmabuf_ops = { 32562306a36Sopenharmony_ci .attach = vb2_vmalloc_dmabuf_ops_attach, 32662306a36Sopenharmony_ci .detach = vb2_vmalloc_dmabuf_ops_detach, 32762306a36Sopenharmony_ci .map_dma_buf = vb2_vmalloc_dmabuf_ops_map, 32862306a36Sopenharmony_ci .unmap_dma_buf = vb2_vmalloc_dmabuf_ops_unmap, 32962306a36Sopenharmony_ci .vmap = vb2_vmalloc_dmabuf_ops_vmap, 33062306a36Sopenharmony_ci .mmap = vb2_vmalloc_dmabuf_ops_mmap, 33162306a36Sopenharmony_ci .release = vb2_vmalloc_dmabuf_ops_release, 33262306a36Sopenharmony_ci}; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic struct dma_buf *vb2_vmalloc_get_dmabuf(struct vb2_buffer *vb, 33562306a36Sopenharmony_ci void *buf_priv, 33662306a36Sopenharmony_ci unsigned long flags) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf = buf_priv; 33962306a36Sopenharmony_ci struct dma_buf *dbuf; 34062306a36Sopenharmony_ci DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci exp_info.ops = &vb2_vmalloc_dmabuf_ops; 34362306a36Sopenharmony_ci exp_info.size = buf->size; 34462306a36Sopenharmony_ci exp_info.flags = flags; 34562306a36Sopenharmony_ci exp_info.priv = buf; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (WARN_ON(!buf->vaddr)) 34862306a36Sopenharmony_ci return NULL; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci dbuf = dma_buf_export(&exp_info); 35162306a36Sopenharmony_ci if (IS_ERR(dbuf)) 35262306a36Sopenharmony_ci return NULL; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* dmabuf keeps reference to vb2 buffer */ 35562306a36Sopenharmony_ci refcount_inc(&buf->refcount); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci return dbuf; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci#endif /* CONFIG_HAS_DMA */ 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/*********************************************/ 36362306a36Sopenharmony_ci/* callbacks for DMABUF buffers */ 36462306a36Sopenharmony_ci/*********************************************/ 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic int vb2_vmalloc_map_dmabuf(void *mem_priv) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf = mem_priv; 36962306a36Sopenharmony_ci struct iosys_map map; 37062306a36Sopenharmony_ci int ret; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci ret = dma_buf_vmap_unlocked(buf->dbuf, &map); 37362306a36Sopenharmony_ci if (ret) 37462306a36Sopenharmony_ci return -EFAULT; 37562306a36Sopenharmony_ci buf->vaddr = map.vaddr; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic void vb2_vmalloc_unmap_dmabuf(void *mem_priv) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf = mem_priv; 38362306a36Sopenharmony_ci struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci dma_buf_vunmap_unlocked(buf->dbuf, &map); 38662306a36Sopenharmony_ci buf->vaddr = NULL; 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic void vb2_vmalloc_detach_dmabuf(void *mem_priv) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf = mem_priv; 39262306a36Sopenharmony_ci struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (buf->vaddr) 39562306a36Sopenharmony_ci dma_buf_vunmap_unlocked(buf->dbuf, &map); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci kfree(buf); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void *vb2_vmalloc_attach_dmabuf(struct vb2_buffer *vb, 40162306a36Sopenharmony_ci struct device *dev, 40262306a36Sopenharmony_ci struct dma_buf *dbuf, 40362306a36Sopenharmony_ci unsigned long size) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct vb2_vmalloc_buf *buf; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (dbuf->size < size) 40862306a36Sopenharmony_ci return ERR_PTR(-EFAULT); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci buf = kzalloc(sizeof(*buf), GFP_KERNEL); 41162306a36Sopenharmony_ci if (!buf) 41262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci buf->dbuf = dbuf; 41562306a36Sopenharmony_ci buf->dma_dir = vb->vb2_queue->dma_dir; 41662306a36Sopenharmony_ci buf->size = size; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci return buf; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ciconst struct vb2_mem_ops vb2_vmalloc_memops = { 42362306a36Sopenharmony_ci .alloc = vb2_vmalloc_alloc, 42462306a36Sopenharmony_ci .put = vb2_vmalloc_put, 42562306a36Sopenharmony_ci .get_userptr = vb2_vmalloc_get_userptr, 42662306a36Sopenharmony_ci .put_userptr = vb2_vmalloc_put_userptr, 42762306a36Sopenharmony_ci#ifdef CONFIG_HAS_DMA 42862306a36Sopenharmony_ci .get_dmabuf = vb2_vmalloc_get_dmabuf, 42962306a36Sopenharmony_ci#endif 43062306a36Sopenharmony_ci .map_dmabuf = vb2_vmalloc_map_dmabuf, 43162306a36Sopenharmony_ci .unmap_dmabuf = vb2_vmalloc_unmap_dmabuf, 43262306a36Sopenharmony_ci .attach_dmabuf = vb2_vmalloc_attach_dmabuf, 43362306a36Sopenharmony_ci .detach_dmabuf = vb2_vmalloc_detach_dmabuf, 43462306a36Sopenharmony_ci .vaddr = vb2_vmalloc_vaddr, 43562306a36Sopenharmony_ci .mmap = vb2_vmalloc_mmap, 43662306a36Sopenharmony_ci .num_users = vb2_vmalloc_num_users, 43762306a36Sopenharmony_ci}; 43862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vb2_vmalloc_memops); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ciMODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2"); 44162306a36Sopenharmony_ciMODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>"); 44262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 44362306a36Sopenharmony_ciMODULE_IMPORT_NS(DMA_BUF); 444