video: tegra: host: Add sync wait to submit
Terje Bergstrom [Tue, 10 Sep 2013 06:18:06 +0000 (09:18 +0300)]
Add sync fd wait to submit interface. This allows adding a wait in
form of sync fd.

Bug 1356557

Change-Id: Ieee60c5321a50bb4805eced415fe126283783104
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/288796
Reviewed-by: Automatic_Commit_Validation_User

drivers/video/tegra/host/bus_client.c
drivers/video/tegra/host/host1x/host1x_channel.c
drivers/video/tegra/host/nvhost_job.c
drivers/video/tegra/host/nvhost_job.h
drivers/video/tegra/host/nvhost_sync.c
drivers/video/tegra/host/nvhost_sync.h
include/linux/nvhost_ioctl.h

index 425a4df..e2a1ecd 100644 (file)
@@ -373,6 +373,8 @@ static int nvhost_ioctl_channel_submit(struct nvhost_channel_userctx *ctx,
        int num_syncpt_incrs = args->num_syncpt_incrs;
        struct nvhost_cmdbuf __user *cmdbufs =
                (struct nvhost_cmdbuf *)(uintptr_t)args->cmdbufs;
+       struct nvhost_cmdbuf __user *cmdbuf_exts =
+               (struct nvhost_cmdbuf *)(uintptr_t)args->cmdbuf_exts;
        struct nvhost_reloc __user *relocs =
                (struct nvhost_reloc *)(uintptr_t)args->relocs;
        struct nvhost_reloc_shift __user *reloc_shifts =
@@ -426,14 +428,21 @@ static int nvhost_ioctl_channel_submit(struct nvhost_channel_userctx *ctx,
 
        for (i = 0; i < num_cmdbufs; ++i) {
                struct nvhost_cmdbuf cmdbuf;
+               struct nvhost_cmdbuf_ext cmdbuf_ext;
                u32 class_id = class_ids ? local_class_ids[i] : 0;
 
                err = copy_from_user(&cmdbuf, cmdbufs + i, sizeof(cmdbuf));
                if (err)
                        goto fail;
 
+               err = copy_from_user(&cmdbuf_ext,
+                               cmdbuf_exts + i, sizeof(cmdbuf_ext));
+               if (err)
+                       cmdbuf_ext.pre_fence = -1;
+
                nvhost_job_add_gather(job, cmdbuf.mem, cmdbuf.words,
-                               cmdbuf.offset, class_id);
+                                     cmdbuf.offset, class_id,
+                                     cmdbuf_ext.pre_fence);
        }
 
        kfree(local_class_ids);
index 21ad44c..3410e1c 100644 (file)
@@ -26,6 +26,7 @@
 #include "nvhost_hwctx.h"
 #include <trace/events/nvhost.h>
 #include <linux/slab.h>
+#include "nvhost_sync.h"
 
 #include "nvhost_hwctx.h"
 #include "nvhost_intr.h"
@@ -113,6 +114,46 @@ static void submit_ctxsave(struct nvhost_job *job, struct nvhost_hwctx *cur_ctx)
        trace_nvhost_channel_context_save(ch->dev->name, cur_ctx);
 }
 
+static void add_sync_waits(struct nvhost_channel *ch, int fd)
+{
+       struct sync_fence *fence;
+       struct sync_pt *_pt;
+       struct nvhost_sync_pt *pt;
+       struct list_head *pos;
+
+       if (fd < 0)
+               return;
+
+       fence = nvhost_sync_fdget(fd);
+       if (!fence)
+               return;
+
+       /*
+        * Force serialization by inserting a host wait for the
+        * previous job to finish before this one can commence.
+        *
+        * NOTE! This cannot be packed because otherwise we might
+        * overwrite the RESTART opcode at the end of the push
+        * buffer.
+        */
+
+       list_for_each(pos, &fence->pt_list_head) {
+               u32 id;
+               u32 thresh;
+
+               _pt = container_of(pos, struct sync_pt, pt_list);
+               pt = to_nvhost_sync_pt(_pt);
+               id = nvhost_sync_pt_id(pt);
+               thresh = nvhost_sync_pt_thresh(pt);
+
+               nvhost_cdma_push(&ch->cdma,
+                       nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
+                               host1x_uclass_wait_syncpt_r(), 1),
+                       nvhost_class_host_wait_syncpt(id, thresh));
+       }
+       sync_fence_put(fence);
+}
+
 static void submit_ctxrestore(struct nvhost_job *job)
 {
        struct nvhost_master *host = nvhost_get_host(job->ch->dev);
@@ -206,6 +247,7 @@ static void submit_gathers(struct nvhost_job *job)
                        class_id = g->class_id;
                }
 
+               add_sync_waits(job->ch, g->pre_fence);
                /* If register is specified, add a gather with incr/nonincr.
                 * This allows writing large amounts of data directly from
                 * memory to a register. */
