]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
gpu: nvgpu: Wait for idle via FIFO registers
authorTerje Bergstrom <tbergstrom@nvidia.com>
Fri, 27 Jun 2014 10:45:02 +0000 (13:45 +0300)
committerEmad Mir <emir@nvidia.com>
Mon, 30 Jun 2014 18:17:03 +0000 (11:17 -0700)
Wait for engine idle via FIFO's engine status instead of submitting
WFI to channel. Submitting WFI and waiting is not robust, and wait
might invoke debug dump which cannot be done while powering down.

Bug 1499214

Change-Id: I4d52e8558e1a862ad4292036594d81ebfbd5f36b
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/432151
(cherry picked from commit 3719dff8287f5402eea81acb19ae21f028b1b968)
Reviewed-on: http://git-master/r/432154
Reviewed-by: Emad Mir <emir@nvidia.com>
Tested-by: Emad Mir <emir@nvidia.com>
drivers/gpu/nvgpu/gk20a/channel_gk20a.c
drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
drivers/gpu/nvgpu/gk20a/fifo_gk20a.c
drivers/gpu/nvgpu/gk20a/fifo_gk20a.h

index dbbd04909f3f35076f9ffe22e056fecb7b337419..99cd8727d74f0df46db5833758868ba39d04648b 100644 (file)
@@ -1842,27 +1842,14 @@ int gk20a_channel_suspend(struct gk20a *g)
        struct fifo_gk20a *f = &g->fifo;
        u32 chid;
        bool channels_in_use = false;
-       struct device *d = dev_from_gk20a(g);
        int err;
 
        gk20a_dbg_fn("");
 
-       /* idle the engine by submitting WFI on non-KEPLER_C channel */
-       for (chid = 0; chid < f->num_channels; chid++) {
-               struct channel_gk20a *c = &f->channel[chid];
-               if (c->in_use && c->obj_class != KEPLER_C && !c->has_timedout) {
-                       err = gk20a_channel_submit_wfi(c);
-                       if (err) {
-                               gk20a_err(d, "cannot idle channel %d\n",
-                                               chid);
-                               return err;
-                       }
-
-                       c->sync->wait_cpu(c->sync, &c->last_submit_fence,
-                                         500000);
-                       break;
-               }
-       }
+       /* wait for engine idle */
+       err = gk20a_fifo_wait_engine_idle(g);
+       if (err)
+               return err;
 
        for (chid = 0; chid < f->num_channels; chid++) {
                if (f->channel[chid].in_use) {
index a302749a61c739248ebb1fa9f8ddfe76f72b8c81..93d947ca83368b66b7654394158803d6a9984ea4 100644 (file)
@@ -615,6 +615,8 @@ static int dbg_set_powergate(struct dbg_session_gk20a *dbg_s,
                break;
        }
 
+       gk20a_dbg(gpu_dbg_fn|gpu_dbg_gpu_dbg, "%s powergate mode = %d done",
+                  dev_name(dbg_s->dev), powermode);
        return err;
 }
 
index f798f26996066573f1339367ea968f72159531e5..3fdf90c070b71c7c03cd4cd2a56e323a572f264a 100644 (file)
@@ -1878,6 +1878,41 @@ bool gk20a_fifo_mmu_fault_pending(struct gk20a *g)
                return false;
 }
 
+int gk20a_fifo_wait_engine_idle(struct gk20a *g)
+{
+       unsigned long end_jiffies = jiffies +
+               msecs_to_jiffies(gk20a_get_gr_idle_timeout(g));
+       unsigned long delay = GR_IDLE_CHECK_DEFAULT;
+       int ret = -ETIMEDOUT;
+       u32 i;
+       struct device *d = dev_from_gk20a(g);
+
+       gk20a_dbg_fn("");
+
+       for (i = 0; i < fifo_engine_status__size_1_v(); i++) {
+               do {
+                       u32 status = gk20a_readl(g, fifo_engine_status_r(i));
+                       if (!fifo_engine_status_engine_v(status)) {
+                               ret = 0;
+                               break;
+                       }
+
+                       usleep_range(delay, delay * 2);
+                       delay = min_t(unsigned long,
+                                       delay << 1, GR_IDLE_CHECK_MAX);
+               } while (time_before(jiffies, end_jiffies) ||
+                               !tegra_platform_is_silicon());
+               if (ret) {
+                       gk20a_err(d, "cannot idle engine %u\n", i);
+                       break;
+               }
+       }
+
+       gk20a_dbg_fn("done");
+
+       return ret;
+}
+
 void gk20a_init_fifo(struct gpu_ops *gops)
 {
        gk20a_init_channel(gops);
index 8a4e0a8f0c8b865bfd925cdff2221418041ced25..105a28e685c6ba79264185aa4882b2ac0cb5bde6 100644 (file)
@@ -164,4 +164,5 @@ void gk20a_init_fifo(struct gpu_ops *gops);
 
 void fifo_gk20a_finish_mmu_fault_handling(struct gk20a *g,
                unsigned long fault_id);
+int gk20a_fifo_wait_engine_idle(struct gk20a *g);
 #endif /*__GR_GK20A_H__*/