]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
video: tegra: host: implement submit wait queue
authorKirill Artamonov <kartamonov@nvidia.com>
Fri, 10 May 2013 14:51:50 +0000 (17:51 +0300)
committerDan Willemsen <dwillemsen@nvidia.com>
Sat, 14 Sep 2013 20:25:44 +0000 (13:25 -0700)
Implement submit wait queue for gk20a host.
Add nvhost_module_idle to submit complete action.

bug 1275382

Signed-off-by: Kirill Artamonov <kartamonov@nvidia.com>
Change-Id: I1b4f738cbc1886a1d14465b49dbc31dd65c12b25
Reviewed-on: http://git-master/r/227495
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Ken Adams <kadams@nvidia.com>
Tested-by: Ken Adams <kadams@nvidia.com>
drivers/video/tegra/host/gk20a/channel_gk20a.c
drivers/video/tegra/host/gk20a/channel_gk20a.h
drivers/video/tegra/host/nvhost_intr.c
drivers/video/tegra/host/nvhost_intr.h
drivers/video/tegra/host/t124/t124.c

index 4964617dd7c6ffa8af8dc2faf9415ee67658fc58..6c185b72ff7028251dd2c8175ad74d8aa53835ea 100644 (file)
@@ -476,6 +476,7 @@ struct nvhost_hwctx *gk20a_open_channel(struct nvhost_channel *ch,
 
        init_waitqueue_head(&ch_gk20a->notifier_wq);
        init_waitqueue_head(&ch_gk20a->semaphore_wq);
+       init_waitqueue_head(&ch_gk20a->submit_wq);
 
        return ctx;
 }
@@ -1050,6 +1051,12 @@ int gk20a_channel_submit_wfi_fence(struct gk20a *g,
        return 0;
 }
 
+static u32 get_gp_free_count(struct channel_gk20a *c)
+{
+       update_gp_get(c->g, c);
+       return gp_free_count(c);
+}
+
 int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
                                struct nvhost_gpfifo *gpfifo,
                                u32 num_entries,
@@ -1060,14 +1067,15 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
        struct nvhost_device_data *pdata = nvhost_get_devdata(g->dev);
        struct device *d = dev_from_gk20a(g);
        struct nvhost_syncpt *sp = syncpt_from_gk20a(g);
-       u32 free_count;
-       u32 extra_count = 0;
        u32 i, incr_id = ~0, wait_id = ~0;
        u32 err = 0;
        int incr_cmd_size;
        bool wfi_cmd;
        struct priv_cmd_entry *wait_cmd = NULL;
        struct priv_cmd_entry *incr_cmd = NULL;
+       /* we might need two extra gpfifo entries - one for syncpoint
+        * wait and one for syncpoint increment */
+       const int extra_entries = 2;
 
        nvhost_dbg_info("channel %d", c->hw_chid);
 
@@ -1077,14 +1085,35 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
        nvhost_dbg_info("pre-submit put %d, get %d, size %d",
                c->gpfifo.put, c->gpfifo.get, c->gpfifo.entry_num);
 
-       free_count = gp_free_count(c);
-
        /* If the caller has requested a fence "get" then we need to be
         * sure the fence represents work completion.  In that case
         * issue a wait-for-idle before the syncpoint increment.
         */
        wfi_cmd = !!(flags & NVHOST_SUBMIT_GPFIFO_FLAGS_FENCE_GET);
 
+       /* Invalidate tlb if it's dirty...                                   */
+       /* TBD: this should be done in the cmd stream, not with PRIs.        */
+       /* We don't know what context is currently running...                */
+       /* Note also: there can be more than one context associated with the */
+       /* address space (vm).   */
+       if (c->vm->tlb_dirty) {
+               c->vm->tlb_inval(c->vm);
+               c->vm->tlb_dirty = false;
+       }
+
+       /* Make sure we have enough space for gpfifo entries. If not,
+        * wait for signals from completed submits */
+       if (gp_free_count(c) < num_entries + extra_entries) {
+               err = wait_event_interruptible(c->submit_wq,
+                       get_gp_free_count(c) >= num_entries + extra_entries);
+       }
+
+       if (err) {
+               nvhost_err(d, "not enough gpfifo space");
+               err = -EAGAIN;
+               goto clean_up;
+       }
+
        /* optionally insert syncpt wait in the beginning of gpfifo submission
           when user requested and the wait hasn't expired.
        */
@@ -1096,7 +1125,6 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
                        err = -EAGAIN;
                        goto clean_up;
                }
