From 62c2aed60372c97eebda02e8833c15b418a16fb0 Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Mon, 20 Aug 2012 13:02:04 -0700 Subject: media: tegra: Tegra videobuf2 This is based off of videobuf2-dma-contig, except we use Tegra's nvmap for the buffer allocations. Signed-off-by: Andrew Chew Change-Id: I15e689c33ee7b4fc0aade794c78701c82483df3f Reviewed-on: http://git-master/r/145345 (cherry picked from commit 70a4f20fbdd6c2c719400d6c59ef58d845657031) Signed-off-by: Bryan Wu Change-Id: Ia0632d7fcb28415e33fbb22c48f29117d7436f1d Reviewed-on: http://git-master/r/170824 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Andrew Chew GVS: Gerrit_Virtual_Submit Reviewed-by: Winnie Hsu --- drivers/media/video/Kconfig | 6 + drivers/media/video/Makefile | 1 + drivers/media/video/videobuf2-dma-nvmap.c | 238 ++++++++++++++++++++++++++++++ include/media/videobuf2-dma-nvmap.h | 36 +++++ 4 files changed, 281 insertions(+) create mode 100644 drivers/media/video/videobuf2-dma-nvmap.c create mode 100644 include/media/videobuf2-dma-nvmap.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 18c9805a8140..1d392bf0d521 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -66,6 +66,12 @@ config VIDEOBUF2_DMA_SG select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS tristate + +config VIDEOBUF2_DMA_NVMAP + select VIDEOBUF2_CORE + select VIDEOBUF2_MEMOPS + tristate + # # Multimedia Video device configuration # diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 21ec2c37da23..b8663f00366e 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -122,6 +122,7 @@ obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o +obj-$(CONFIG_VIDEOBUF2_DMA_NVMAP) += videobuf2-dma-nvmap.o obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o diff --git a/drivers/media/video/videobuf2-dma-nvmap.c b/drivers/media/video/videobuf2-dma-nvmap.c new file mode 100644 index 000000000000..27f43e5a3a57 --- /dev/null +++ b/drivers/media/video/videobuf2-dma-nvmap.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2012, 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, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include +#include + +struct vb2_dc_conf { + struct device *dev; + struct nvmap_client *nvmap_client; +}; + +struct vb2_dc_buf { + struct vb2_dc_conf *conf; + void *vaddr; + dma_addr_t paddr; + unsigned long size; + struct vm_area_struct *vma; + atomic_t refcount; + struct vb2_vmarea_handler handler; + + struct nvmap_handle_ref *nvmap_ref; +}; + +static void vb2_dma_nvmap_put(void *buf_priv); + +static void *vb2_dma_nvmap_alloc(void *alloc_ctx, unsigned long size) +{ + struct vb2_dc_conf *conf = alloc_ctx; + struct vb2_dc_buf *buf; + int ret; + + buf = kzalloc(sizeof *buf, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto exit; + } + + buf->nvmap_ref = nvmap_alloc(conf->nvmap_client, size, 32, + NVMAP_HANDLE_CACHEABLE, NVMAP_HEAP_SYSMEM); + if (IS_ERR(buf->nvmap_ref)) { + dev_err(conf->dev, "nvmap_alloc failed\n"); + ret = -ENOMEM; + goto exit_free; + } + + buf->paddr = nvmap_pin(conf->nvmap_client, buf->nvmap_ref); + if (IS_ERR_VALUE(buf->paddr)) { + dev_err(conf->dev, "nvmap_pin failed\n"); + ret = -ENOMEM; + goto exit_dealloc; + } + + buf->vaddr = nvmap_mmap(buf->nvmap_ref); + if (!buf->vaddr) { + dev_err(conf->dev, "nvmap_mmap failed\n"); + ret = -ENOMEM; + goto exit_unpin; + } + + buf->conf = conf; + buf->size = size; + + buf->handler.refcount = &buf->refcount; + buf->handler.put = vb2_dma_nvmap_put; + buf->handler.arg = buf; + + atomic_inc(&buf->refcount); + + return buf; + +exit_unpin: + nvmap_unpin(conf->nvmap_client, buf->nvmap_ref); +exit_dealloc: + nvmap_free(conf->nvmap_client, buf->nvmap_ref); +exit_free: + kfree(buf); +exit: + return ERR_PTR(ret); +} + +static void vb2_dma_nvmap_put(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + if (atomic_dec_and_test(&buf->refcount)) { + nvmap_munmap(buf->nvmap_ref, buf->vaddr); + nvmap_unpin(buf->conf->nvmap_client, buf->nvmap_ref); + nvmap_free(buf->conf->nvmap_client, buf->nvmap_ref); + kfree(buf); + } +} + +static void *vb2_dma_nvmap_cookie(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + return &buf->paddr; +} + +static void *vb2_dma_nvmap_vaddr(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + if (!buf) + return 0; + + return buf->vaddr; +} + +static unsigned int vb2_dma_nvmap_num_users(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + return atomic_read(&buf->refcount); +} + +static int vb2_dma_nvmap_mmap(void *buf_priv, struct vm_area_struct *vma) +{ + struct vb2_dc_buf *buf = buf_priv; + + 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); +} + +static void *vb2_dma_nvmap_get_userptr(void *alloc_ctx, unsigned long vaddr, + unsigned long size, int write) +{ + struct vb2_dc_buf *buf; + struct vm_area_struct *vma; + dma_addr_t paddr = 0; + int ret; + + buf = kzalloc(sizeof *buf, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr); + if (ret) { + printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n", + vaddr); + kfree(buf); + return ERR_PTR(ret); + } + + buf->size = size; + buf->paddr = paddr; + buf->vma = vma; + + return buf; +} + +static void vb2_dma_nvmap_put_userptr(void *mem_priv) +{ + struct vb2_dc_buf *buf = mem_priv; + + if (!buf) + return; + + vb2_put_vma(buf->vma); + kfree(buf); +} + +const struct vb2_mem_ops vb2_dma_nvmap_memops = { + .alloc = vb2_dma_nvmap_alloc, + .put = vb2_dma_nvmap_put, + .cookie = vb2_dma_nvmap_cookie, + .vaddr = vb2_dma_nvmap_vaddr, + .mmap = vb2_dma_nvmap_mmap, + .get_userptr = vb2_dma_nvmap_get_userptr, + .put_userptr = vb2_dma_nvmap_put_userptr, + .num_users = vb2_dma_nvmap_num_users, +}; +EXPORT_SYMBOL_GPL(vb2_dma_nvmap_memops); + +void *vb2_dma_nvmap_init_ctx(struct device *dev) +{ + struct vb2_dc_conf *conf; + int ret; + + conf = kzalloc(sizeof *conf, GFP_KERNEL); + if (!conf) { + ret = -ENOMEM; + goto exit; + } + + conf->dev = dev; + + conf->nvmap_client = nvmap_create_client(nvmap_dev, + "videobuf2-dma-nvmap"); + if (!conf->nvmap_client) { + ret = -ENOMEM; + goto exit_free; + } + + return conf; + +exit_free: + kfree(conf); +exit: + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(vb2_dma_nvmap_init_ctx); + +void vb2_dma_nvmap_cleanup_ctx(void *alloc_ctx) +{ + struct vb2_dc_conf *conf = alloc_ctx; + + nvmap_client_put(conf->nvmap_client); + + kfree(alloc_ctx); +} +EXPORT_SYMBOL_GPL(vb2_dma_nvmap_cleanup_ctx); + +MODULE_DESCRIPTION("DMA-nvmap memory handling routines for videobuf2"); +MODULE_AUTHOR("Andrew Chew "); +MODULE_LICENSE("GPL"); diff --git a/include/media/videobuf2-dma-nvmap.h b/include/media/videobuf2-dma-nvmap.h new file mode 100644 index 000000000000..39ae3d3a1d5d --- /dev/null +++ b/include/media/videobuf2-dma-nvmap.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012, 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, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _MEDIA_VIDEOBUF2_DMA_NVMAP_H +#define _MEDIA_VIDEOBUF2_DMA_NVMAP_H + +#include +#include + +static inline dma_addr_t +vb2_dma_nvmap_plane_paddr(struct vb2_buffer *vb, unsigned int plane_no) +{ + dma_addr_t *paddr = vb2_plane_cookie(vb, plane_no); + + return *paddr; +} + +void *vb2_dma_nvmap_init_ctx(struct device *dev); +void vb2_dma_nvmap_cleanup_ctx(void *alloc_ctx); + +extern const struct vb2_mem_ops vb2_dma_nvmap_memops; + +#endif -- cgit v1.2.3