video: tegra: host: Throttle lower priority jobs
Terje Bergstrom [Mon, 28 May 2012 08:56:54 +0000 (11:56 +0300)]
Implement per channel counter for jobs in each priority level. If
there are jobs active with higher priority than the one being
submitted, throttle.

Bug 926690

Change-Id: I5fed341e3f248325873b31d1c53bf57bf0a78074
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/104939
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com>
Reviewed-by: Mayuresh Kulkarni <mkulkarni@nvidia.com>

drivers/video/tegra/host/bus_client.c
drivers/video/tegra/host/nvhost_cdma.c
drivers/video/tegra/host/nvhost_cdma.h
drivers/video/tegra/host/nvhost_channel.c
drivers/video/tegra/host/nvhost_intr.c
include/trace/events/nvhost.h

index 9b71542..87aa9c6 100644 (file)
@@ -141,12 +141,6 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
        priv->clientid = atomic_add_return(1,
                        &nvhost_get_host(ch->dev)->clientid);
        priv->timeout = MAX_STUCK_CHECK_COUNT * SYNCPT_CHECK_PERIOD;
-
-       priv->job = nvhost_job_alloc(ch, priv->hwctx, &priv->hdr,
-                       NULL, priv->priority, priv->clientid);
-       if (!priv->job)
-               goto fail;
-
        return 0;
 fail:
        nvhost_channelrelease(inode, filp);
index b1f1383..c87415b 100644 (file)
@@ -53,6 +53,18 @@ static void add_to_sync_queue(struct nvhost_cdma *cdma,
        job->num_slots = nr_slots;
        nvhost_job_get(job);
        list_add_tail(&job->list, &cdma->sync_queue);
+
+       switch (job->priority) {
+       case NVHOST_PRIORITY_HIGH:
+               cdma->high_prio_count++;
+               break;
+       case NVHOST_PRIORITY_MEDIUM:
+               cdma->med_prio_count++;
+               break;
+       case NVHOST_PRIORITY_LOW:
+               cdma->low_prio_count++;
+               break;
+       }
 }
 
 /**
@@ -200,6 +212,19 @@ static void update_cdma_locked(struct nvhost_cdma *cdma)
                }
 
                list_del(&job->list);
+
+               switch (job->priority) {
+               case NVHOST_PRIORITY_HIGH:
+                       cdma->high_prio_count--;
+                       break;
+               case NVHOST_PRIORITY_MEDIUM:
+                       cdma->med_prio_count--;
+                       break;
+               case NVHOST_PRIORITY_LOW:
+                       cdma->low_prio_count--;
+                       break;
+               }
+
                nvhost_job_put(job);
        }
 
@@ -466,6 +491,12 @@ void nvhost_cdma_end(struct nvhost_cdma *cdma,
        if (job->timeout && was_idle)
                cdma_start_timer_locked(cdma, job);
 
+       trace_nvhost_cdma_end(job->ch->dev->name,
+                       job->priority,
+                       job->ch->cdma.high_prio_count,
+                       job->ch->cdma.med_prio_count,
+                       job->ch->cdma.low_prio_count);
+
        mutex_unlock(&cdma->lock);
 }
 
@@ -490,6 +521,8 @@ int nvhost_cdma_flush(struct nvhost_cdma *cdma, int timeout)
        unsigned int space, err = 0;
        unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout);
 
+       trace_nvhost_cdma_flush(cdma_to_channel(cdma)->dev->name, timeout);
+
        /*
         * Wait for at most timeout ms. Recalculate timeout at each iteration
         * to better keep within given timeout.
index 98393f0..2056774 100644 (file)
@@ -99,6 +99,9 @@ struct nvhost_cdma {
        struct buffer_timeout timeout;  /* channel's timeout state/wq */
        bool running;
        bool torndown;
+       int high_prio_count;
+       int med_prio_count;
+       int low_prio_count;
 };
 
 #define cdma_to_channel(cdma) container_of(cdma, struct nvhost_channel, cdma)