-               extra_count++;
        }
 
        /* always insert syncpt increment at end of gpfifo submission
@@ -1113,13 +1141,6 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
                err = -EAGAIN;
                goto clean_up;
        }
-       extra_count++;
-
-       if (num_entries + extra_count > free_count) {
-               nvhost_err(d, "not enough gpfifo space");
-               err = -EAGAIN;
-               goto clean_up;
-       }
 
        if (wait_cmd) {
                wait_id = fence->syncpt_id;
index 42b46f37a410acafebbe756e187250ac6a2e621d..5b63c96b362349072faba4a33c075b3044fc7235 100644 (file)
@@ -98,6 +98,7 @@ struct channel_gk20a {
 
        wait_queue_head_t notifier_wq;
        wait_queue_head_t semaphore_wq;
+       wait_queue_head_t submit_wq;
 
        bool cmds_pending;
        struct {
index acce7080e91360dc692d6ec527a71409ddc04722..2c32d13de49359761ee00d96c4e1389c6aaebe9b 100644 (file)
@@ -29,6 +29,7 @@
 #include "nvhost_channel.h"
 #include "nvhost_hwctx.h"
 #include "chip_support.h"
+#include "gk20a/channel_gk20a.h"
 
 /*** Wait list management ***/
 
@@ -153,6 +154,15 @@ static void action_submit_complete(struct nvhost_waitlist *waiter)
 
 }
 
+static void action_gpfifo_submit_complete(struct nvhost_waitlist *waiter)
+{
+       struct channel_gk20a *ch20a = waiter->data;
+       int nr_completed = waiter->count;
+       wake_up(&ch20a->submit_wq);
+       nvhost_module_idle_mult(ch20a->ch->dev, nr_completed);
+       /* TODO: add trace function */
+}
+
 static void action_ctxsave(struct nvhost_waitlist *waiter)
 {
        struct nvhost_hwctx *hwctx = waiter->data;
@@ -187,6 +197,7 @@ typedef void (*action_handler)(struct nvhost_waitlist *waiter);
 
 static action_handler action_handlers[NVHOST_INTR_ACTION_COUNT] = {
        action_submit_complete,
+       action_gpfifo_submit_complete,
        action_ctxsave,
        action_signal_sync_pt,
        action_wakeup,
index e609129e4daf8f8c72c6cf68eef41b51cdb3621f..1f2b08e20d0c12a73f4811be12578bcdf461e59d 100644 (file)
@@ -35,6 +35,12 @@ enum nvhost_intr_action {
         */
        NVHOST_INTR_ACTION_SUBMIT_COMPLETE = 0,
 
+       /**
+        * Wake up a interruptible task.
+        * 'data' points to a wait_queue_head_t
+        */
+       NVHOST_INTR_ACTION_GPFIFO_SUBMIT_COMPLETE,
+
        /**
         * Save a HW context.
         * 'data' points to a context
index 77b4a6f2200a97f8803653b3c1e08180bceb26c3..ecd390f772509f589ec2ce37efc48223ecd19b41 100644 (file)
@@ -404,7 +404,8 @@ static int t124_channel_submit_gpfifo(struct nvhost_hwctx *hwctx,
                                     struct nvhost_gpfifo *gpfifo, u32 num_entries,
                                     struct nvhost_fence *fence, u32 flags)
 {
-       struct nvhost_channel *ch = hwctx->channel;
+       struct channel_gk20a *ch = hwctx->priv;
+       struct nvhost_channel *nvhost_ch = hwctx->channel;
        void *completed_waiter = NULL;
        int err, ret;
 
@@ -414,18 +415,22 @@ static int t124_channel_submit_gpfifo(struct nvhost_hwctx *hwctx,
        if (!completed_waiter)
                return -ENOMEM;
 
-       nvhost_module_busy(ch->dev);
+       nvhost_module_busy(nvhost_ch->dev);
+
 
        ret = gk20a_submit_channel_gpfifo(hwctx->priv, gpfifo, num_entries,
                                        fence, flags);
        if (!ret) {
-               err = nvhost_intr_add_action(&nvhost_get_host(ch->dev)->intr,
+               err = nvhost_intr_add_action(
+                       &nvhost_get_host(nvhost_ch->dev)->intr,
                        fence->syncpt_id, fence->value,
-                       NVHOST_INTR_ACTION_SUBMIT_COMPLETE, ch,
+                       NVHOST_INTR_ACTION_GPFIFO_SUBMIT_COMPLETE,
+                       ch,
                        completed_waiter,
                        NULL);
                WARN(err, "Failed to set submit complete interrupt");
        } else {
+               pr_err("submit error %d\n", ret);
                kfree(completed_waiter);
        }
        return ret;