From 06ceff1240902c7f4cdb01dcbc9c988fc5fd9495 Mon Sep 17 00:00:00 2001 From: Vinod G Date: Mon, 18 Jun 2018 12:04:13 -0700 Subject: gpu: nvgpu: PG refcount check moved to a wrapper function. Moved PG refcount checking to a wrapper function, this function manages the refcount and decides whether to call dbg_set_powergate function. Instead of checking the dbg_s->is_pg_disabled variable, code is checking g->dbg_powergating_disabled_refcount variable to know if powergate is disabled or not. Updating hwpm ctxsw mode without disabling powergate will result in priv errors. Bug 200410871 Bug 2109765 Change-Id: I33c9022cb04cd39249c78e72584dfe6afb7212d0 Signed-off-by: Vinod G Reviewed-on: https://git-master.nvidia.com/r/1753550 Reviewed-by: svc-mobile-coverity Reviewed-by: Richard Zhao GVS: Gerrit_Virtual_Submit Reviewed-by: Terje Bergstrom Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c | 142 ++++++++++++++++++-------------- drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.h | 2 + drivers/gpu/nvgpu/os/linux/ioctl_dbg.c | 30 ++++--- 3 files changed, 97 insertions(+), 77 deletions(-) diff --git a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c index 97de7138..ddf2039b 100644 --- a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c @@ -169,6 +169,36 @@ int gk20a_dbg_gpu_clear_broadcast_stop_trigger(struct channel_gk20a *ch) return 0; } +u32 nvgpu_set_powergate_locked(struct dbg_session_gk20a *dbg_s, + bool mode) +{ + u32 err = 0U; + struct gk20a *g = dbg_s->g; + + if (dbg_s->is_pg_disabled != mode) { + if (mode == false) { + g->dbg_powergating_disabled_refcount--; + } + + /* + * Allow powergate disable or enable only if + * the global pg disabled refcount is zero + */ + if (g->dbg_powergating_disabled_refcount == 0) { + err = g->ops.dbg_session_ops.dbg_set_powergate(dbg_s, + mode); + } + + if (mode) { + g->dbg_powergating_disabled_refcount++; + } + + dbg_s->is_pg_disabled = mode; + } + + return err; +} + int dbg_set_powergate(struct dbg_session_gk20a *dbg_s, bool disable_powergate) { int err = 0; @@ -194,36 +224,28 @@ int dbg_set_powergate(struct dbg_session_gk20a *dbg_s, bool disable_powergate) * clocking state changes allowed from mainline code (but they * should be saved). */ - /* Allow powergate disable if the current dbg_session doesn't - * call a powergate disable ioctl and the global - * powergating_disabled_refcount is zero - */ - if ((dbg_s->is_pg_disabled == false) && - (g->dbg_powergating_disabled_refcount++ == 0)) { - - nvgpu_log(g, gpu_dbg_gpu_dbg | gpu_dbg_fn, - "module busy"); - err = gk20a_busy(g); - if (err) - return err; - - /*do elpg disable before clock gating */ - nvgpu_pmu_pg_global_enable(g, false); - - if (g->ops.clock_gating.slcg_gr_load_gating_prod) - g->ops.clock_gating.slcg_gr_load_gating_prod(g, - false); - if (g->ops.clock_gating.slcg_perf_load_gating_prod) - g->ops.clock_gating.slcg_perf_load_gating_prod(g, - false); - if (g->ops.clock_gating.slcg_ltc_load_gating_prod) - g->ops.clock_gating.slcg_ltc_load_gating_prod(g, - false); - - gr_gk20a_init_cg_mode(g, BLCG_MODE, BLCG_RUN); - gr_gk20a_init_cg_mode(g, ELCG_MODE, ELCG_RUN); - } + nvgpu_log(g, gpu_dbg_gpu_dbg | gpu_dbg_fn, + "module busy"); + err = gk20a_busy(g); + if (err) + return err; + + /*do elpg disable before clock gating */ + nvgpu_pmu_pg_global_enable(g, false); + + if (g->ops.clock_gating.slcg_gr_load_gating_prod) + g->ops.clock_gating.slcg_gr_load_gating_prod(g, + false); + if (g->ops.clock_gating.slcg_perf_load_gating_prod) + g->ops.clock_gating.slcg_perf_load_gating_prod(g, + false); + if (g->ops.clock_gating.slcg_ltc_load_gating_prod) + g->ops.clock_gating.slcg_ltc_load_gating_prod(g, + false); + + gr_gk20a_init_cg_mode(g, BLCG_MODE, BLCG_RUN); + gr_gk20a_init_cg_mode(g, ELCG_MODE, ELCG_RUN); dbg_s->is_pg_disabled = true; } else { @@ -231,42 +253,34 @@ int dbg_set_powergate(struct dbg_session_gk20a *dbg_s, bool disable_powergate) /* release pending exceptions to fault/be handled as usual */ /*TBD: ordering of these? */ - /* Re-enabling powergate as no other sessions want - * powergate disabled and the current dbg-sessions had - * requested the powergate disable through ioctl - */ - if (dbg_s->is_pg_disabled && - --g->dbg_powergating_disabled_refcount == 0) { - - if (g->elcg_enabled) - gr_gk20a_init_cg_mode(g, ELCG_MODE, ELCG_AUTO); - - if (g->blcg_enabled) - gr_gk20a_init_cg_mode(g, BLCG_MODE, BLCG_AUTO); - - if (g->slcg_enabled) { - if (g->ops.clock_gating. - slcg_ltc_load_gating_prod) - g->ops.clock_gating. - slcg_ltc_load_gating_prod(g, - g->slcg_enabled); - if (g->ops.clock_gating. - slcg_perf_load_gating_prod) - g->ops.clock_gating. - slcg_perf_load_gating_prod(g, - g->slcg_enabled); - if (g->ops.clock_gating. - slcg_gr_load_gating_prod) - g->ops.clock_gating. - slcg_gr_load_gating_prod(g, - g->slcg_enabled); - } - nvgpu_pmu_pg_global_enable(g, true); - - nvgpu_log(g, gpu_dbg_gpu_dbg | gpu_dbg_fn, - "module idle"); - gk20a_idle(g); + if (g->elcg_enabled) + gr_gk20a_init_cg_mode(g, ELCG_MODE, ELCG_AUTO); + + if (g->blcg_enabled) + gr_gk20a_init_cg_mode(g, BLCG_MODE, BLCG_AUTO); + + if (g->slcg_enabled) { + if (g->ops.clock_gating. + slcg_ltc_load_gating_prod) + g->ops.clock_gating. + slcg_ltc_load_gating_prod(g, + g->slcg_enabled); + if (g->ops.clock_gating. + slcg_perf_load_gating_prod) + g->ops.clock_gating. + slcg_perf_load_gating_prod(g, + g->slcg_enabled); + if (g->ops.clock_gating. + slcg_gr_load_gating_prod) + g->ops.clock_gating. + slcg_gr_load_gating_prod(g, + g->slcg_enabled); } + nvgpu_pmu_pg_global_enable(g, true); + + nvgpu_log(g, gpu_dbg_gpu_dbg | gpu_dbg_fn, + "module idle"); + gk20a_idle(g); dbg_s->is_pg_disabled = false; } diff --git a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.h b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.h index b714a648..d9d07844 100644 --- a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.h @@ -133,4 +133,6 @@ int gk20a_perfbuf_enable_locked(struct gk20a *g, u64 offset, u32 size); int gk20a_perfbuf_disable_locked(struct gk20a *g); void nvgpu_dbg_session_post_event(struct dbg_session_gk20a *dbg_s); +u32 nvgpu_set_powergate_locked(struct dbg_session_gk20a *dbg_s, + bool mode); #endif /* DBG_GPU_GK20A_H */ diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_dbg.c b/drivers/gpu/nvgpu/os/linux/ioctl_dbg.c index 31e7e2cb..76ff25c0 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_dbg.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_dbg.c @@ -181,7 +181,9 @@ int gk20a_dbg_gpu_dev_release(struct inode *inode, struct file *filp) * calling powergate/timeout enable ioctl */ nvgpu_mutex_acquire(&g->dbg_sessions_lock); - g->ops.dbg_session_ops.dbg_set_powergate(dbg_s, false); + if (dbg_s->is_pg_disabled) { + nvgpu_set_powergate_locked(dbg_s, false); + } nvgpu_dbg_timeout_enable(dbg_s, NVGPU_DBG_GPU_IOCTL_TIMEOUT_ENABLE); /* If this session owned the perf buffer, release it */ @@ -867,9 +869,10 @@ static int nvgpu_ioctl_channel_reg_ops(struct dbg_session_gk20a *dbg_s, /* In the virtual case, the server will handle * disabling/enabling powergating when processing reg ops */ - powergate_err = g->ops.dbg_session_ops.dbg_set_powergate(dbg_s, - true); - is_pg_disabled = true; + powergate_err = nvgpu_set_powergate_locked(dbg_s, true); + if (!powergate_err) { + is_pg_disabled = true; + } } if (!powergate_err) { @@ -938,9 +941,8 @@ static int nvgpu_ioctl_channel_reg_ops(struct dbg_session_gk20a *dbg_s, /* enable powergate, if previously disabled */ if (is_pg_disabled) { - powergate_err = - g->ops.dbg_session_ops.dbg_set_powergate(dbg_s, - false); + powergate_err = nvgpu_set_powergate_locked(dbg_s, + false); } } @@ -964,14 +966,16 @@ static int nvgpu_ioctl_powergate_gk20a(struct dbg_session_gk20a *dbg_s, g->name, args->mode); nvgpu_mutex_acquire(&g->dbg_sessions_lock); - if (args->mode == NVGPU_DBG_GPU_POWERGATE_MODE_DISABLE) { - err = g->ops.dbg_session_ops.dbg_set_powergate(dbg_s, true); - } else if (args->mode == NVGPU_DBG_GPU_POWERGATE_MODE_ENABLE) { - err = g->ops.dbg_session_ops.dbg_set_powergate(dbg_s, false); - } else { + if ((args->mode != NVGPU_DBG_GPU_POWERGATE_MODE_DISABLE) && + (args->mode != NVGPU_DBG_GPU_POWERGATE_MODE_ENABLE)) { nvgpu_err(g, "invalid powergate mode"); err = -EINVAL; + goto pg_err_end; } + + err = nvgpu_set_powergate_locked(dbg_s, + args->mode == NVGPU_DBG_GPU_POWERGATE_MODE_DISABLE); +pg_err_end: nvgpu_mutex_release(&g->dbg_sessions_lock); return err; } @@ -1053,7 +1057,7 @@ static int nvgpu_dbg_gpu_ioctl_hwpm_ctxsw_mode(struct dbg_session_gk20a *dbg_s, err = -EINVAL; goto clean_up; } - if (!dbg_s->is_pg_disabled) { + if (g->dbg_powergating_disabled_refcount == 0) { nvgpu_err(g, "powergate is not disabled"); err = -ENOSYS; goto clean_up; -- cgit v1.2.2