From bb608d8f147839a4c8e53476fb97f1f3eaff3db5 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Tue, 23 Apr 2013 15:27:40 -0700 Subject: media: videobuf2: fix buffer management issues Use right buffer flag NVMAP_HANDLE_WRITE_COMBINE to allocate buffer, which can be shared by VI/CSI and CPU. Don't use NVMAP_HEAP_SYSMEM. It is validated to old T20 silicon and can't support big buffers. By default, our nvmap_alloc() will use IOVMM to allocate buffers. nvmap_pin() gives us IOVA for hardware engines like VI/CSI module with IOMMU enabled in kernel. nvmap_mmap() gives us VA for CPU read/write operations. So we need to convert VA address to physical address of the buffer and map that buffer to user space processor's memory space "page by page". Change-Id: I543d9d95fc14395200647e09480f25d9bc001e00 Signed-off-by: Bryan Wu --- drivers/media/video/videobuf2-dma-nvmap.c | 33 ++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/videobuf2-dma-nvmap.c b/drivers/media/video/videobuf2-dma-nvmap.c index 27f43e5a3a57..8c3c36c9922f 100644 --- a/drivers/media/video/videobuf2-dma-nvmap.c +++ b/drivers/media/video/videobuf2-dma-nvmap.c @@ -54,7 +54,7 @@ static void *vb2_dma_nvmap_alloc(void *alloc_ctx, unsigned long size) } buf->nvmap_ref = nvmap_alloc(conf->nvmap_client, size, 32, - NVMAP_HANDLE_CACHEABLE, NVMAP_HEAP_SYSMEM); + NVMAP_HANDLE_UNCACHEABLE, 0); if (IS_ERR(buf->nvmap_ref)) { dev_err(conf->dev, "nvmap_alloc failed\n"); ret = -ENOMEM; @@ -134,14 +134,41 @@ static unsigned int vb2_dma_nvmap_num_users(void *buf_priv) static int vb2_dma_nvmap_mmap(void *buf_priv, struct vm_area_struct *vma) { struct vb2_dc_buf *buf = buf_priv; + unsigned long vm_start, paddr; + void * vaddr; + int size; + int ret; if (!buf) { printk(KERN_ERR "No buffer to map\n"); return -EINVAL; } - return vb2_mmap_pfn_range(vma, buf->paddr, buf->size, - &vb2_common_vm_ops, &buf->handler); + size = min_t(unsigned long, vma->vm_end - vma->vm_start, buf->size); + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + for (vaddr = buf->vaddr; vaddr < buf->vaddr + size; + vaddr += PAGE_SIZE) { + paddr = page_to_phys(vmalloc_to_page(vaddr)); + vm_start = vma->vm_start + (unsigned long) (vaddr - buf->vaddr); + ret = remap_pfn_range(vma, vm_start, paddr >> PAGE_SHIFT, + PAGE_SIZE, vma->vm_page_prot); + if (ret) { + printk(KERN_ERR "Remapping memory failed, error: %d\n", ret); + return ret; + } + pr_debug("%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n", + __func__, paddr, vm_start, PAGE_SIZE); + } + + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + vma->vm_private_data = &buf->handler; + vma->vm_ops = &vb2_common_vm_ops; + + vma->vm_ops->open(vma); + + return 0; } static void *vb2_dma_nvmap_get_userptr(void *alloc_ctx, unsigned long vaddr, -- cgit v1.2.3