From eee2744d497213a503de927cbbfe179753f5e370 Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Wed, 3 Aug 2016 13:04:38 -0700 Subject: gpu: nvgpu: When powering down, abort if not idle When trying to power down GPU the engine might be still busy. In this case delay power down by returning -EBUSY from gk20a_pm_runtime_suspend(). Bug 200224907 Change-Id: Ibad74c090add24a185bc1a7a02df367af9b95ced Signed-off-by: Terje Bergstrom Reviewed-on: http://git-master/r/1213042 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 6 ------ drivers/gpu/nvgpu/gk20a/fifo_gk20a.c | 16 ++++++++++++++-- drivers/gpu/nvgpu/gk20a/fifo_gk20a.h | 1 + drivers/gpu/nvgpu/gk20a/gk20a.c | 10 +++++++++- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index b4c132ce..085caec5 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c @@ -2789,16 +2789,10 @@ int gk20a_channel_suspend(struct gk20a *g) struct fifo_gk20a *f = &g->fifo; u32 chid; bool channels_in_use = false; - int err; u32 active_runlist_ids = 0; gk20a_dbg_fn(""); - /* wait for engine idle */ - err = g->ops.fifo.wait_engine_idle(g); - if (err) - return err; - for (chid = 0; chid < f->num_channels; chid++) { struct channel_gk20a *ch = &f->channel[chid]; if (gk20a_channel_get(ch)) { diff --git a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c index ff052400..2e38c4b6 100644 --- a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c @@ -3016,6 +3016,19 @@ bool gk20a_fifo_mmu_fault_pending(struct gk20a *g) return false; } +bool gk20a_fifo_is_engine_busy(struct gk20a *g) +{ + int i; + + for (i = 0; i < fifo_engine_status__size_1_v(); i++) { + u32 status = gk20a_readl(g, fifo_engine_status_r(i)); + if (fifo_engine_status_engine_v(status) == + fifo_engine_status_engine_busy_v()) + return true; + } + return false; +} + int gk20a_fifo_wait_engine_idle(struct gk20a *g) { unsigned long end_jiffies = jiffies + @@ -3023,7 +3036,6 @@ int gk20a_fifo_wait_engine_idle(struct gk20a *g) unsigned long delay = GR_IDLE_CHECK_DEFAULT; int ret = -ETIMEDOUT; u32 i; - struct device *d = dev_from_gk20a(g); gk20a_dbg_fn(""); @@ -3041,7 +3053,7 @@ int gk20a_fifo_wait_engine_idle(struct gk20a *g) } while (time_before(jiffies, end_jiffies) || !tegra_platform_is_silicon()); if (ret) { - gk20a_err(d, "cannot idle engine %u\n", i); + gk20a_dbg_info("cannot idle engine %u", i); break; } } diff --git a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.h b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.h index 17c6dbf6..71a9d35d 100644 --- a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.h @@ -206,6 +206,7 @@ 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); +bool gk20a_fifo_is_engine_busy(struct gk20a *g); u32 gk20a_fifo_engine_interrupt_mask(struct gk20a *g); u32 gk20a_fifo_get_pbdma_signature(struct gk20a *g); u32 gk20a_fifo_get_failing_engine_data(struct gk20a *g, diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c index f6bb9445..10fa86a1 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a.c @@ -767,6 +767,10 @@ static int gk20a_pm_prepare_poweroff(struct device *dev) if (!g->power_on) goto done; + if (gk20a_fifo_is_engine_busy(g)) { + mutex_unlock(&g->poweroff_lock); + return -EBUSY; + } gk20a_scale_suspend(dev); /* cancel any pending cde work */ @@ -1353,6 +1357,7 @@ static int gk20a_pm_runtime_suspend(struct device *dev) fail_railgate: gk20a_pm_finalize_poweron(dev); fail: + pm_runtime_mark_last_busy(dev); return err; } @@ -1751,6 +1756,7 @@ int __gk20a_do_idle(struct device *dev, bool force_reset) msecs_to_jiffies(GK20A_WAIT_FOR_IDLE_MS); int ref_cnt; bool is_railgated; + int err = 0; /* acquire busy lock to block other busy() calls */ down_write(&g->busy_lock); @@ -1825,7 +1831,9 @@ int __gk20a_do_idle(struct device *dev, bool force_reset) */ /* Save the GPU state */ - gk20a_pm_prepare_poweroff(dev); + err = gk20a_pm_prepare_poweroff(dev); + if (err) + goto fail_drop_usage_count; /* railgate GPU */ platform->railgate(dev); -- cgit v1.2.2