index ef8886f..ad303cf 100644 (file)
@@ -51,10 +51,26 @@ int nvhost_channel_init(struct nvhost_channel *ch,
 
 int nvhost_channel_submit(struct nvhost_job *job)
 {
-       /* Low priority submits wait until sync queue is empty. Ignores result
-        * from nvhost_cdma_flush, as we submit either when push buffer is
-        * empty or when we reach the timeout. */
-       if (job->priority < NVHOST_PRIORITY_MEDIUM)
+       /*
+        * Check if queue has higher priority jobs running. If so, wait until
+        * queue is empty. Ignores result from nvhost_cdma_flush, as we submit
+        * either when push buffer is empty or when we reach the timeout.
+        */
+       int higher_count = 0;
+
+       switch (job->priority) {
+       case NVHOST_PRIORITY_HIGH:
+               higher_count = 0;
+               break;
+       case NVHOST_PRIORITY_MEDIUM:
+               higher_count = job->ch->cdma.high_prio_count;
+               break;
+       case NVHOST_PRIORITY_LOW:
+               higher_count = job->ch->cdma.high_prio_count
+                       + job->ch->cdma.med_prio_count;
+               break;
+       }
+       if (higher_count > 0)
                (void)nvhost_cdma_flush(&job->ch->cdma,
                                NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT);
 
index ba821f6..af2e3ad 100644 (file)
@@ -128,12 +128,16 @@ static void action_submit_complete(struct nvhost_waitlist *waiter)
        struct nvhost_channel *channel = waiter->data;
        int nr_completed = waiter->count;
 
+       nvhost_cdma_update(&channel->cdma);
+       nvhost_module_idle_mult(channel->dev, nr_completed);
+
        /*  Add nr_completed to trace */
        trace_nvhost_channel_submit_complete(channel->dev->name,
-                       nr_completed, waiter->thresh);
+                       nr_completed, waiter->thresh,
+                       channel->cdma.high_prio_count,
+                       channel->cdma.med_prio_count,
+                       channel->cdma.low_prio_count);
 
-       nvhost_cdma_update(&channel->cdma);
-       nvhost_module_idle_mult(channel->dev, nr_completed);
 }
 
 static void action_ctxsave(struct nvhost_waitlist *waiter)
index b4818f5..6506af4 100644 (file)
@@ -138,6 +138,52 @@ TRACE_EVENT(nvhost_channel_write_cmdbuf,
          __entry->words, __entry->offset)
 );
 
+TRACE_EVENT(nvhost_cdma_end,
+       TP_PROTO(const char *name, int prio,
+               int hi_count, int med_count, int low_count),
+
+       TP_ARGS(name, prio, hi_count, med_count, low_count),
+
+       TP_STRUCT__entry(
+               __field(const char *, name)
+               __field(int, prio)
+               __field(int, hi_count)
+               __field(int, med_count)
+               __field(int, low_count)
+       ),
+
+       TP_fast_assign(
+               __entry->name = name;
+               __entry->prio = prio;
+               __entry->hi_count = hi_count;
+               __entry->med_count = med_count;
+               __entry->low_count = low_count;
+       ),
+
+       TP_printk("name=%s, prio=%d, hi=%d, med=%d, low=%d",
+               __entry->name, __entry->prio,
+               __entry->hi_count, __entry->med_count, __entry->low_count)
+);
+
+TRACE_EVENT(nvhost_cdma_flush,
+       TP_PROTO(const char *name, int timeout),
+
+       TP_ARGS(name, timeout),
+
+       TP_STRUCT__entry(
+               __field(const char *, name)
+               __field(int, timeout)
+       ),
+
+       TP_fast_assign(
+               __entry->name = name;
+               __entry->timeout = timeout;
+       ),
+
+       TP_printk("name=%s, timeout=%d",
+               __entry->name, __entry->timeout)
+);
+
 TRACE_EVENT(nvhost_cdma_push,
        TP_PROTO(const char *name, u32 op1, u32 op2),
 
@@ -425,24 +471,32 @@ TRACE_EVENT(nvhost_channel_submitted,
 );
 
 TRACE_EVENT(nvhost_channel_submit_complete,
-       TP_PROTO(const char *name, int count, u32 thresh),
+       TP_PROTO(const char *name, int count, u32 thresh,
+               int hi_count, int med_count, int low_count),
 
-       TP_ARGS(name, count, thresh),
+       TP_ARGS(name, count, thresh, hi_count, med_count, low_count),
 
        TP_STRUCT__entry(
                __field(const char *, name)
                __field(int, count)
                __field(u32, thresh)
+               __field(int, hi_count)
+               __field(int, med_count)
+               __field(int, low_count)
        ),
 
        TP_fast_assign(
                __entry->name = name;
                __entry->count = count;
                __entry->thresh = thresh;
+               __entry->hi_count = hi_count;
+               __entry->med_count = med_count;
+               __entry->low_count = low_count;
        ),
 
-       TP_printk("name=%s, count=%d, thresh=%d",
-               __entry->name, __entry->count, __entry->thresh)
+       TP_printk("name=%s, count=%d, thresh=%d, hi=%d, med=%d, low=%d",
+               __entry->name, __entry->count, __entry->thresh,
+               __entry->hi_count, __entry->med_count, __entry->low_count)
 );
 
 TRACE_EVENT(nvhost_wait_cdma,