diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index 33681c2af..b4d9c7852 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c @@ -1948,29 +1948,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; - } - - if (c->sync) - c->sync->wait_cpu(c->sync, - &c->last_submit.post_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) { diff --git a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c index 8cb1d0a58..fb15b3dab 100644 --- a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c @@ -633,6 +633,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; } diff --git a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c index 52c0627df..daf40d9ce 100644 --- a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c @@ -1955,6 +1955,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); diff --git a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.h b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.h index 6e6907c12..e738b1521 100644 --- a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.h @@ -169,4 +169,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__*/