From c81cc032c48a1b25e095b17b77399166c9091ff3 Mon Sep 17 00:00:00 2001 From: Debarshi Dutta Date: Tue, 30 Apr 2019 13:54:08 +0530 Subject: gpu: nvgpu: add cg and pg function Add new power/clock gating functions that can be called by other units. New clock_gating functions will reside in cg.c under common/power_features/cg unit. New power gating functions will reside in pg.c under common/power_features/pg unit. Use nvgpu_pg_elpg_disable and nvgpu_pg_elpg_enable to disable/enable elpg and also in gr_gk20a_elpg_protected macro to access gr registers. Add cg_pg_lock to make elpg_enabled, elcg_enabled, blcg_enabled and slcg_enabled thread safe. JIRA NVGPU-2014 Change-Id: I00d124c2ee16242c9a3ef82e7620fbb7f1297aff Signed-off-by: Seema Khowala Reviewed-on: https://git-master.nvidia.com/r/2025493 Signed-off-by: Debarshi Dutta (cherry-picked from c90585856567a547173a8b207365b3a4a3ccdd57 in dev-kernel) Reviewed-on: https://git-master.nvidia.com/r/2108406 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/common/mm/mm.c | 20 +- drivers/gpu/nvgpu/common/pmu/pmu.c | 14 +- drivers/gpu/nvgpu/common/power_features/cg/cg.c | 566 +++++++++++++++++++++ drivers/gpu/nvgpu/common/power_features/pg/pg.c | 106 ++++ .../nvgpu/common/power_features/power_features.c | 66 +++ .../gpu/nvgpu/common/priv_ring/priv_ring_gm20b.c | 6 +- 6 files changed, 749 insertions(+), 29 deletions(-) create mode 100644 drivers/gpu/nvgpu/common/power_features/cg/cg.c create mode 100644 drivers/gpu/nvgpu/common/power_features/pg/pg.c create mode 100644 drivers/gpu/nvgpu/common/power_features/power_features.c (limited to 'drivers/gpu/nvgpu/common') diff --git a/drivers/gpu/nvgpu/common/mm/mm.c b/drivers/gpu/nvgpu/common/mm/mm.c index c9aac4af..fc7a9ae4 100644 --- a/drivers/gpu/nvgpu/common/mm/mm.c +++ b/drivers/gpu/nvgpu/common/mm/mm.c @@ -30,6 +30,7 @@ #include #include #include +#include /* * Attempt to find a reserved memory area to determine PTE size for the passed @@ -349,22 +350,9 @@ static int nvgpu_init_mm_reset_enable_hw(struct gk20a *g) g->ops.mc.fb_reset(g); } - if (g->ops.clock_gating.slcg_fb_load_gating_prod) { - g->ops.clock_gating.slcg_fb_load_gating_prod(g, - 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.blcg_fb_load_gating_prod) { - g->ops.clock_gating.blcg_fb_load_gating_prod(g, - g->blcg_enabled); - } - if (g->ops.clock_gating.blcg_ltc_load_gating_prod) { - g->ops.clock_gating.blcg_ltc_load_gating_prod(g, - g->blcg_enabled); - } + nvgpu_cg_slcg_fb_ltc_load_enable(g); + + nvgpu_cg_blcg_fb_ltc_load_enable(g); if (g->ops.fb.init_fs_state) { g->ops.fb.init_fs_state(g); diff --git a/drivers/gpu/nvgpu/common/pmu/pmu.c b/drivers/gpu/nvgpu/common/pmu/pmu.c index f86dc2c2..b9cfd033 100644 --- a/drivers/gpu/nvgpu/common/pmu/pmu.c +++ b/drivers/gpu/nvgpu/common/pmu/pmu.c @@ -30,6 +30,8 @@ #include #include #include +#include + static int nvgpu_pg_init_task(void *arg); @@ -44,15 +46,9 @@ static int pmu_enable_hw(struct nvgpu_pmu *pmu, bool enable) /* bring PMU falcon/engine out of reset */ g->ops.pmu.reset_engine(g, true); - if (g->ops.clock_gating.slcg_pmu_load_gating_prod) { - g->ops.clock_gating.slcg_pmu_load_gating_prod(g, - g->slcg_enabled); - } + nvgpu_cg_slcg_pmu_load_enable(g); - if (g->ops.clock_gating.blcg_pmu_load_gating_prod) { - g->ops.clock_gating.blcg_pmu_load_gating_prod(g, - g->blcg_enabled); - } + nvgpu_cg_blcg_pmu_load_enable(g); if (nvgpu_flcn_mem_scrub_wait(pmu->flcn)) { /* keep PMU falcon/engine in reset @@ -446,7 +442,7 @@ static void pmu_setup_hw_enable_elpg(struct gk20a *g) g->ops.gr.pmu_save_zbc(g, 0xf); } - if (g->elpg_enabled) { + if (g->can_elpg && g->elpg_enabled) { /* Init reg with prod values*/ if (g->ops.pmu.pmu_setup_elpg) { g->ops.pmu.pmu_setup_elpg(g); diff --git a/drivers/gpu/nvgpu/common/power_features/cg/cg.c b/drivers/gpu/nvgpu/common/power_features/cg/cg.c new file mode 100644 index 00000000..66b95226 --- /dev/null +++ b/drivers/gpu/nvgpu/common/power_features/cg/cg.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +static void nvgpu_cg_set_mode(struct gk20a *g, int cgmode, int mode_config) +{ + u32 engine_idx; + u32 active_engine_id = 0; + struct fifo_engine_info_gk20a *engine_info = NULL; + struct fifo_gk20a *f = &g->fifo; + + nvgpu_log_fn(g, " "); + + for (engine_idx = 0; engine_idx < f->num_engines; ++engine_idx) { + active_engine_id = f->active_engines_list[engine_idx]; + engine_info = &f->engine_info[active_engine_id]; + + /* gr_engine supports both BLCG and ELCG */ + if ((cgmode == BLCG_MODE) && (engine_info->engine_enum == + ENGINE_GR_GK20A)) { + g->ops.therm.init_blcg_mode(g, (u32)mode_config, + active_engine_id); + break; + } else if (cgmode == ELCG_MODE) { + g->ops.therm.init_elcg_mode(g, (u32)mode_config, + active_engine_id); + } else { + nvgpu_err(g, "invalid cg mode %d, config %d for " + "act_eng_id %d", + cgmode, mode_config, active_engine_id); + } + } +} + +void nvgpu_cg_elcg_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_ELCG)) { + return; + } + + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (g->elcg_enabled) { + nvgpu_cg_set_mode(g, ELCG_MODE, ELCG_AUTO); + } + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_elcg_disable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_ELCG)) { + return; + } + + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (g->elcg_enabled) { + nvgpu_cg_set_mode(g, ELCG_MODE, ELCG_RUN); + } + nvgpu_mutex_release(&g->cg_pg_lock); + +} + +void nvgpu_cg_blcg_mode_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_BLCG)) { + return; + } + + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (g->blcg_enabled) { + nvgpu_cg_set_mode(g, BLCG_MODE, BLCG_AUTO); + } + nvgpu_mutex_release(&g->cg_pg_lock); + +} + +void nvgpu_cg_blcg_mode_disable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_BLCG)) { + return; + } + + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (g->blcg_enabled) { + nvgpu_cg_set_mode(g, BLCG_MODE, BLCG_RUN); + } + nvgpu_mutex_release(&g->cg_pg_lock); + + +} + +void nvgpu_cg_blcg_fb_ltc_load_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_BLCG)) { + return; + } + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (!g->blcg_enabled) { + goto done; + } + if (g->ops.clock_gating.blcg_fb_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_fb_load_gating_prod(g, true); + } + if (g->ops.clock_gating.blcg_ltc_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_ltc_load_gating_prod(g, true); + } +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_blcg_fifo_load_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_BLCG)) { + return; + } + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (!g->blcg_enabled) { + goto done; + } + if (g->ops.clock_gating.blcg_fifo_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_fifo_load_gating_prod(g, true); + } +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_blcg_pmu_load_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_BLCG)) { + return; + } + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (!g->blcg_enabled) { + goto done; + } + if (g->ops.clock_gating.blcg_pmu_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_pmu_load_gating_prod(g, true); + } +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_blcg_ce_load_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_BLCG)) { + return; + } + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (!g->blcg_enabled) { + goto done; + } + if (g->ops.clock_gating.blcg_ce_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_ce_load_gating_prod(g, true); + } +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_blcg_gr_load_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_BLCG)) { + return; + } + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (!g->blcg_enabled) { + goto done; + } + if (g->ops.clock_gating.blcg_gr_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_gr_load_gating_prod(g, true); + } +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_slcg_fb_ltc_load_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_SLCG)) { + return; + } + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (!g->slcg_enabled) { + goto done; + } + if (g->ops.clock_gating.slcg_fb_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_fb_load_gating_prod(g, true); + } + if (g->ops.clock_gating.slcg_ltc_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_ltc_load_gating_prod(g, true); + } +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_slcg_priring_load_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_SLCG)) { + return; + } + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (!g->slcg_enabled) { + goto done; + } + if (g->ops.clock_gating.slcg_priring_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_priring_load_gating_prod(g, true); + } +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_slcg_gr_perf_ltc_load_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_SLCG)) { + return; + } + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (!g->slcg_enabled) { + goto done; + } + if (g->ops.clock_gating.slcg_ltc_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_ltc_load_gating_prod(g, true); + } + if (g->ops.clock_gating.slcg_perf_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_perf_load_gating_prod(g, true); + } + if (g->ops.clock_gating.slcg_gr_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_gr_load_gating_prod(g, true); + } +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_slcg_gr_perf_ltc_load_disable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_SLCG)) { + return; + } + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (!g->slcg_enabled) { + goto done; + } + if (g->ops.clock_gating.slcg_gr_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_gr_load_gating_prod(g, false); + } + if (g->ops.clock_gating.slcg_perf_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_perf_load_gating_prod(g, false); + } + if (g->ops.clock_gating.slcg_ltc_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_ltc_load_gating_prod(g, false); + } +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_slcg_fifo_load_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_SLCG)) { + return; + } + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (!g->slcg_enabled) { + goto done; + } + if (g->ops.clock_gating.slcg_fifo_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_fifo_load_gating_prod(g, true); + } +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_slcg_pmu_load_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_SLCG)) { + return; + } + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (!g->slcg_enabled) { + goto done; + } + if (g->ops.clock_gating.slcg_pmu_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_pmu_load_gating_prod(g, true); + } +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_slcg_ce2_load_enable(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_SLCG)) { + return; + } + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (!g->slcg_enabled) { + goto done; + } + if (g->ops.clock_gating.slcg_ce2_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_ce2_load_gating_prod(g, true); + } +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_init_gr_load_gating_prod(struct gk20a *g) +{ + nvgpu_log_fn(g, " "); + + nvgpu_mutex_acquire(&g->cg_pg_lock); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_SLCG)) { + goto check_can_blcg; + } + if (!g->slcg_enabled) { + goto check_can_blcg; + } + + if (g->ops.clock_gating.slcg_bus_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_bus_load_gating_prod(g, true); + } + if (g->ops.clock_gating.slcg_chiplet_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_chiplet_load_gating_prod(g, true); + } + if (g->ops.clock_gating.slcg_gr_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_gr_load_gating_prod(g, true); + } + if (g->ops.clock_gating.slcg_ctxsw_firmware_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_ctxsw_firmware_load_gating_prod(g, + true); + } + if (g->ops.clock_gating.slcg_perf_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_perf_load_gating_prod(g, true); + } + if (g->ops.clock_gating.slcg_xbar_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_xbar_load_gating_prod(g, true); + } + +check_can_blcg: + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_BLCG)) { + goto pg_gr_load; + } + if (!g->blcg_enabled) { + goto pg_gr_load; + } + if (g->ops.clock_gating.blcg_bus_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_bus_load_gating_prod(g, true); + } + if (g->ops.clock_gating.blcg_gr_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_gr_load_gating_prod(g, true); + } + if (g->ops.clock_gating.blcg_ctxsw_firmware_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_ctxsw_firmware_load_gating_prod(g, + true); + } + if (g->ops.clock_gating.blcg_xbar_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_xbar_load_gating_prod(g, true); + } +pg_gr_load: + if (g->ops.clock_gating.pg_gr_load_gating_prod != NULL) { + g->ops.clock_gating.pg_gr_load_gating_prod(g, true); + } + + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_elcg_set_elcg_enabled(struct gk20a *g, bool enable) +{ + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_ELCG)) { + return; + } + + nvgpu_mutex_release(&g->cg_pg_lock); + if (enable) { + if (!g->elcg_enabled) { + g->elcg_enabled = true; + nvgpu_cg_set_mode(g, ELCG_MODE, ELCG_AUTO); + } + } else { + if (g->elcg_enabled) { + g->elcg_enabled = false; + nvgpu_cg_set_mode(g, ELCG_MODE, ELCG_RUN); + } + } + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_blcg_set_blcg_enabled(struct gk20a *g, bool enable) +{ + bool load = false; + + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_BLCG)) { + return; + } + + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (enable) { + if (!g->blcg_enabled) { + load = true; + g->blcg_enabled = true; + } + } else { + if (g->blcg_enabled) { + load = true; + g->blcg_enabled = false; + } + } + if (!load ) { + goto done; + } + + if (g->ops.clock_gating.blcg_bus_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_bus_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.blcg_ce_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_ce_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.blcg_ctxsw_firmware_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_ctxsw_firmware_load_gating_prod(g, + enable); + } + if (g->ops.clock_gating.blcg_fb_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_fb_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.blcg_fifo_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_fifo_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.blcg_gr_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_gr_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.blcg_ltc_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_ltc_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.blcg_pmu_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_pmu_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.blcg_xbar_load_gating_prod != NULL) { + g->ops.clock_gating.blcg_xbar_load_gating_prod(g, enable); + } + +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} + +void nvgpu_cg_slcg_set_slcg_enabled(struct gk20a *g, bool enable) +{ + bool load = false; + + nvgpu_log_fn(g, " "); + + if (!nvgpu_is_enabled(g, NVGPU_GPU_CAN_SLCG)) { + return; + } + + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (enable) { + if (!g->slcg_enabled) { + load = true; + g->slcg_enabled = true; + } + } else { + if (g->slcg_enabled) { + load = true; + g->slcg_enabled = false; + } + } + if (!load ) { + goto done; + } + + if (g->ops.clock_gating.slcg_bus_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_bus_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.slcg_ce2_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_ce2_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.slcg_chiplet_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_chiplet_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.slcg_ctxsw_firmware_load_gating_prod != + NULL) { + g->ops.clock_gating.slcg_ctxsw_firmware_load_gating_prod(g, + enable); + } + if (g->ops.clock_gating.slcg_fb_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_fb_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.slcg_fifo_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_fifo_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.slcg_gr_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_gr_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.slcg_ltc_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_ltc_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.slcg_perf_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_perf_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.slcg_priring_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_priring_load_gating_prod(g, + enable); + } + if (g->ops.clock_gating.slcg_pmu_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_pmu_load_gating_prod(g, enable); + } + if (g->ops.clock_gating.slcg_xbar_load_gating_prod != NULL) { + g->ops.clock_gating.slcg_xbar_load_gating_prod(g, enable); + } + +done: + nvgpu_mutex_release(&g->cg_pg_lock); +} diff --git a/drivers/gpu/nvgpu/common/power_features/pg/pg.c b/drivers/gpu/nvgpu/common/power_features/pg/pg.c new file mode 100644 index 00000000..fa31f4e3 --- /dev/null +++ b/drivers/gpu/nvgpu/common/power_features/pg/pg.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +bool nvgpu_pg_elpg_is_enabled(struct gk20a *g) +{ + bool elpg_enabled; + + nvgpu_log_fn(g, " "); + + nvgpu_mutex_acquire(&g->cg_pg_lock); + elpg_enabled = g->elpg_enabled; + nvgpu_mutex_release(&g->cg_pg_lock); + return elpg_enabled; +} + +int nvgpu_pg_elpg_enable(struct gk20a *g) +{ + int err = 0; + + nvgpu_log_fn(g, " "); + + if (!g->can_elpg) { + return 0; + } + + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (g->elpg_enabled) { + err = nvgpu_pmu_pg_global_enable(g, true); + } + nvgpu_mutex_release(&g->cg_pg_lock); + return err; +} + +int nvgpu_pg_elpg_disable(struct gk20a *g) +{ + int err = 0; + + nvgpu_log_fn(g, " "); + + if (!g->can_elpg) { + return 0; + } + + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (g->elpg_enabled) { + err = nvgpu_pmu_pg_global_enable(g, false); + } + nvgpu_mutex_release(&g->cg_pg_lock); + return err; +} + +int nvgpu_pg_elpg_set_elpg_enabled(struct gk20a *g, bool enable) +{ + int err = 0; + bool change_mode = false; + + nvgpu_log_fn(g, " "); + + if (!g->can_elpg) { + return 0; + } + + nvgpu_mutex_acquire(&g->cg_pg_lock); + if (enable) { + if (!g->elpg_enabled) { + change_mode = true; + g->elpg_enabled = true; + } + } else { + if (g->elpg_enabled) { + change_mode = true; + g->elpg_enabled = false; + } + } + if (!change_mode) { + goto done; + } + + err = nvgpu_pmu_pg_global_enable(g, enable); +done: + nvgpu_mutex_release(&g->cg_pg_lock); + return err; +} diff --git a/drivers/gpu/nvgpu/common/power_features/power_features.c b/drivers/gpu/nvgpu/common/power_features/power_features.c new file mode 100644 index 00000000..792fdc01 --- /dev/null +++ b/drivers/gpu/nvgpu/common/power_features/power_features.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +int nvgpu_cg_pg_disable(struct gk20a *g) +{ + int err = 0; + + nvgpu_log_fn(g, " "); + + /* disable elpg before clock gating */ + err = nvgpu_pg_elpg_disable(g); + if (err != 0) { + nvgpu_err(g, "failed to set disable elpg"); + } + nvgpu_cg_slcg_gr_perf_ltc_load_disable(g); + + nvgpu_cg_blcg_mode_disable(g); + + nvgpu_cg_elcg_disable(g); + + return err; +} + +int nvgpu_cg_pg_enable(struct gk20a *g) +{ + int err = 0; + + nvgpu_log_fn(g, " "); + + nvgpu_cg_elcg_enable(g); + + nvgpu_cg_blcg_mode_enable(g); + + nvgpu_cg_slcg_gr_perf_ltc_load_enable(g); + + err = nvgpu_pg_elpg_enable(g); + if (err != 0) { + nvgpu_err(g, "failed to set enable elpg"); + } + + return err; +} diff --git a/drivers/gpu/nvgpu/common/priv_ring/priv_ring_gm20b.c b/drivers/gpu/nvgpu/common/priv_ring/priv_ring_gm20b.c index e30d94f9..8c9b23fa 100644 --- a/drivers/gpu/nvgpu/common/priv_ring/priv_ring_gm20b.c +++ b/drivers/gpu/nvgpu/common/priv_ring/priv_ring_gm20b.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "priv_ring_gm20b.h" @@ -41,10 +42,7 @@ void gm20b_priv_ring_enable(struct gk20a *g) nvgpu_log(g, gpu_dbg_info, "enabling priv ring"); - if (g->ops.clock_gating.slcg_priring_load_gating_prod) { - g->ops.clock_gating.slcg_priring_load_gating_prod(g, - g->slcg_enabled); - } + nvgpu_cg_slcg_priring_load_enable(g); gk20a_writel(g,pri_ringmaster_command_r(), 0x4); -- cgit v1.2.2