media: videobuf2: fix buffer management issues
Bryan Wu [Tue, 23 Apr 2013 22:27:40 +0000 (15:27 -0700)]
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".

Bug 1369083

Change-Id: I4629eebe206c7640adf63551968fd89260dd0082
Signed-off-by: Bryan Wu <pengw@nvidia.com>
Reviewed-on: http://git-master/r/279984
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Allen Martin <amartin@nvidia.com>
Reviewed-by: Matthew Pedro <mapedro@nvidia.com>
Tested-by: Matthew Pedro <mapedro@nvidia.com>

drivers/media/video/videobuf2-dma-nvmap.c

index 27f43e5..5ab3c62 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2012-2013, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -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,42 @@ 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");
+               pr_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) {
+                       pr_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,
@@ -158,8 +186,8 @@ static void *vb2_dma_nvmap_get_userptr(void *alloc_ctx, unsigned long vaddr,
 
        ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr);
        if (ret) {
-               printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n",
-                               vaddr);
+               pr_err("Failed acquiring VMA for vaddr 0x%08lx\n",
+                       vaddr);
                kfree(buf);
                return ERR_PTR(ret);
        }