summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/nvmap/nvmap_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/nvmap/nvmap_ioctl.c')
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.c58
1 files changed, 45 insertions, 13 deletions
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c
index 44f00d2951a0..da974b2c6846 100644
--- a/drivers/video/tegra/nvmap/nvmap_ioctl.c
+++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c
@@ -3,7 +3,7 @@
*
* User-space interface to nvmap
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -65,10 +65,10 @@ int nvmap_ioctl_pinop(struct file *filp, bool is_pin, void __user *arg)
return -EINVAL;
if (op.count > 1) {
- size_t bytes = op.count * sizeof(unsigned long *);
+ size_t bytes = op.count * sizeof(*refs); /* kcalloc below will catch overflow. */
if (op.count > ARRAY_SIZE(on_stack))
- refs = kmalloc(op.count * sizeof(*refs), GFP_KERNEL);
+ refs = kcalloc(op.count, sizeof(*refs), GFP_KERNEL);
else
refs = on_stack;
@@ -175,6 +175,9 @@ int nvmap_ioctl_alloc(struct file *filp, void __user *arg)
/* user-space handles are aligned to page boundaries, to prevent
* data leakage. */
op.align = max_t(size_t, op.align, PAGE_SIZE);
+#if defined(CONFIG_NVMAP_FORCE_ZEROED_USER_PAGES)
+ op.flags |= NVMAP_HANDLE_ZEROED_PAGES;
+#endif
return nvmap_alloc_handle_id(client, op.handle, op.heap_mask,
op.align, op.flags);
@@ -236,6 +239,11 @@ int nvmap_map_into_caller_ptr(struct file *filp, void __user *arg)
if (!h)
return -EPERM;
+ if(!h->alloc) {
+ nvmap_handle_put(h);
+ return -EFAULT;
+ }
+
trace_nvmap_map_into_caller_ptr(client, h, op.offset,
op.length, op.flags);
down_read(&current->mm->mmap_sem);
@@ -251,7 +259,7 @@ int nvmap_map_into_caller_ptr(struct file *filp, void __user *arg)
goto out;
}
- if ((op.offset + op.length) > h->size) {
+ if (op.offset > h->size || (op.offset + op.length) > h->size) {
err = -EADDRNOTAVAIL;
goto out;
}
@@ -542,14 +550,32 @@ static void heap_page_cache_maint(struct nvmap_client *client,
}
}
+static bool fast_cache_maint_outer(unsigned long start,
+ unsigned long end, unsigned int op)
+{
+ bool result = false;
+#if defined(CONFIG_NVMAP_OUTER_CACHE_MAINT_BY_SET_WAYS)
+ if (end - start >= FLUSH_CLEAN_BY_SET_WAY_THRESHOLD_OUTER) {
+ if (op == NVMAP_CACHE_OP_WB_INV) {
+ outer_flush_all();
+ result = true;
+ }
+ if (op == NVMAP_CACHE_OP_WB) {
+ outer_clean_all();
+ result = true;
+ }
+ }
+#endif
+ return result;
+}
+
static bool fast_cache_maint(struct nvmap_client *client, struct nvmap_handle *h,
unsigned long start, unsigned long end, unsigned int op)
{
int ret = false;
-
#if defined(CONFIG_NVMAP_CACHE_MAINT_BY_SET_WAYS)
if ((op == NVMAP_CACHE_OP_INV) ||
- ((end - start) < FLUSH_CLEAN_BY_SET_WAY_THRESHOLD))
+ ((end - start) < FLUSH_CLEAN_BY_SET_WAY_THRESHOLD_INNER))
goto out;
if (op == NVMAP_CACHE_OP_WB_INV)
@@ -557,13 +583,19 @@ static bool fast_cache_maint(struct nvmap_client *client, struct nvmap_handle *h
else if (op == NVMAP_CACHE_OP_WB)
inner_clean_cache_all();
- if (h->heap_pgalloc && (h->flags != NVMAP_HANDLE_INNER_CACHEABLE)) {
- heap_page_cache_maint(client, h, start, end, op,
- false, true, NULL, 0, 0);
- } else if (h->flags != NVMAP_HANDLE_INNER_CACHEABLE) {
- start += h->carveout->base;
- end += h->carveout->base;
- outer_cache_maint(op, start, end - start);
+ /* outer maintenance */
+ if (h->flags != NVMAP_HANDLE_INNER_CACHEABLE ) {
+ if(!fast_cache_maint_outer(start, end, op))
+ {
+ if (h->heap_pgalloc) {
+ heap_page_cache_maint(client, h, start,
+ end, op, false, true, NULL, 0, 0);
+ } else {
+ start += h->carveout->base;
+ end += h->carveout->base;
+ outer_cache_maint(op, start, end - start);
+ }
+ }
}
ret = true;
out: