From fdec8f268bc9968e054955123fd7dad7128d5c8a Mon Sep 17 00:00:00 2001 From: Alex Waterman Date: Wed, 13 Nov 2013 11:58:32 -0800 Subject: video: tegra: nvmap: implement new cache operation Provide the ability to flush a list of handles. This code will optimize the cache flush to be full inner/outer flushes if the total size of the passed list of handles exceeds the inner cache maintenance threshold. Bug 1373180 Change-Id: I357b5d5d1a9697aa6487ad6ef6723448a368a45b Signed-off-by: Alex Waterman Signed-off-by: Sri Krishna chowdary Reviewed-on: http://git-master/r/330638 Reviewed-by: Hiroshi Doyu Tested-by: Hiroshi Doyu --- drivers/video/tegra/nvmap/nvmap_dmabuf.c | 6 +-- drivers/video/tegra/nvmap/nvmap_ioctl.c | 74 ++++++++++++++++++-------------- drivers/video/tegra/nvmap/nvmap_mm.c | 38 ++++++++++++++++ drivers/video/tegra/nvmap/nvmap_priv.h | 8 ++-- 4 files changed, 87 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/video/tegra/nvmap/nvmap_dmabuf.c b/drivers/video/tegra/nvmap/nvmap_dmabuf.c index 370a6c702b26..46f4f63ca45a 100644 --- a/drivers/video/tegra/nvmap/nvmap_dmabuf.c +++ b/drivers/video/tegra/nvmap/nvmap_dmabuf.c @@ -458,8 +458,8 @@ static int nvmap_dmabuf_begin_cpu_access(struct dma_buf *dmabuf, struct nvmap_handle_info *info = dmabuf->priv; trace_nvmap_dmabuf_begin_cpu_access(dmabuf, start, len); - return __nvmap_cache_maint(NULL, info->handle, start, start + len, - NVMAP_CACHE_OP_INV, 1); + return __nvmap_do_cache_maint(NULL, info->handle, start, start + len, + NVMAP_CACHE_OP_INV, 1); } static void nvmap_dmabuf_end_cpu_access(struct dma_buf *dmabuf, @@ -469,7 +469,7 @@ static void nvmap_dmabuf_end_cpu_access(struct dma_buf *dmabuf, struct nvmap_handle_info *info = dmabuf->priv; trace_nvmap_dmabuf_end_cpu_access(dmabuf, start, len); - __nvmap_cache_maint(NULL, info->handle, start, start + len, + __nvmap_do_cache_maint(NULL, info->handle, start, start + len, NVMAP_CACHE_OP_WB_INV, 1); } diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c index b449d40051fe..5a89be557860 100644 --- a/drivers/video/tegra/nvmap/nvmap_ioctl.c +++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c @@ -646,13 +646,9 @@ int nvmap_ioctl_rw_handle(struct file *filp, int is_read, void __user *arg, return err; } -int nvmap_ioctl_cache_maint(struct file *filp, void __user *arg, bool is32) +static int __nvmap_cache_maint(struct nvmap_client *client, + struct nvmap_cache_op *op) { - struct nvmap_client *client = filp->private_data; - struct nvmap_cache_op op; -#ifdef CONFIG_COMPAT - struct nvmap_cache_op_32 op32; -#endif struct vm_area_struct *vma; struct nvmap_vma_priv *vpriv; struct nvmap_handle *handle; @@ -660,31 +656,18 @@ int nvmap_ioctl_cache_maint(struct file *filp, void __user *arg, bool is32) unsigned long end; int err = 0; -#ifdef CONFIG_COMPAT - if (is32) { - if (copy_from_user(&op32, arg, sizeof(op32))) - return -EFAULT; - op.addr = op32.addr; - op.handle = op32.handle; - op.len = op32.len; - op.op = op32.op; - } else -#endif - if (copy_from_user(&op, arg, sizeof(op))) - return -EFAULT; - - handle = unmarshal_user_handle(op.handle); - if (!handle || !op.addr || op.op < NVMAP_CACHE_OP_WB || - op.op > NVMAP_CACHE_OP_WB_INV) + handle = unmarshal_user_handle(op->handle); + if (!handle || !op->addr || op->op < NVMAP_CACHE_OP_WB || + op->op > NVMAP_CACHE_OP_WB_INV) return -EINVAL; down_read(¤t->mm->mmap_sem); - vma = find_vma(current->active_mm, op.addr); + vma = find_vma(current->active_mm, (unsigned long)op->addr); if (!vma || !is_nvmap_vma(vma) || - (ulong)op.addr < vma->vm_start || - (ulong)op.addr >= vma->vm_end || - op.len > vma->vm_end - (ulong)op.addr) { + (ulong)op->addr < vma->vm_start || + (ulong)op->addr >= vma->vm_end || + op->len > vma->vm_end - (ulong)op->addr) { err = -EADDRNOTAVAIL; goto out; } @@ -696,16 +679,41 @@ int nvmap_ioctl_cache_maint(struct file *filp, void __user *arg, bool is32) goto out; } - start = op.addr - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT); - end = start + op.len; + start = (unsigned long)op->addr - vma->vm_start + + (vma->vm_pgoff << PAGE_SHIFT); + end = start + op->len; - err = __nvmap_cache_maint(client, vpriv->handle, start, end, op.op, - CACHE_MAINT_ALLOW_DEFERRED); + err = __nvmap_do_cache_maint(client, vpriv->handle, start, end, op->op, + CACHE_MAINT_ALLOW_DEFERRED); out: up_read(¤t->mm->mmap_sem); return err; } +int nvmap_ioctl_cache_maint(struct file *filp, void __user *arg, bool is32) +{ + struct nvmap_client *client = filp->private_data; + struct nvmap_cache_op op; +#ifdef CONFIG_COMPAT + struct nvmap_cache_op_32 op32; +#endif + +#ifdef CONFIG_COMPAT + if (is32) { + if (copy_from_user(&op32, arg, sizeof(op32))) + return -EFAULT; + op.addr = op32.addr; + op.handle = op32.handle; + op.len = op32.len; + op.op = op32.op; + } else +#endif + if (copy_from_user(&op, arg, sizeof(op))) + return -EFAULT; + + return __nvmap_cache_maint(client, &op); +} + int nvmap_ioctl_free(struct file *filp, unsigned long arg) { struct nvmap_client *client = filp->private_data; @@ -938,7 +946,7 @@ out: return err; } -int __nvmap_cache_maint(struct nvmap_client *client, +int __nvmap_do_cache_maint(struct nvmap_client *client, struct nvmap_handle *h, unsigned long start, unsigned long end, unsigned int op, unsigned int allow_deferred) @@ -1048,7 +1056,7 @@ static ssize_t rw_handle(struct nvmap_client *client, struct nvmap_handle *h, break; } if (is_read) - __nvmap_cache_maint(client, h, h_offs, + __nvmap_do_cache_maint(client, h, h_offs, h_offs + elem_size, NVMAP_CACHE_OP_INV, CACHE_MAINT_IMMEDIATE); @@ -1059,7 +1067,7 @@ static ssize_t rw_handle(struct nvmap_client *client, struct nvmap_handle *h, break; if (!is_read) - __nvmap_cache_maint(client, h, h_offs, + __nvmap_do_cache_maint(client, h, h_offs, h_offs + elem_size, NVMAP_CACHE_OP_WB_INV, CACHE_MAINT_IMMEDIATE); diff --git a/drivers/video/tegra/nvmap/nvmap_mm.c b/drivers/video/tegra/nvmap/nvmap_mm.c index 2af163279fc7..fd29f8b551a9 100644 --- a/drivers/video/tegra/nvmap/nvmap_mm.c +++ b/drivers/video/tegra/nvmap/nvmap_mm.c @@ -83,3 +83,41 @@ void nvmap_flush_cache(struct page **pages, int numpages) #endif } } + +/* + * Flush the list of passed handles. This will optimze the flush if it can. + * In the case that all the handles together are larger than the inner cache + * maint threshold it is possible to just do an entire inner cache flush. + */ +int nvmap_flush_cache_list(struct nvmap_handle **handles, int nr) +{ + int i, err = 0; + u64 total = 0; + + for (i = 0; i < nr; i++) + total += handles[i]->size; + + /* Full flush in the case the passed list is bigger than our + * threshold. */ + if (total >= cache_maint_inner_threshold) { + inner_flush_cache_all(); + outer_flush_all(); + nvmap_stats_inc(NS_CFLUSH_RQ, total); + nvmap_stats_inc(NS_CFLUSH_DONE, cache_maint_inner_threshold); + trace_nvmap_cache_flush(total, + nvmap_stats_read(NS_ALLOC), + nvmap_stats_read(NS_CFLUSH_RQ), + nvmap_stats_read(NS_CFLUSH_DONE)); + } else { + for (i = 0; i < nr; i++) { + err = __nvmap_do_cache_maint(handles[i]->owner, + handles[i], 0, + handles[i]->size, + NVMAP_CACHE_OP_WB_INV, 0); + if (err) + break; + } + } + + return err; +} diff --git a/drivers/video/tegra/nvmap/nvmap_priv.h b/drivers/video/tegra/nvmap/nvmap_priv.h index 13be4a1aa1f0..22e2df786442 100644 --- a/drivers/video/tegra/nvmap/nvmap_priv.h +++ b/drivers/video/tegra/nvmap/nvmap_priv.h @@ -410,6 +410,8 @@ void inner_flush_cache_all(void); void inner_clean_cache_all(void); void nvmap_flush_cache(struct page **pages, int numpages); +int nvmap_flush_cache_list(struct nvmap_handle **handles, int nr); + /* Internal API to support dmabuf */ struct dma_buf *__nvmap_dmabuf_export(struct nvmap_client *client, struct nvmap_handle *handle); @@ -426,9 +428,9 @@ void __nvmap_munmap(struct nvmap_handle *h, void *addr); int __nvmap_map(struct nvmap_handle *h, struct vm_area_struct *vma); int __nvmap_get_handle_param(struct nvmap_client *client, struct nvmap_handle *h, u32 param, u64 *result); -int __nvmap_cache_maint(struct nvmap_client *client, struct nvmap_handle *h, - unsigned long start, unsigned long end, - unsigned int op, unsigned int allow_deferred); +int __nvmap_do_cache_maint(struct nvmap_client *client, struct nvmap_handle *h, + unsigned long start, unsigned long end, + unsigned int op, unsigned int allow_deferred); struct nvmap_client *__nvmap_create_client(struct nvmap_device *dev, const char *name); struct dma_buf *__nvmap_dmabuf_export_from_ref(struct nvmap_handle_ref *ref); -- cgit v1.2.3