video: tegra: host: Do not access cmdbuf_ext if NULL
[linux-3.10.git] / drivers / video / tegra / host / bus_client.c
index e2a1ecd..030e28c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Tegra Graphics Host Client Module
  *
- * Copyright (c) 2010-2013, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2010-2014, 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,6 +54,7 @@
 #include "nvhost_job.h"
 #include "nvhost_hwctx.h"
 #include "user_hwctx.h"
+#include "nvhost_sync.h"
 
 static int validate_reg(struct platform_device *ndev, u32 offset, int count)
 {
@@ -234,7 +235,6 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
        priv->timeout_debug_dump = true;
        if (!tegra_platform_is_silicon())
                priv->timeout = 0;
-
        return 0;
 fail:
        nvhost_channelrelease(inode, filp);
@@ -435,8 +435,10 @@ static int nvhost_ioctl_channel_submit(struct nvhost_channel_userctx *ctx,
                if (err)
                        goto fail;
 
-               err = copy_from_user(&cmdbuf_ext,
-                               cmdbuf_exts + i, sizeof(cmdbuf_ext));
+               cmdbuf_ext.pre_fence = -1;
+               if (cmdbuf_exts)
+                       err = copy_from_user(&cmdbuf_ext,
+                                       cmdbuf_exts + i, sizeof(cmdbuf_ext));
                if (err)
                        cmdbuf_ext.pre_fence = -1;
 
@@ -480,8 +482,8 @@ static int nvhost_ioctl_channel_submit(struct nvhost_channel_userctx *ctx,
                }
        }
 
-       /* set valid id for hwctx_syncpt_idx if no hwctx is present */
-       if (!ctx->hwctx)
+       /* set valid id for hwctx_syncpt_idx if hwctx does not provide one */
+       if (!ctx->hwctx || ctx->hwctx->h->syncpt == NVSYNCPT_INVALID)
                hwctx_syncpt_idx = 0;
 
        /*
@@ -541,7 +543,9 @@ static int nvhost_ioctl_channel_submit(struct nvhost_channel_userctx *ctx,
                job->sp[job->hwctx_syncpt_idx].id,
                job->sp[job->hwctx_syncpt_idx].incrs);
 
+       nvhost_module_busy(ctx->ch->dev);
        err = nvhost_job_pin(job, &nvhost_get_host(ctx->ch->dev)->syncpt);
+       nvhost_module_idle(ctx->ch->dev);
        if (err)
                goto fail;
 
@@ -568,7 +572,20 @@ static int nvhost_ioctl_channel_submit(struct nvhost_channel_userctx *ctx,
        /* Deliver the fence using the old mechanism _only_ if a single
         * syncpoint is used. */
 
-       if (num_syncpt_incrs == 1)
+       if (args->flags & BIT(NVHOST_SUBMIT_FLAG_SYNC_FENCE_FD)) {
+               struct nvhost_ctrl_sync_fence_info pts[num_syncpt_incrs];
+
+               for (i = 0; i < num_syncpt_incrs; i++) {
+                       pts[i].id = job->sp[i].id;
+                       pts[i].thresh = job->sp[i].fence;
+               }
+
+               err = nvhost_sync_create_fence(
+                               &nvhost_get_host(ctx->ch->dev)->syncpt,
+                               pts, num_syncpt_incrs, "fence", &args->fence);
+               if (err)
+                       goto fail;
+       } else if (num_syncpt_incrs == 1)
                args->fence = job->sp[job->hwctx_syncpt_idx].fence;
        else
                args->fence = 0;
@@ -708,7 +725,7 @@ fail:
        return err;
 }
 
-#if defined(CONFIG_TEGRA_GPU_CYCLE_STATS)
+#if defined(CONFIG_GK20A_CYCLE_STATS)
 static int nvhost_ioctl_channel_cycle_stats(
        struct nvhost_channel_userctx *ctx,
        struct nvhost_cycle_stats_args *args)
@@ -958,7 +975,7 @@ static long nvhost_channelctl(struct file *filp,
                err = nvhost_ioctl_channel_set_error_notifier(priv,
                        (void *)buf);
                break;
-#if defined(CONFIG_TEGRA_GPU_CYCLE_STATS)
+#if defined(CONFIG_GK20A_CYCLE_STATS)
        case NVHOST_IOCTL_CHANNEL_CYCLE_STATS:
                err = nvhost_ioctl_channel_cycle_stats(priv, (void *)buf);
                break;
@@ -984,12 +1001,18 @@ static long nvhost_channelctl(struct file *filp,
                break;
        }
        case NVHOST_IOCTL_CHANNEL_SET_TIMEOUT:
-               priv->timeout =
+       {
+               u32 timeout =
                        (u32)((struct nvhost_set_timeout_args *)buf)->timeout;
+
+               priv->timeout = timeout;
                dev_dbg(&priv->ch->dev->dev,
                        "%s: setting buffer timeout (%d ms) for userctx 0x%p\n",
                        __func__, priv->timeout, priv);
+               if (priv->hwctx)
+                       priv->hwctx->timeout_ms_max = timeout;
                break;
+       }
        case NVHOST_IOCTL_CHANNEL_GET_TIMEDOUT:
                ((struct nvhost_get_param_args *)buf)->value =
                                priv->hwctx->has_timedout;
@@ -1021,6 +1044,7 @@ static long nvhost_channelctl(struct file *filp,
                struct nvhost32_submit_args *args32 = (void *)buf;
                struct nvhost_submit_args args;
 
+               memset(&args, 0, sizeof(args));
                args.submit_version = args32->submit_version;
                args.num_syncpt_incrs = args32->num_syncpt_incrs;
                args.num_cmdbufs = args32->num_cmdbufs;
@@ -1046,15 +1070,23 @@ static long nvhost_channelctl(struct file *filp,
                err = nvhost_ioctl_channel_submit(priv, (void *)buf);
                break;
        case NVHOST_IOCTL_CHANNEL_SET_TIMEOUT_EX:
-               priv->timeout = (u32)
-                       ((struct nvhost_set_timeout_ex_args *)buf)->timeout;
-               priv->timeout_debug_dump = !((u32)
+       {
+               u32 timeout =
+                       (u32)((struct nvhost_set_timeout_args *)buf)->timeout;
+               bool timeout_debug_dump = !((u32)
                        ((struct nvhost_set_timeout_ex_args *)buf)->flags &
                        (1 << NVHOST_TIMEOUT_FLAG_DISABLE_DUMP));
+               priv->timeout = timeout;
+               priv->timeout_debug_dump = timeout_debug_dump;
                dev_dbg(&priv->ch->dev->dev,
                        "%s: setting buffer timeout (%d ms) for userctx 0x%p\n",
                        __func__, priv->timeout, priv);
+               if (priv->hwctx) {
+                       priv->hwctx->timeout_ms_max = timeout;
+                       priv->hwctx->timeout_debug_dump = timeout_debug_dump;
+               }
                break;
+       }
        case NVHOST_IOCTL_CHANNEL_SET_CTXSWITCH:
                err = nvhost_ioctl_channel_set_ctxswitch(priv, (void *)buf);
                break;