index eaff7bb..e5215ea 100644 (file)
@@ -154,7 +154,7 @@ void nvhost_job_put(struct nvhost_job *job)
 }
 
 void nvhost_job_add_gather(struct nvhost_job *job,
-               u32 mem_id, u32 words, u32 offset, u32 class_id)
+               u32 mem_id, u32 words, u32 offset, u32 class_id, int pre_fence)
 {
        struct nvhost_device_data *pdata = platform_get_drvdata(job->ch->dev);
        struct nvhost_job_gather *cur_gather =
@@ -164,6 +164,7 @@ void nvhost_job_add_gather(struct nvhost_job *job,
        cur_gather->mem_id = mem_id;
        cur_gather->offset = offset;
        cur_gather->class_id = class_id ? class_id : pdata->class;
+       cur_gather->pre_fence = pre_fence;
        job->num_gathers += 1;
 }
 
index b6fc6c0..ae490d3 100644 (file)
@@ -38,6 +38,7 @@ struct nvhost_job_gather {
        u32 class_id;
        int offset;
        struct mem_handle *ref;
+       int pre_fence;
 };
 
 struct nvhost_job_syncpt {
@@ -130,7 +131,7 @@ struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
  * Add a gather to a job.
  */
 void nvhost_job_add_gather(struct nvhost_job *job,
-               u32 mem_id, u32 words, u32 offset, u32 class_id);
+               u32 mem_id, u32 words, u32 offset, u32 class_id, int pre_fence);
 
 /*
  * Increment reference going to nvhost_job.
index 891b046..8dbb0f6 100644 (file)
@@ -55,7 +55,7 @@ struct nvhost_sync_pt_inst {
        struct nvhost_sync_pt           *shared;
 };
 
-static struct nvhost_sync_pt *to_nvhost_sync_pt(struct sync_pt *pt)
+struct nvhost_sync_pt *to_nvhost_sync_pt(struct sync_pt *pt)
 {
        struct nvhost_sync_pt_inst *pti =
                        container_of(pt, struct nvhost_sync_pt_inst, pt);
@@ -240,7 +240,7 @@ static int nvhost_sync_fill_driver_data(struct sync_pt *sync_pt,
        return sizeof(info);
 }
 
-struct sync_timeline_ops nvhost_sync_timeline_ops = {
+static const struct sync_timeline_ops nvhost_sync_timeline_ops = {
        .driver_name = "nvhost_sync",
        .dup = nvhost_sync_pt_dup_inst,
        .has_signaled = nvhost_sync_pt_has_signaled,
@@ -251,6 +251,38 @@ struct sync_timeline_ops nvhost_sync_timeline_ops = {
        .pt_value_str = nvhost_sync_pt_value_str,
 };
 
+struct sync_fence *nvhost_sync_fdget(int fd)
+{
+       struct sync_fence *fence = sync_fence_fdget(fd);
+       struct list_head *pos;
+
+       if (!fence)
+               return fence;
+
+       list_for_each(pos, &fence->pt_list_head) {
+               struct sync_pt *pt =
+                       container_of(pos, struct sync_pt, pt_list);
+               struct sync_timeline *timeline = pt->parent;
+
+               if (timeline->ops != &nvhost_sync_timeline_ops) {
+                       sync_fence_put(fence);
+                       return ERR_PTR(-EINVAL);
+               }
+       }
+
+       return fence;
+}
+
+u32 nvhost_sync_pt_id(struct nvhost_sync_pt *pt)
+{
+       return pt->obj->id;
+}
+
+u32 nvhost_sync_pt_thresh(struct nvhost_sync_pt *pt)
+{
+       return pt->thresh;
+}
+
 /* Public API */
 
 struct nvhost_sync_timeline *nvhost_sync_timeline_create(
index 5428063..0c8b06a 100644 (file)
@@ -1,9 +1,7 @@
 /*
- * drivers/video/tegra/host/nvhost_sync.h
- *
  * Tegra Graphics Host Syncpoint Integration to linux/sync Framework
  *
- * Copyright (c) 2013, NVIDIA Corporation.
+ * Copyright (c) 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,
@@ -45,6 +43,10 @@ int nvhost_sync_create_fence(
                u32 num_pts,
                const char *name,
                s32 *fence_fd);
+struct sync_fence *nvhost_sync_fdget(int fd);
+struct nvhost_sync_pt *to_nvhost_sync_pt(struct sync_pt *pt);
+u32 nvhost_sync_pt_id(struct nvhost_sync_pt *pt);
+u32 nvhost_sync_pt_thresh(struct nvhost_sync_pt *pt);
 
 #else
 static inline struct nvhost_sync_timeline *nvhost_sync_timeline_create(
@@ -68,6 +70,27 @@ static inline int nvhost_sync_create_fence(
 {
        return -EINVAL;
 }
+
+static inline struct sync_fence *nvhost_sync_fdget(int fd)
+{
+       return NULL;
+}
+
+static inline struct nvhost_sync_pt *to_nvhost_sync_pt(struct sync_pt *pt)
+{
+       return NULL;
+}
+
+static inline u32 nvhost_sync_pt_id(struct nvhost_sync_pt *pt)
+{
+       return NVSYNCPT_INVALID;
+}
+
+static inline u32 nvhost_sync_pt_thresh(struct nvhost_sync_pt *pt)
+{
+       return 0;
+}
+
 #endif
 
 #endif /* __KERNEL __ */
index d22fcc2..dd903ca 100644 (file)
@@ -51,6 +51,11 @@ struct nvhost_cmdbuf {
        __u32 words;
 } __packed;
 
+struct nvhost_cmdbuf_ext {
+       __s32 pre_fence;
+       __u32 reserved;
+};
+
 struct nvhost_reloc {
        __u32 cmdbuf_mem;
        __u32 cmdbuf_offset;
@@ -267,6 +272,7 @@ struct nvhost32_submit_args {
        __u32 class_ids;
 
        __u32 pad[2];           /* future expansion */
+
        __u32 fences;
        __u32 fence;            /* Return value */
 } __packed;
@@ -280,8 +286,9 @@ struct nvhost_submit_args {
        __u32 timeout;
        __u32 syncpt_incrs;
        __u32 fence;            /* Return value */
+       __u64 cmdbuf_exts;
 
-       __u64 pad[4];           /* future expansion */
+       __u64 pad[3];           /* future expansion */
 
        __u64 cmdbufs;
        __u64 relocs;