From fba516ffaebaaf61ea261fb569b4da51cdfb1779 Mon Sep 17 00:00:00 2001 From: Sagar Kamble Date: Fri, 29 Nov 2019 15:18:17 +0530 Subject: [PATCH] gpu: nvgpu: enable PMU ECC interrupt early PMU IRQs were not enabled assuming entire functionality for LS PMU. Debugging early init issues of PMU falcon ECC errors triggered during nvgpu power-on will be cumbersome if interrupts are not enabled early. FMEA analysis of the nvgpu init path also requires this interrupt be enabled earlier. Hence, Enable the PMU ECC IRQ early during nvgpu_finalize_poweron. pmu_enable_irq is updated to enable interrupts differently for safety and non-safety. PMU interrupts disabling is moved out of nvgpu_pmu_destroy to nvgpu_prepare_poweroff. Prepared new wrapper API nvgpu_pmu_enable_irq. PMU ECC init and isr mutex init is moved to the beginning of nvgpu_pmu_early_init as for safety, ls pmu code path is disabled. Fixed the pmu_early_init dependent and mc interrupt related unit tests. Update the doxygen for changed functions. JIRA NVGPU-4439 Change-Id: I1a1e792d2ad2cc7a926c8c1456d4d0d6d1f14d1a Signed-off-by: Sagar Kamble Reviewed-on: https://git-master.nvidia.com/r/2251732 Reviewed-by: mobile promotions Tested-by: mobile promotions --- arch/nvgpu-hal-new.yaml | 5 +- drivers/gpu/nvgpu/Makefile | 1 + drivers/gpu/nvgpu/Makefile.sources | 1 + drivers/gpu/nvgpu/common/falcon/falcon.c | 41 +++-- drivers/gpu/nvgpu/common/init/nvgpu_init.c | 2 + .../gpu/nvgpu/common/pmu/fw/fw_ns_bootstrap.c | 4 +- drivers/gpu/nvgpu/common/pmu/pmu.c | 49 ++++-- drivers/gpu/nvgpu/common/pmu/pmu_rtos_init.c | 19 +- drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.c | 17 -- drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.h | 4 +- .../gpu/nvgpu/hal/falcon/falcon_gk20a_fusa.c | 12 ++ drivers/gpu/nvgpu/hal/init/hal_gv11b.c | 12 +- drivers/gpu/nvgpu/hal/init/hal_tu104.c | 4 +- drivers/gpu/nvgpu/hal/mc/mc_gp10b_fusa.c | 2 - drivers/gpu/nvgpu/hal/pmu/pmu_gk20a.c | 49 +----- drivers/gpu/nvgpu/hal/pmu/pmu_gk20a.h | 8 +- drivers/gpu/nvgpu/hal/pmu/pmu_gk20a_fusa.c | 74 ++++++++ drivers/gpu/nvgpu/hal/pmu/pmu_gv11b.c | 119 ------------- drivers/gpu/nvgpu/hal/pmu/pmu_gv11b.h | 5 +- drivers/gpu/nvgpu/hal/pmu/pmu_gv11b_fusa.c | 166 ++++++++++++++++++ drivers/gpu/nvgpu/include/nvgpu/falcon.h | 34 +++- drivers/gpu/nvgpu/include/nvgpu/gops_falcon.h | 4 +- drivers/gpu/nvgpu/include/nvgpu/gops_mc.h | 3 + drivers/gpu/nvgpu/include/nvgpu/gops_pmu.h | 30 +++- drivers/gpu/nvgpu/include/nvgpu/pmu.h | 18 +- drivers/gpu/nvgpu/include/nvgpu/pmu/debug.h | 5 + userspace/units/acr/nvgpu-acr.c | 5 + userspace/units/mc/nvgpu-mc.c | 13 +- userspace/units/pmu/nvgpu-pmu.c | 5 + 29 files changed, 448 insertions(+), 263 deletions(-) create mode 100644 drivers/gpu/nvgpu/hal/pmu/pmu_gk20a_fusa.c diff --git a/arch/nvgpu-hal-new.yaml b/arch/nvgpu-hal-new.yaml index 7ccf1d097..d8aad8271 100644 --- a/arch/nvgpu-hal-new.yaml +++ b/arch/nvgpu-hal-new.yaml @@ -652,14 +652,15 @@ fb: pmu_fusa: safe: yes owner: Mahantesh K - sources: [ hal/pmu/pmu_gv11b_fusa.c, + sources: [ hal/pmu/pmu_gk20a_fusa.c, + hal/pmu/pmu_gk20a.h, + hal/pmu/pmu_gv11b_fusa.c, hal/pmu/pmu_gv11b.h ] pmu: safe: no owner: Mahantesh K sources: [ hal/pmu/pmu_gk20a.c, - hal/pmu/pmu_gk20a.h, hal/pmu/pmu_gm20b.c, hal/pmu/pmu_gm20b.h, hal/pmu/pmu_gp10b.c, diff --git a/drivers/gpu/nvgpu/Makefile b/drivers/gpu/nvgpu/Makefile index 377a99553..480062f41 100644 --- a/drivers/gpu/nvgpu/Makefile +++ b/drivers/gpu/nvgpu/Makefile @@ -647,6 +647,7 @@ nvgpu-y += \ hal/mc/mc_gp10b_fusa.o \ hal/mc/mc_gv11b_fusa.o \ hal/netlist/netlist_gv11b_fusa.o \ + hal/pmu/pmu_gk20a_fusa.o \ hal/pmu/pmu_gv11b_fusa.o \ hal/priv_ring/priv_ring_gm20b_fusa.o \ hal/priv_ring/priv_ring_gp10b_fusa.o \ diff --git a/drivers/gpu/nvgpu/Makefile.sources b/drivers/gpu/nvgpu/Makefile.sources index 46ebc23a4..59e41228b 100644 --- a/drivers/gpu/nvgpu/Makefile.sources +++ b/drivers/gpu/nvgpu/Makefile.sources @@ -231,6 +231,7 @@ srcs += hal/mm/mm_gv11b_fusa.c \ hal/mc/mc_gp10b_fusa.c \ hal/mc/mc_gv11b_fusa.c \ hal/netlist/netlist_gv11b_fusa.c \ + hal/pmu/pmu_gk20a_fusa.c \ hal/pmu/pmu_gv11b_fusa.c \ hal/priv_ring/priv_ring_gm20b_fusa.c \ hal/priv_ring/priv_ring_gp10b_fusa.c \ diff --git a/drivers/gpu/nvgpu/common/falcon/falcon.c b/drivers/gpu/nvgpu/common/falcon/falcon.c index 83dc3b2f0..13931f03d 100644 --- a/drivers/gpu/nvgpu/common/falcon/falcon.c +++ b/drivers/gpu/nvgpu/common/falcon/falcon.c @@ -538,6 +538,26 @@ void nvgpu_falcon_sw_free(struct gk20a *g, u32 flcn_id) nvgpu_mutex_destroy(&flcn->imem_lock); } +void nvgpu_falcon_set_irq(struct nvgpu_falcon *flcn, bool enable, + u32 intr_mask, u32 intr_dest) +{ + struct gk20a *g; + + if (!is_falcon_valid(flcn)) { + return; + } + + g = flcn->g; + + if (!flcn->is_interrupt_enabled) { + nvgpu_warn(g, "Interrupt not supported on flcn 0x%x ", + flcn->flcn_id); + return; + } + + g->ops.falcon.set_irq(flcn, enable, intr_mask, intr_dest); +} + #ifdef CONFIG_NVGPU_DGPU int nvgpu_falcon_copy_from_emem(struct nvgpu_falcon *flcn, u32 src, u8 *dst, u32 size, u8 port) @@ -641,27 +661,6 @@ int nvgpu_falcon_clear_halt_intr_status(struct nvgpu_falcon *flcn, return status; } -void nvgpu_falcon_set_irq(struct nvgpu_falcon *flcn, bool enable, - u32 intr_mask, u32 intr_dest) -{ - struct gk20a *g; - - if (!is_falcon_valid(flcn)) { - return; - } - - g = flcn->g; - - if (!flcn->is_interrupt_enabled) { - nvgpu_warn(g, "Interrupt not supported on flcn 0x%x ", - flcn->flcn_id); - /* Keep interrupt disabled */ - enable = false; - } - - g->ops.falcon.set_irq(flcn, enable, intr_mask, intr_dest); -} - int nvgpu_falcon_copy_from_dmem(struct nvgpu_falcon *flcn, u32 src, u8 *dst, u32 size, u8 port) { diff --git a/drivers/gpu/nvgpu/common/init/nvgpu_init.c b/drivers/gpu/nvgpu/common/init/nvgpu_init.c index 0ca3a6f3c..75ac901a8 100644 --- a/drivers/gpu/nvgpu/common/init/nvgpu_init.c +++ b/drivers/gpu/nvgpu/common/init/nvgpu_init.c @@ -272,6 +272,8 @@ int nvgpu_prepare_poweroff(struct gk20a *g) } #endif + nvgpu_pmu_enable_irq(g, false); + #ifdef CONFIG_NVGPU_DGPU if (nvgpu_is_enabled(g, NVGPU_SUPPORT_SEC2_RTOS)) { tmp_ret = g->ops.sec2.sec2_destroy(g); diff --git a/drivers/gpu/nvgpu/common/pmu/fw/fw_ns_bootstrap.c b/drivers/gpu/nvgpu/common/pmu/fw/fw_ns_bootstrap.c index 81da96a3b..fb5305172 100644 --- a/drivers/gpu/nvgpu/common/pmu/fw/fw_ns_bootstrap.c +++ b/drivers/gpu/nvgpu/common/pmu/fw/fw_ns_bootstrap.c @@ -83,15 +83,15 @@ int nvgpu_pmu_ns_fw_bootstrap(struct gk20a *g, struct nvgpu_pmu *pmu) } /* Do non-secure PMU boot */ - nvgpu_mutex_acquire(&pmu->isr_mutex); err = nvgpu_falcon_reset(pmu->flcn); if (err != 0) { nvgpu_err(g, "falcon reset failed"); /* free the ns ucode blob */ pmu_free_ns_ucode_blob(g); - nvgpu_mutex_release(&pmu->isr_mutex); return err; } + + nvgpu_mutex_acquire(&pmu->isr_mutex); pmu->isr_enabled = true; nvgpu_mutex_release(&pmu->isr_mutex); diff --git a/drivers/gpu/nvgpu/common/pmu/pmu.c b/drivers/gpu/nvgpu/common/pmu/pmu.c index b875726ed..2aa296d62 100644 --- a/drivers/gpu/nvgpu/common/pmu/pmu.c +++ b/drivers/gpu/nvgpu/common/pmu/pmu.c @@ -72,6 +72,16 @@ static int pmu_enable_hw(struct nvgpu_pmu *pmu, bool enable) return err; } +void nvgpu_pmu_enable_irq(struct gk20a *g, bool enable) +{ + if (g->pmu != NULL && g->ops.pmu.pmu_enable_irq != NULL) { + nvgpu_mutex_acquire(&g->pmu->isr_mutex); + g->ops.pmu.pmu_enable_irq(g->pmu, enable); + g->pmu->isr_enabled = enable; + nvgpu_mutex_release(&g->pmu->isr_mutex); + } +} + static int pmu_enable(struct nvgpu_pmu *pmu, bool enable) { struct gk20a *g = pmu->g; @@ -81,9 +91,7 @@ static int pmu_enable(struct nvgpu_pmu *pmu, bool enable) if (!enable) { if (!g->ops.pmu.is_engine_in_reset(g)) { -#ifdef CONFIG_NVGPU_LS_PMU - g->ops.pmu.pmu_enable_irq(pmu, false); -#endif + nvgpu_pmu_enable_irq(g, false); err = pmu_enable_hw(pmu, false); if (err != 0) { goto exit; @@ -99,6 +107,11 @@ static int pmu_enable(struct nvgpu_pmu *pmu, bool enable) if (err != 0) { goto exit; } + +#ifndef CONFIG_NVGPU_LS_PMU + /* Enable PMU ECC interrupts for safety. */ + nvgpu_pmu_enable_irq(g, true); +#endif } exit: @@ -137,6 +150,7 @@ void nvgpu_pmu_remove_support(struct gk20a *g, struct nvgpu_pmu *pmu) pmu->remove_support(g->pmu); } #endif + nvgpu_mutex_destroy(&pmu->isr_mutex); nvgpu_kfree(g, g->pmu); g->pmu = NULL; } @@ -166,6 +180,17 @@ int nvgpu_pmu_early_init(struct gk20a *g) pmu->g = g; pmu->flcn = &g->pmu_flcn; + if (g->ops.pmu.ecc_init != NULL && !g->ecc.initialized) { + err = g->ops.pmu.ecc_init(g); + if (err != 0) { + nvgpu_kfree(g, pmu); + g->pmu = NULL; + goto exit; + } + } + + nvgpu_mutex_init(&pmu->isr_mutex); + if (!g->support_ls_pmu) { goto exit; } @@ -181,17 +206,17 @@ int nvgpu_pmu_early_init(struct gk20a *g) goto exit; } - if (g->ops.pmu.ecc_init != NULL && !g->ecc.initialized) { - err = g->ops.pmu.ecc_init(g); - if (err != 0) { - nvgpu_kfree(g, pmu); - g->pmu = NULL; - goto exit; - } - } - #ifdef CONFIG_NVGPU_LS_PMU err = nvgpu_pmu_rtos_early_init(g, pmu); + if (err != 0) { + nvgpu_mutex_destroy(&pmu->isr_mutex); + if (g->ops.pmu.ecc_free != NULL) { + g->ops.pmu.ecc_free(g); + } + nvgpu_kfree(g, pmu); + g->pmu = NULL; + goto exit; + } #endif exit: diff --git a/drivers/gpu/nvgpu/common/pmu/pmu_rtos_init.c b/drivers/gpu/nvgpu/common/pmu/pmu_rtos_init.c index e7dde78d1..763d20068 100644 --- a/drivers/gpu/nvgpu/common/pmu/pmu_rtos_init.c +++ b/drivers/gpu/nvgpu/common/pmu/pmu_rtos_init.c @@ -88,19 +88,10 @@ int nvgpu_pmu_destroy(struct gk20a *g, struct nvgpu_pmu *pmu) { nvgpu_log_fn(g, " "); - if (!g->support_ls_pmu) { - return 0; - } - if (g->can_elpg) { nvgpu_pmu_pg_destroy(g, pmu, pmu->pg); } - nvgpu_mutex_acquire(&pmu->isr_mutex); - g->ops.pmu.pmu_enable_irq(pmu, false); - pmu->isr_enabled = false; - nvgpu_mutex_release(&pmu->isr_mutex); - nvgpu_pmu_queues_free(g, &pmu->queues); nvgpu_pmu_fw_state_change(g, pmu, PMU_FW_STATE_OFF, false); @@ -158,7 +149,6 @@ static void remove_pmu_support(struct nvgpu_pmu *pmu) nvgpu_pmu_mutexe_deinit(g, pmu, pmu->mutexes); nvgpu_pmu_fw_deinit(g, pmu, pmu->fw); nvgpu_pmu_deinitialize_perfmon(g, pmu); - nvgpu_mutex_destroy(&pmu->isr_mutex); } static int pmu_sw_setup(struct gk20a *g, struct nvgpu_pmu *pmu ) @@ -258,12 +248,7 @@ int nvgpu_pmu_rtos_init(struct gk20a *g) goto exit; } - if (g->ops.pmu.pmu_enable_irq != NULL) { - nvgpu_mutex_acquire(&g->pmu->isr_mutex); - g->ops.pmu.pmu_enable_irq(g->pmu, true); - g->pmu->isr_enabled = true; - nvgpu_mutex_release(&g->pmu->isr_mutex); - } + nvgpu_pmu_enable_irq(g, true); /*Once in LS mode, cpuctl_alias is only accessible*/ if (g->ops.pmu.secured_pmu_start != NULL) { @@ -289,8 +274,6 @@ int nvgpu_pmu_rtos_early_init(struct gk20a *g, struct nvgpu_pmu *pmu) nvgpu_log_fn(g, " "); - nvgpu_mutex_init(&pmu->isr_mutex); - /* Allocate memory for pmu_perfmon */ err = nvgpu_pmu_initialize_perfmon(g, pmu, &pmu->pmu_perfmon); if (err != 0) { diff --git a/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.c b/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.c index e49a23a8f..39858a060 100644 --- a/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.c +++ b/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.c @@ -49,23 +49,6 @@ bool gk20a_falcon_clear_halt_interrupt_status(struct nvgpu_falcon *flcn) return status; } -void gk20a_falcon_set_irq(struct nvgpu_falcon *flcn, bool enable, - u32 intr_mask, u32 intr_dest) -{ - struct gk20a *g = flcn->g; - u32 base_addr = flcn->flcn_base; - - if (enable) { - gk20a_writel(g, base_addr + falcon_falcon_irqmset_r(), - intr_mask); - gk20a_writel(g, base_addr + falcon_falcon_irqdest_r(), - intr_dest); - } else { - gk20a_writel(g, base_addr + falcon_falcon_irqmclr_r(), - 0xffffffffU); - } -} - int gk20a_falcon_copy_from_dmem(struct nvgpu_falcon *flcn, u32 src, u8 *dst, u32 size, u8 port) { diff --git a/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.h b/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.h index f7c7848b1..493a370b9 100644 --- a/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.h +++ b/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.h @@ -79,6 +79,8 @@ u32 gk20a_falcon_mailbox_read(struct nvgpu_falcon *flcn, u32 mailbox_index); void gk20a_falcon_mailbox_write(struct nvgpu_falcon *flcn, u32 mailbox_index, u32 data); +void gk20a_falcon_set_irq(struct nvgpu_falcon *flcn, bool enable, + u32 intr_mask, u32 intr_dest); #ifdef CONFIG_NVGPU_FALCON_DEBUG void gk20a_falcon_dump_stats(struct nvgpu_falcon *flcn); @@ -86,8 +88,6 @@ void gk20a_falcon_dump_stats(struct nvgpu_falcon *flcn); #ifdef CONFIG_NVGPU_FALCON_NON_FUSA bool gk20a_falcon_clear_halt_interrupt_status(struct nvgpu_falcon *flcn); -void gk20a_falcon_set_irq(struct nvgpu_falcon *flcn, bool enable, - u32 intr_mask, u32 intr_dest); int gk20a_falcon_copy_from_dmem(struct nvgpu_falcon *flcn, u32 src, u8 *dst, u32 size, u8 port); int gk20a_falcon_copy_from_imem(struct nvgpu_falcon *flcn, u32 src, diff --git a/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a_fusa.c b/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a_fusa.c index ac99e912f..1712ce43d 100644 --- a/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a_fusa.c +++ b/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a_fusa.c @@ -361,6 +361,18 @@ void gk20a_falcon_mailbox_write(struct nvgpu_falcon *flcn, falcon_falcon_mailbox0_r(), data); } +void gk20a_falcon_set_irq(struct nvgpu_falcon *flcn, bool enable, + u32 intr_mask, u32 intr_dest) +{ + if (enable) { + gk20a_falcon_writel(flcn, falcon_falcon_irqmset_r(), intr_mask); + gk20a_falcon_writel(flcn, falcon_falcon_irqdest_r(), intr_dest); + } else { + gk20a_falcon_writel(flcn, falcon_falcon_irqmclr_r(), + 0xffffffffU); + } +} + #ifdef CONFIG_NVGPU_FALCON_DEBUG static void gk20a_falcon_dump_imblk(struct nvgpu_falcon *flcn) { diff --git a/drivers/gpu/nvgpu/hal/init/hal_gv11b.c b/drivers/gpu/nvgpu/hal/init/hal_gv11b.c index e4b6a2619..a6472b15d 100644 --- a/drivers/gpu/nvgpu/hal/init/hal_gv11b.c +++ b/drivers/gpu/nvgpu/hal/init/hal_gv11b.c @@ -140,8 +140,8 @@ #include "hal/gr/gr/gr_gp10b.h" #include "hal/gr/gr/gr_gv100.h" #include "hal/gr/gr/gr_gv11b.h" -#ifdef CONFIG_NVGPU_LS_PMU #include "hal/pmu/pmu_gk20a.h" +#ifdef CONFIG_NVGPU_LS_PMU #include "hal/pmu/pmu_gm20b.h" #endif #include "hal/pmu/pmu_gv11b.h" @@ -1187,6 +1187,10 @@ static const struct gpu_ops gv11b_ops = { gv11b_clear_pmu_bar0_host_err_status, .bar0_error_status = gv11b_pmu_bar0_error_status, .validate_mem_integrity = gv11b_pmu_validate_mem_integrity, + .pmu_enable_irq = gv11b_pmu_enable_irq, + .get_irqdest = gv11b_pmu_get_irqdest, + .pmu_isr = gk20a_pmu_isr, + .handle_ext_irq = gv11b_pmu_handle_ext_irq, #ifdef CONFIG_NVGPU_LS_PMU /* Init */ .pmu_rtos_init = nvgpu_pmu_rtos_init, @@ -1194,11 +1198,7 @@ static const struct gpu_ops gv11b_ops = { .pmu_pstate_pmu_setup = nvgpu_pmu_pstate_pmu_setup, .pmu_destroy = nvgpu_pmu_destroy, /* ISR */ - .pmu_enable_irq = gk20a_pmu_enable_irq, - .get_irqdest = gv11b_pmu_get_irqdest, - .handle_ext_irq = gv11b_pmu_handle_ext_irq, .pmu_is_interrupted = gk20a_pmu_is_interrupted, - .pmu_isr = gk20a_pmu_isr, /* queue */ .pmu_get_queue_head = gv11b_pmu_queue_head_r, .pmu_get_queue_head_size = gv11b_pmu_queue_head__size_1_v, @@ -1371,13 +1371,13 @@ static const struct gpu_ops gv11b_ops = { .bootstrap = gk20a_falcon_bootstrap, .mailbox_read = gk20a_falcon_mailbox_read, .mailbox_write = gk20a_falcon_mailbox_write, + .set_irq = gk20a_falcon_set_irq, #ifdef CONFIG_NVGPU_FALCON_DEBUG .dump_falcon_stats = gk20a_falcon_dump_stats, #endif #ifdef CONFIG_NVGPU_FALCON_NON_FUSA .clear_halt_interrupt_status = gk20a_falcon_clear_halt_interrupt_status, - .set_irq = gk20a_falcon_set_irq, .copy_from_dmem = gk20a_falcon_copy_from_dmem, .copy_from_imem = gk20a_falcon_copy_from_imem, .get_falcon_ctls = gk20a_falcon_get_ctls, diff --git a/drivers/gpu/nvgpu/hal/init/hal_tu104.c b/drivers/gpu/nvgpu/hal/init/hal_tu104.c index a66d66f9e..6bc4168ac 100644 --- a/drivers/gpu/nvgpu/hal/init/hal_tu104.c +++ b/drivers/gpu/nvgpu/hal/init/hal_tu104.c @@ -1216,7 +1216,7 @@ static const struct gpu_ops tu104_ops = { .pmu_clear_idle_intr_status = NULL, .pmu_dump_elpg_stats = gk20a_pmu_dump_elpg_stats, .pmu_dump_falcon_stats = gk20a_pmu_dump_falcon_stats, - .pmu_enable_irq = gk20a_pmu_enable_irq, + .pmu_enable_irq = gv11b_pmu_enable_irq, .is_pmu_supported = tu104_is_pmu_supported, .pmu_mutex_owner = gk20a_pmu_mutex_owner, .pmu_mutex_acquire = gk20a_pmu_mutex_acquire, @@ -1413,13 +1413,13 @@ static const struct gpu_ops tu104_ops = { .bootstrap = gk20a_falcon_bootstrap, .mailbox_read = gk20a_falcon_mailbox_read, .mailbox_write = gk20a_falcon_mailbox_write, + .set_irq = gk20a_falcon_set_irq, #ifdef CONFIG_NVGPU_FALCON_DEBUG .dump_falcon_stats = gk20a_falcon_dump_stats, #endif #ifdef CONFIG_NVGPU_FALCON_NON_FUSA .clear_halt_interrupt_status = gk20a_falcon_clear_halt_interrupt_status, - .set_irq = gk20a_falcon_set_irq, .copy_from_dmem = gk20a_falcon_copy_from_dmem, .copy_from_imem = gk20a_falcon_copy_from_imem, .get_falcon_ctls = gk20a_falcon_get_ctls, diff --git a/drivers/gpu/nvgpu/hal/mc/mc_gp10b_fusa.c b/drivers/gpu/nvgpu/hal/mc/mc_gp10b_fusa.c index 47880839b..70bb6eb61 100644 --- a/drivers/gpu/nvgpu/hal/mc/mc_gp10b_fusa.c +++ b/drivers/gpu/nvgpu/hal/mc/mc_gp10b_fusa.c @@ -113,11 +113,9 @@ static void mc_gp10b_isr_stall_secondary_0(struct gk20a *g, u32 mc_intr_0) if ((mc_intr_0 & mc_intr_pfifo_pending_f()) != 0U) { g->ops.fifo.intr_0_isr(g); } -#ifdef CONFIG_NVGPU_LS_PMU if ((mc_intr_0 & mc_intr_pmu_pending_f()) != 0U) { g->ops.pmu.pmu_isr(g); } -#endif if ((mc_intr_0 & mc_intr_priv_ring_pending_f()) != 0U) { g->ops.priv_ring.isr(g); } diff --git a/drivers/gpu/nvgpu/hal/pmu/pmu_gk20a.c b/drivers/gpu/nvgpu/hal/pmu/pmu_gk20a.c index 51da0b8c5..8471fa9d1 100644 --- a/drivers/gpu/nvgpu/hal/pmu/pmu_gk20a.c +++ b/drivers/gpu/nvgpu/hal/pmu/pmu_gk20a.c @@ -486,7 +486,7 @@ bool gk20a_pmu_is_interrupted(struct nvgpu_pmu *pmu) return false; } -static void gk20a_pmu_handle_interrupts(struct gk20a *g, u32 intr) +void gk20a_pmu_handle_interrupts(struct gk20a *g, u32 intr) { struct nvgpu_pmu *pmu = g->pmu; bool recheck = false; @@ -495,7 +495,7 @@ static void gk20a_pmu_handle_interrupts(struct gk20a *g, u32 intr) if ((intr & pwr_falcon_irqstat_halt_true_f()) != 0U) { nvgpu_err(g, "pmu halt intr not implemented"); nvgpu_pmu_dump_falcon_stats(pmu); - if (gk20a_readl(g, pwr_pmu_mailbox_r + if (nvgpu_readl(g, pwr_pmu_mailbox_r (PMU_MODE_MISMATCH_STATUS_MAILBOX_R)) == PMU_MODE_MISMATCH_STATUS_VAL) { if (g->ops.pmu.dump_secure_fuses != NULL) { @@ -508,15 +508,11 @@ static void gk20a_pmu_handle_interrupts(struct gk20a *g, u32 intr) "pmu exterr intr not implemented. Clearing interrupt."); nvgpu_pmu_dump_falcon_stats(pmu); - gk20a_writel(g, pwr_falcon_exterrstat_r(), - gk20a_readl(g, pwr_falcon_exterrstat_r()) & + nvgpu_writel(g, pwr_falcon_exterrstat_r(), + nvgpu_readl(g, pwr_falcon_exterrstat_r()) & ~pwr_falcon_exterrstat_valid_m()); } - if (g->ops.pmu.handle_ext_irq != NULL) { - g->ops.pmu.handle_ext_irq(g, intr); - } - if ((intr & pwr_falcon_irqstat_swgen0_true_f()) != 0U) { err = nvgpu_pmu_process_message(pmu); if (err != 0) { @@ -526,50 +522,15 @@ static void gk20a_pmu_handle_interrupts(struct gk20a *g, u32 intr) recheck = true; } - gk20a_writel(g, pwr_falcon_irqsclr_r(), intr); - if (recheck) { if (!nvgpu_pmu_queue_is_empty(&pmu->queues, PMU_MESSAGE_QUEUE)) { - gk20a_writel(g, pwr_falcon_irqsset_r(), + nvgpu_writel(g, pwr_falcon_irqsset_r(), pwr_falcon_irqsset_swgen0_set_f()); } } } -void gk20a_pmu_isr(struct gk20a *g) -{ - struct nvgpu_pmu *pmu = g->pmu; - u32 intr, mask; - - nvgpu_log_fn(g, " "); - - nvgpu_mutex_acquire(&pmu->isr_mutex); - if (!pmu->isr_enabled) { - nvgpu_mutex_release(&pmu->isr_mutex); - return; - } - - mask = gk20a_readl(g, pwr_falcon_irqmask_r()) & - gk20a_readl(g, pwr_falcon_irqdest_r()); - - intr = gk20a_readl(g, pwr_falcon_irqstat_r()); - - nvgpu_pmu_dbg(g, "received falcon interrupt: 0x%08x", intr); - - intr = gk20a_readl(g, pwr_falcon_irqstat_r()) & mask; - if ((intr == 0U) || (nvgpu_pmu_get_fw_state(g, pmu) - == PMU_FW_STATE_OFF)) { - gk20a_writel(g, pwr_falcon_irqsclr_r(), intr); - nvgpu_mutex_release(&pmu->isr_mutex); - return; - } - - gk20a_pmu_handle_interrupts(g, intr); - - nvgpu_mutex_release(&pmu->isr_mutex); -} - static u32 pmu_bar0_host_tout_etype(u32 val) { return (val != 0U) ? PMU_BAR0_HOST_WRITE_TOUT : PMU_BAR0_HOST_READ_TOUT; diff --git a/drivers/gpu/nvgpu/hal/pmu/pmu_gk20a.h b/drivers/gpu/nvgpu/hal/pmu/pmu_gk20a.h index 0b387315b..01cc1b2b7 100644 --- a/drivers/gpu/nvgpu/hal/pmu/pmu_gk20a.h +++ b/drivers/gpu/nvgpu/hal/pmu/pmu_gk20a.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2019, NVIDIA CORPORATION. All rights reserved + * Copyright (c) 2011-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"), @@ -32,6 +32,9 @@ struct pmu_mutexes; #define PMU_MODE_MISMATCH_STATUS_MAILBOX_R 6U #define PMU_MODE_MISMATCH_STATUS_VAL 0xDEADDEADU +void gk20a_pmu_isr(struct gk20a *g); + +#ifdef CONFIG_NVGPU_LS_PMU void gk20a_pmu_dump_falcon_stats(struct nvgpu_pmu *pmu); void gk20a_pmu_init_perfmon_counter(struct gk20a *g); void gk20a_pmu_pg_idle_counter_config(struct gk20a *g, u32 pg_engine_id); @@ -53,8 +56,8 @@ int gk20a_pmu_queue_tail(struct gk20a *g, u32 queue_id, u32 queue_index, void gk20a_pmu_msgq_tail(struct nvgpu_pmu *pmu, u32 *tail, bool set); u32 gk20a_pmu_get_irqdest(struct gk20a *g); void gk20a_pmu_enable_irq(struct nvgpu_pmu *pmu, bool enable); +void gk20a_pmu_handle_interrupts(struct gk20a *g, u32 intr); bool gk20a_pmu_is_interrupted(struct nvgpu_pmu *pmu); -void gk20a_pmu_isr(struct gk20a *g); int gk20a_pmu_bar0_error_status(struct gk20a *g, u32 *bar0_status, u32 *etype); int gk20a_pmu_ns_bootstrap(struct gk20a *g, struct nvgpu_pmu *pmu, @@ -64,5 +67,6 @@ void gk20a_pmu_engine_reset(struct gk20a *g, bool do_reset); void gk20a_write_dmatrfbase(struct gk20a *g, u32 addr); u32 gk20a_pmu_falcon_base_addr(void); bool gk20a_is_pmu_supported(struct gk20a *g); +#endif #endif /* PMU_GK20A_H */ diff --git a/drivers/gpu/nvgpu/hal/pmu/pmu_gk20a_fusa.c b/drivers/gpu/nvgpu/hal/pmu/pmu_gk20a_fusa.c new file mode 100644 index 000000000..80da5b835 --- /dev/null +++ b/drivers/gpu/nvgpu/hal/pmu/pmu_gk20a_fusa.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2011-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 + +#include "pmu_gk20a.h" + +void gk20a_pmu_isr(struct gk20a *g) +{ + struct nvgpu_pmu *pmu = g->pmu; + u32 intr, mask; + + nvgpu_log_fn(g, " "); + + nvgpu_mutex_acquire(&pmu->isr_mutex); + if (!pmu->isr_enabled) { + nvgpu_mutex_release(&pmu->isr_mutex); + return; + } + + mask = nvgpu_readl(g, pwr_falcon_irqmask_r()); + mask &= nvgpu_readl(g, pwr_falcon_irqdest_r()); + + intr = nvgpu_readl(g, pwr_falcon_irqstat_r()); + + nvgpu_pmu_dbg(g, "received falcon interrupt: 0x%08x", intr); + + intr = nvgpu_readl(g, pwr_falcon_irqstat_r()) & mask; + + if (intr == 0U) { + nvgpu_mutex_release(&pmu->isr_mutex); + return; + } + + if (g->ops.pmu.handle_ext_irq != NULL) { + g->ops.pmu.handle_ext_irq(g, intr); + } + + nvgpu_writel(g, pwr_falcon_irqsclr_r(), intr); + +#ifdef CONFIG_NVGPU_LS_PMU + if (nvgpu_pmu_get_fw_state(g, pmu) == PMU_FW_STATE_OFF) { + nvgpu_mutex_release(&pmu->isr_mutex); + return; + } + + gk20a_pmu_handle_interrupts(g, intr); +#endif + + nvgpu_mutex_release(&pmu->isr_mutex); +} diff --git a/drivers/gpu/nvgpu/hal/pmu/pmu_gv11b.c b/drivers/gpu/nvgpu/hal/pmu/pmu_gv11b.c index 5060a9a64..de367eec4 100644 --- a/drivers/gpu/nvgpu/hal/pmu/pmu_gv11b.c +++ b/drivers/gpu/nvgpu/hal/pmu/pmu_gv11b.c @@ -229,125 +229,6 @@ int gv11b_pmu_bootstrap(struct gk20a *g, struct nvgpu_pmu *pmu, return err; } -static void gv11b_pmu_handle_ecc_irq(struct gk20a *g) -{ - u32 intr1; - u32 ecc_status, ecc_addr, corrected_cnt, uncorrected_cnt; - u32 corrected_delta, uncorrected_delta; - u32 corrected_overflow, uncorrected_overflow; - - intr1 = nvgpu_readl(g, pwr_pmu_ecc_intr_status_r()); - if ((intr1 & - (pwr_pmu_ecc_intr_status_corrected_m() | - pwr_pmu_ecc_intr_status_uncorrected_m())) == 0U) { - return; - } - - ecc_status = nvgpu_readl(g, - pwr_pmu_falcon_ecc_status_r()); - ecc_addr = nvgpu_readl(g, - pwr_pmu_falcon_ecc_address_r()); - corrected_cnt = nvgpu_readl(g, - pwr_pmu_falcon_ecc_corrected_err_count_r()); - uncorrected_cnt = nvgpu_readl(g, - pwr_pmu_falcon_ecc_uncorrected_err_count_r()); - - corrected_delta = - pwr_pmu_falcon_ecc_corrected_err_count_total_v(corrected_cnt); - uncorrected_delta = - pwr_pmu_falcon_ecc_uncorrected_err_count_total_v(uncorrected_cnt); - corrected_overflow = ecc_status & - pwr_pmu_falcon_ecc_status_corrected_err_total_counter_overflow_m(); - - uncorrected_overflow = ecc_status & - pwr_pmu_falcon_ecc_status_uncorrected_err_total_counter_overflow_m(); - corrected_overflow = ecc_status & - pwr_pmu_falcon_ecc_status_corrected_err_total_counter_overflow_m(); - - /* clear the interrupt */ - if (((intr1 & pwr_pmu_ecc_intr_status_corrected_m()) != 0U) || - (corrected_overflow != 0U)) { - nvgpu_writel(g, pwr_pmu_falcon_ecc_corrected_err_count_r(), 0); - } - if (((intr1 & pwr_pmu_ecc_intr_status_uncorrected_m()) != 0U) || - (uncorrected_overflow != 0U)) { - nvgpu_writel(g, - pwr_pmu_falcon_ecc_uncorrected_err_count_r(), 0); - } - - nvgpu_writel(g, pwr_pmu_falcon_ecc_status_r(), - pwr_pmu_falcon_ecc_status_reset_task_f()); - - /* update counters per slice */ - if (corrected_overflow != 0U) { - corrected_delta += - BIT32(pwr_pmu_falcon_ecc_corrected_err_count_total_s()); - } - if (uncorrected_overflow != 0U) { - uncorrected_delta += - BIT32(pwr_pmu_falcon_ecc_uncorrected_err_count_total_s()); - } - - g->ecc.pmu.pmu_ecc_corrected_err_count[0].counter += corrected_delta; - g->ecc.pmu.pmu_ecc_uncorrected_err_count[0].counter += - uncorrected_delta; - - nvgpu_log(g, gpu_dbg_intr, - "pmu ecc interrupt intr1: 0x%x", intr1); - - (void)gv11b_pmu_correct_ecc(g, ecc_status, ecc_addr); - - if ((corrected_overflow != 0U) || (uncorrected_overflow != 0U)) { - nvgpu_info(g, "ecc counter overflow!"); - } - - nvgpu_log(g, gpu_dbg_intr, - "ecc error row address: 0x%x", - pwr_pmu_falcon_ecc_address_row_address_v(ecc_addr)); - - nvgpu_log(g, gpu_dbg_intr, - "ecc error count corrected: %d, uncorrected %d", - g->ecc.pmu.pmu_ecc_corrected_err_count[0].counter, - g->ecc.pmu.pmu_ecc_uncorrected_err_count[0].counter); -} - -void gv11b_pmu_handle_ext_irq(struct gk20a *g, u32 intr0) -{ - /* - * handle the ECC interrupt - */ - if ((intr0 & pwr_falcon_irqstat_ext_ecc_parity_true_f()) != 0U) { - gv11b_pmu_handle_ecc_irq(g); - } -} - -u32 gv11b_pmu_get_irqdest(struct gk20a *g) -{ - u32 intr_dest; - - /* dest 0=falcon, 1=host; level 0=irq0, 1=irq1 */ - intr_dest = pwr_falcon_irqdest_host_gptmr_f(0) | - pwr_falcon_irqdest_host_wdtmr_f(1) | - pwr_falcon_irqdest_host_mthd_f(0) | - pwr_falcon_irqdest_host_ctxsw_f(0) | - pwr_falcon_irqdest_host_halt_f(1) | - pwr_falcon_irqdest_host_exterr_f(0) | - pwr_falcon_irqdest_host_swgen0_f(1) | - pwr_falcon_irqdest_host_swgen1_f(0) | - pwr_falcon_irqdest_host_ext_ecc_parity_f(1) | - pwr_falcon_irqdest_target_gptmr_f(1) | - pwr_falcon_irqdest_target_wdtmr_f(0) | - pwr_falcon_irqdest_target_mthd_f(0) | - pwr_falcon_irqdest_target_ctxsw_f(0) | - pwr_falcon_irqdest_target_halt_f(0) | - pwr_falcon_irqdest_target_exterr_f(0) | - pwr_falcon_irqdest_target_swgen0_f(0) | - pwr_falcon_irqdest_target_swgen1_f(0) | - pwr_falcon_irqdest_target_ext_ecc_parity_f(0); - - return intr_dest; -} - u32 gv11b_pmu_queue_head_r(u32 i) { return pwr_pmu_queue_head_r(i); diff --git a/drivers/gpu/nvgpu/hal/pmu/pmu_gv11b.h b/drivers/gpu/nvgpu/hal/pmu/pmu_gv11b.h index c82b77f82..8ed34a8b8 100644 --- a/drivers/gpu/nvgpu/hal/pmu/pmu_gv11b.h +++ b/drivers/gpu/nvgpu/hal/pmu/pmu_gv11b.h @@ -40,13 +40,12 @@ u32 gv11b_pmu_falcon_base_addr(void); void gv11b_secured_pmu_start(struct gk20a *g); bool gv11b_is_pmu_supported(struct gk20a *g); int gv11b_pmu_correct_ecc(struct gk20a *g, u32 ecc_status, u32 ecc_addr); +void gv11b_pmu_handle_ext_irq(struct gk20a *g, u32 intr0); #ifdef CONFIG_NVGPU_LS_PMU int gv11b_pmu_bootstrap(struct gk20a *g, struct nvgpu_pmu *pmu, u32 args_offset); void gv11b_pmu_setup_elpg(struct gk20a *g); -u32 gv11b_pmu_get_irqdest(struct gk20a *g); -void gv11b_pmu_handle_ext_irq(struct gk20a *g, u32 intr0); u32 gv11b_pmu_queue_head_r(u32 i); u32 gv11b_pmu_queue_head__size_1_v(void); u32 gv11b_pmu_queue_tail_r(u32 i); @@ -68,5 +67,7 @@ void gv11b_pmu_inject_ecc_error(struct gk20a *g, int gv11b_pmu_ecc_init(struct gk20a *g); void gv11b_pmu_ecc_free(struct gk20a *g); +u32 gv11b_pmu_get_irqdest(struct gk20a *g); +void gv11b_pmu_enable_irq(struct nvgpu_pmu *pmu, bool enable); #endif /* PMU_GV11B_H */ diff --git a/drivers/gpu/nvgpu/hal/pmu/pmu_gv11b_fusa.c b/drivers/gpu/nvgpu/hal/pmu/pmu_gv11b_fusa.c index adb757966..db2987caa 100644 --- a/drivers/gpu/nvgpu/hal/pmu/pmu_gv11b_fusa.c +++ b/drivers/gpu/nvgpu/hal/pmu/pmu_gv11b_fusa.c @@ -346,3 +346,169 @@ void gv11b_pmu_ecc_free(struct gk20a *g) nvgpu_kfree(g, ecc->pmu.pmu_ecc_corrected_err_count); nvgpu_kfree(g, ecc->pmu.pmu_ecc_uncorrected_err_count); } + +static void gv11b_pmu_handle_ecc_irq(struct gk20a *g) +{ + u32 intr1; + u32 ecc_status, ecc_addr, corrected_cnt, uncorrected_cnt; + u32 corrected_delta, uncorrected_delta; + u32 corrected_overflow, uncorrected_overflow; + + intr1 = nvgpu_readl(g, pwr_pmu_ecc_intr_status_r()); + if ((intr1 & + (pwr_pmu_ecc_intr_status_corrected_m() | + pwr_pmu_ecc_intr_status_uncorrected_m())) == 0U) { + return; + } + + ecc_status = nvgpu_readl(g, + pwr_pmu_falcon_ecc_status_r()); + ecc_addr = nvgpu_readl(g, + pwr_pmu_falcon_ecc_address_r()); + corrected_cnt = nvgpu_readl(g, + pwr_pmu_falcon_ecc_corrected_err_count_r()); + uncorrected_cnt = nvgpu_readl(g, + pwr_pmu_falcon_ecc_uncorrected_err_count_r()); + + corrected_delta = + pwr_pmu_falcon_ecc_corrected_err_count_total_v(corrected_cnt); + uncorrected_delta = + pwr_pmu_falcon_ecc_uncorrected_err_count_total_v(uncorrected_cnt); + corrected_overflow = ecc_status & + pwr_pmu_falcon_ecc_status_corrected_err_total_counter_overflow_m(); + + uncorrected_overflow = ecc_status & + pwr_pmu_falcon_ecc_status_uncorrected_err_total_counter_overflow_m(); + corrected_overflow = ecc_status & + pwr_pmu_falcon_ecc_status_corrected_err_total_counter_overflow_m(); + + /* clear the interrupt */ + if (((intr1 & pwr_pmu_ecc_intr_status_corrected_m()) != 0U) || + (corrected_overflow != 0U)) { + nvgpu_writel(g, pwr_pmu_falcon_ecc_corrected_err_count_r(), 0); + } + if (((intr1 & pwr_pmu_ecc_intr_status_uncorrected_m()) != 0U) || + (uncorrected_overflow != 0U)) { + nvgpu_writel(g, + pwr_pmu_falcon_ecc_uncorrected_err_count_r(), 0); + } + + nvgpu_writel(g, pwr_pmu_falcon_ecc_status_r(), + pwr_pmu_falcon_ecc_status_reset_task_f()); + + /* update counters per slice */ + if (corrected_overflow != 0U) { + corrected_delta += + BIT32(pwr_pmu_falcon_ecc_corrected_err_count_total_s()); + } + if (uncorrected_overflow != 0U) { + uncorrected_delta += + BIT32(pwr_pmu_falcon_ecc_uncorrected_err_count_total_s()); + } + + g->ecc.pmu.pmu_ecc_corrected_err_count[0].counter = + nvgpu_safe_add_u32( + g->ecc.pmu.pmu_ecc_corrected_err_count[0].counter, + corrected_delta); + g->ecc.pmu.pmu_ecc_uncorrected_err_count[0].counter = + nvgpu_safe_add_u32( + g->ecc.pmu.pmu_ecc_uncorrected_err_count[0].counter, + uncorrected_delta); + + nvgpu_log(g, gpu_dbg_intr, + "pmu ecc interrupt intr1: 0x%x", intr1); + + (void)gv11b_pmu_correct_ecc(g, ecc_status, ecc_addr); + + if ((corrected_overflow != 0U) || (uncorrected_overflow != 0U)) { + nvgpu_info(g, "ecc counter overflow!"); + } + + nvgpu_log(g, gpu_dbg_intr, + "ecc error row address: 0x%x", + pwr_pmu_falcon_ecc_address_row_address_v(ecc_addr)); + + nvgpu_log(g, gpu_dbg_intr, + "ecc error count corrected: %d, uncorrected %d", + g->ecc.pmu.pmu_ecc_corrected_err_count[0].counter, + g->ecc.pmu.pmu_ecc_uncorrected_err_count[0].counter); +} + +void gv11b_pmu_handle_ext_irq(struct gk20a *g, u32 intr0) +{ + /* + * handle the ECC interrupt + */ + if ((intr0 & pwr_falcon_irqstat_ext_ecc_parity_true_f()) != 0U) { + gv11b_pmu_handle_ecc_irq(g); + } +} + +void gv11b_pmu_enable_irq(struct nvgpu_pmu *pmu, bool enable) +{ + struct gk20a *g = pmu->g; + u32 intr_mask; + u32 intr_dest; + + nvgpu_log_fn(g, " "); + + nvgpu_mc_intr_stall_unit_config(g, MC_INTR_UNIT_PMU, MC_INTR_DISABLE); + + nvgpu_falcon_set_irq(pmu->flcn, false, 0x0, 0x0); + + if (enable) { + intr_dest = g->ops.pmu.get_irqdest(g); +#ifdef CONFIG_NVGPU_LS_PMU + /* 0=disable, 1=enable */ + intr_mask = pwr_falcon_irqmset_gptmr_f(1) | + pwr_falcon_irqmset_wdtmr_f(1) | + pwr_falcon_irqmset_mthd_f(0) | + pwr_falcon_irqmset_ctxsw_f(0) | + pwr_falcon_irqmset_halt_f(1) | + pwr_falcon_irqmset_exterr_f(1) | + pwr_falcon_irqmset_swgen0_f(1) | + pwr_falcon_irqmset_swgen1_f(1) | + pwr_falcon_irqmset_ext_ecc_parity_f(1); +#else + intr_mask = pwr_falcon_irqmset_ext_ecc_parity_f(1); +#endif + nvgpu_mc_intr_stall_unit_config(g, MC_INTR_UNIT_PMU, + MC_INTR_ENABLE); + + nvgpu_falcon_set_irq(pmu->flcn, true, intr_mask, intr_dest); + } + + nvgpu_log_fn(g, "done"); +} + +u32 gv11b_pmu_get_irqdest(struct gk20a *g) +{ + u32 intr_dest; + +#ifdef CONFIG_NVGPU_LS_PMU + /* dest 0=falcon, 1=host; level 0=irq0, 1=irq1 */ + intr_dest = pwr_falcon_irqdest_host_gptmr_f(0) | + pwr_falcon_irqdest_host_wdtmr_f(1) | + pwr_falcon_irqdest_host_mthd_f(0) | + pwr_falcon_irqdest_host_ctxsw_f(0) | + pwr_falcon_irqdest_host_halt_f(1) | + pwr_falcon_irqdest_host_exterr_f(0) | + pwr_falcon_irqdest_host_swgen0_f(1) | + pwr_falcon_irqdest_host_swgen1_f(0) | + pwr_falcon_irqdest_host_ext_ecc_parity_f(1) | + pwr_falcon_irqdest_target_gptmr_f(1) | + pwr_falcon_irqdest_target_wdtmr_f(0) | + pwr_falcon_irqdest_target_mthd_f(0) | + pwr_falcon_irqdest_target_ctxsw_f(0) | + pwr_falcon_irqdest_target_halt_f(0) | + pwr_falcon_irqdest_target_exterr_f(0) | + pwr_falcon_irqdest_target_swgen0_f(0) | + pwr_falcon_irqdest_target_swgen1_f(0) | + pwr_falcon_irqdest_target_ext_ecc_parity_f(0); +#else + intr_dest = pwr_falcon_irqdest_host_ext_ecc_parity_f(1) | + pwr_falcon_irqdest_target_ext_ecc_parity_f(0); +#endif + + return intr_dest; +} diff --git a/drivers/gpu/nvgpu/include/nvgpu/falcon.h b/drivers/gpu/nvgpu/include/nvgpu/falcon.h index a426e80b4..cca2677ce 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/falcon.h +++ b/drivers/gpu/nvgpu/include/nvgpu/falcon.h @@ -111,6 +111,7 @@ * + nvgpu_falcon_hs_ucode_load_bootstrap() * + nvgpu_falcon_get_mem_size() * + nvgpu_falcon_get_id() + * + nvgpu_falcon_set_irq() */ #include @@ -583,7 +584,7 @@ int nvgpu_falcon_sw_init(struct gk20a *g, u32 flcn_id); * @brief Free the falcon software state. * * @param g [in] The GPU driver struct. - * @param flcn_id [id] falcon ID. See #nvgpu_falcon_get_instance for supported + * @param flcn_id [in] falcon ID. See #nvgpu_falcon_get_instance for supported * values. * * This function is called during nvgpu power off to deinitialize falcons @@ -597,6 +598,35 @@ int nvgpu_falcon_sw_init(struct gk20a *g, u32 flcn_id); */ void nvgpu_falcon_sw_free(struct gk20a *g, u32 flcn_id); +/** + * @brief Set the falcon interrupt mask and routing registers. + * + * @param flcn [in] The falcon. + * @param enable [in] Indicates if interrupt mask is to be set or cleared and + * if interrupt routing register is to be set. + * @param intr_mask [in] Interrupt mask to be set when interrupts are to be + * enabled. Not applicable when interrupts are to be + * disabled. + * @param intr_dest [in] Interrupt routing to be set when interrupts are to + * be enabled. Not applicable when interrupts are to be + * disabled. + * + * This function is called during nvgpu power on to enable the falcon ECC + * interrupt and called during nvgpu power off to disable the falcon interrupts. + * + * Steps: + * - Validate the passed in \a flcn and return if not valid. + * - Check if interrupts are supported on the falcon and return if not + * supported. + * - If enabling the interrupts: + * - Set falcon_falcon_irqmset_r() register with the value \a intr_mask. + * - Set falcon_falcon_irqdest_r() register with the value \a intr_dest. + * - Else if disabling the interrupts: + * - Set falcon_falcon_irqmclr_r() register with the value 0xffffffffU; + */ +void nvgpu_falcon_set_irq(struct nvgpu_falcon *flcn, bool enable, + u32 intr_mask, u32 intr_dest); + #ifdef CONFIG_NVGPU_DGPU int nvgpu_falcon_copy_from_emem(struct nvgpu_falcon *flcn, u32 src, u8 *dst, u32 size, u8 port); @@ -611,8 +641,6 @@ void nvgpu_falcon_dump_stats(struct nvgpu_falcon *flcn); #ifdef CONFIG_NVGPU_FALCON_NON_FUSA int nvgpu_falcon_clear_halt_intr_status(struct nvgpu_falcon *flcn, unsigned int timeout); -void nvgpu_falcon_set_irq(struct nvgpu_falcon *flcn, bool enable, - u32 intr_mask, u32 intr_dest); int nvgpu_falcon_copy_from_dmem(struct nvgpu_falcon *flcn, u32 src, u8 *dst, u32 size, u8 port); int nvgpu_falcon_copy_from_imem(struct nvgpu_falcon *flcn, diff --git a/drivers/gpu/nvgpu/include/nvgpu/gops_falcon.h b/drivers/gpu/nvgpu/include/nvgpu/gops_falcon.h index 403521bf2..0c9114435 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/gops_falcon.h +++ b/drivers/gpu/nvgpu/include/nvgpu/gops_falcon.h @@ -56,13 +56,13 @@ struct gops_falcon { u32 mailbox_index); void (*mailbox_write)(struct nvgpu_falcon *flcn, u32 mailbox_index, u32 data); + void (*set_irq)(struct nvgpu_falcon *flcn, bool enable, + u32 intr_mask, u32 intr_dest); #ifdef CONFIG_NVGPU_FALCON_DEBUG void (*dump_falcon_stats)(struct nvgpu_falcon *flcn); #endif #ifdef CONFIG_NVGPU_FALCON_NON_FUSA bool (*clear_halt_interrupt_status)(struct nvgpu_falcon *flcn); - void (*set_irq)(struct nvgpu_falcon *flcn, bool enable, - u32 intr_mask, u32 intr_dest); int (*copy_from_dmem)(struct nvgpu_falcon *flcn, u32 src, u8 *dst, u32 size, u8 port); int (*copy_from_imem)(struct nvgpu_falcon *flcn, diff --git a/drivers/gpu/nvgpu/include/nvgpu/gops_mc.h b/drivers/gpu/nvgpu/include/nvgpu/gops_mc.h index b42d20095..dfca5d0ee 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/gops_mc.h +++ b/drivers/gpu/nvgpu/include/nvgpu/gops_mc.h @@ -111,6 +111,9 @@ struct gops_mc { * - Invoke g->ops.fifo.intr_0_isr if FIFO interrupt is pending. The * FIFO interrupt bit in mc_intr_r(#NVGPU_MC_INTR_STALLING) is * mc_intr_pfifo_pending_f. + * - Invoke g->ops.pmu.pmu_isr if PMU interrupt is pending. + * The PMU interrupt bit in mc_intr_r(#NVGPU_MC_INTR_STALLING) + * is mc_intr_pmu_pending_f. * - Invoke g->ops.priv_ring.isr if PRIV_RING interrupt is pending. * The PRIV_RING interrupt bit in mc_intr_r(#NVGPU_MC_INTR_STALLING) * is mc_intr_priv_ring_pending_f. diff --git a/drivers/gpu/nvgpu/include/nvgpu/gops_pmu.h b/drivers/gpu/nvgpu/include/nvgpu/gops_pmu.h index a008b71c9..c0dc0b5c7 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/gops_pmu.h +++ b/drivers/gpu/nvgpu/include/nvgpu/gops_pmu.h @@ -59,6 +59,27 @@ struct gops_pmu { */ void (*ecc_free)(struct gk20a *g); + /** + * @brief Interrupt handler for PMU interrupts. + * + * @param g [in] The GPU driver struct. + * + * Steps: + * + Acquire mutex g->pmu->isr_mutex. + * + If PMU interrupts are not enabled release isr_mutex and return. + * + Prepare mask by AND'ing registers pwr_falcon_irqmask_r and + * pwr_falcon_irqdest_r. + * + Read interrupts status register pwr_falcon_irqstat_r. + * + Determine interrupts to be handled by AND'ing value read in + * the previous step with the mask computed earlier. + * + If no interrupts are to be handled release isr_mutex and return. + * + Handle ECC interrupt if it is pending. + * + Clear the pending interrupts to be handled by writing the + * pending interrupt mask to the register pwr_falcon_irqsclr_r. + * + Release mutex g->pmu->isr_mutex. + */ + void (*pmu_isr)(struct gk20a *g); + /** @cond DOXYGEN_SHOULD_SKIP_THIS */ /** @@ -291,14 +312,15 @@ struct gops_pmu { bool (*validate_mem_integrity)(struct gk20a *g); /** @cond DOXYGEN_SHOULD_SKIP_THIS */ + void (*handle_ext_irq)(struct gk20a *g, u32 intr); + + void (*pmu_enable_irq)(struct nvgpu_pmu *pmu, bool enable); + u32 (*get_irqdest)(struct gk20a *g); + #ifdef CONFIG_NVGPU_LS_PMU /* ISR */ - void (*pmu_enable_irq)(struct nvgpu_pmu *pmu, bool enable); bool (*pmu_is_interrupted)(struct nvgpu_pmu *pmu); - void (*pmu_isr)(struct gk20a *g); void (*set_irqmask)(struct gk20a *g); - u32 (*get_irqdest)(struct gk20a *g); - void (*handle_ext_irq)(struct gk20a *g, u32 intr); /* non-secure */ int (*pmu_ns_bootstrap)(struct gk20a *g, struct nvgpu_pmu *pmu, u32 args_offset); diff --git a/drivers/gpu/nvgpu/include/nvgpu/pmu.h b/drivers/gpu/nvgpu/include/nvgpu/pmu.h index 785ad5108..4ad5eb9c5 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/pmu.h +++ b/drivers/gpu/nvgpu/include/nvgpu/pmu.h @@ -346,6 +346,22 @@ int nvgpu_pmu_destroy(struct gk20a *g, struct nvgpu_pmu *pmu); void nvgpu_pmu_report_bar0_pri_err_status(struct gk20a *g, u32 bar0_status, u32 error_type); +/** + * @brief Enable/Disable PMU ECC interrupt. + * + * @param g [in] The GPU driver struct. + * @param enable [in] boolean parameter to enable/disable. + * + * Enable/Disable PMU ECC interrupt. + * + Check that g->pmu and g->ops.pmu.pmu_enable_irq are not null. + * + Acquire the mutex g->pmu->isr_mutex. + * + Disable the PMU interrupts at MC and PMU level. + * + If enabling, enable ECC interrupt in PMU interrupt configuration + * registers and enable PMU interrupts at MC level. + * + Release the mutex g->pmu->isr_mutex. + */ +void nvgpu_pmu_enable_irq(struct gk20a *g, bool enable); + /** * @brief Reset the PMU Engine. * @@ -371,7 +387,7 @@ int nvgpu_pmu_reset(struct gk20a *g); * Allocate memory for #nvgpu_pmu data struct & set PMU Engine h/w properties, * PMU RTOS supporting data structs & ops of the PMU unit by populating data * based on the detected chip. Allocates memory for ECC counters for PMU - * unit. + * unit. Initializes the isr_mutex. * * @return 0 in case of success, < 0 in case of failure. */ diff --git a/drivers/gpu/nvgpu/include/nvgpu/pmu/debug.h b/drivers/gpu/nvgpu/include/nvgpu/pmu/debug.h index 7efeb1d44..f8f86a4d0 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/pmu/debug.h +++ b/drivers/gpu/nvgpu/include/nvgpu/pmu/debug.h @@ -23,6 +23,11 @@ #ifndef NVGPU_PMU_DEBUG_H #define NVGPU_PMU_DEBUG_H +#include + +struct nvgpu_pmu; +struct gk20a; + /* PMU debug */ void nvgpu_pmu_dump_falcon_stats(struct nvgpu_pmu *pmu); bool nvgpu_find_hex_in_string(char *strings, struct gk20a *g, u32 *hex_pos); diff --git a/userspace/units/acr/nvgpu-acr.c b/userspace/units/acr/nvgpu-acr.c index 3a4e6b582..3aea2dc6f 100644 --- a/userspace/units/acr/nvgpu-acr.c +++ b/userspace/units/acr/nvgpu-acr.c @@ -602,6 +602,11 @@ int test_acr_init(struct unit_module *m, unit_return_fail(m, "Module init failed\n"); } + err = g->ops.ecc.ecc_init_support(g); + if (err != 0) { + unit_return_fail(m, "ecc init failed\n"); + } + /* * initialize PMU */ diff --git a/userspace/units/mc/nvgpu-mc.c b/userspace/units/mc/nvgpu-mc.c index 405dac1bf..4589061c1 100644 --- a/userspace/units/mc/nvgpu-mc.c +++ b/userspace/units/mc/nvgpu-mc.c @@ -61,6 +61,7 @@ struct mc_unit { }; static struct mc_unit mc_units[] = { { MC_INTR_UNIT_BUS, mc_intr_pbus_pending_f() }, + { MC_INTR_UNIT_PMU, mc_intr_pmu_pending_f() }, { MC_INTR_UNIT_PRIV_RING, mc_intr_priv_ring_pending_f() }, { MC_INTR_UNIT_FIFO, mc_intr_pfifo_pending_f() }, { MC_INTR_UNIT_LTC, mc_intr_ltc_pending_f() }, @@ -114,6 +115,7 @@ struct unit_ctx { bool fifo_isr; bool gr_isr; bool ltc_isr; + bool pmu_isr; bool priv_ring_isr; u32 ce_isr_return; @@ -132,6 +134,7 @@ static void reset_ctx(void) u.gr_isr = false; u.gr_isr_return = 0; u.ltc_isr = false; + u.pmu_isr = false; u.priv_ring_isr = false; } @@ -219,6 +222,11 @@ static void mock_ltc_isr(struct gk20a *g, u32 ltc) u.ltc_isr = true; } +static void mock_pmu_isr(struct gk20a *g) +{ + u.pmu_isr = true; +} + static void mock_priv_ring_isr(struct gk20a *g) { u.priv_ring_isr = true; @@ -265,6 +273,7 @@ int test_setup_env(struct unit_module *m, g->ops.gr.intr.stall_isr = mock_gr_stall_isr; g->ops.gr.intr.nonstall_isr = mock_gr_nonstall_isr; g->ops.ltc.intr.isr = mock_ltc_isr; + g->ops.pmu.pmu_isr = mock_pmu_isr; g->ops.priv_ring.isr = mock_priv_ring_isr; /* setup engines for getting interrupt info */ @@ -513,7 +522,7 @@ int test_isr_stall(struct unit_module *m, struct gk20a *g, void *args) reset_ctx(); g->ops.mc.isr_stall(g); if (u.bus_isr || u.ce_isr || u.fb_isr || u.fifo_isr || u.gr_isr || - u.priv_ring_isr) { + u.pmu_isr || u.priv_ring_isr) { unit_return_fail(m, "unexpected ISR called\n"); } @@ -526,7 +535,7 @@ int test_isr_stall(struct unit_module *m, struct gk20a *g, void *args) reset_ctx(); g->ops.mc.isr_stall(g); if (!u.bus_isr || !u.ce_isr || !u.fb_isr || !u.fifo_isr || !u.gr_isr || - !u.priv_ring_isr) { + !u.pmu_isr || !u.priv_ring_isr) { unit_return_fail(m, "not all ISRs called\n"); } diff --git a/userspace/units/pmu/nvgpu-pmu.c b/userspace/units/pmu/nvgpu-pmu.c index 951a05453..61713b760 100644 --- a/userspace/units/pmu/nvgpu-pmu.c +++ b/userspace/units/pmu/nvgpu-pmu.c @@ -227,6 +227,11 @@ static int test_pmu_reset(struct unit_module *m, unit_return_fail(m, "Module init failed\n"); } + err = g->ops.ecc.ecc_init_support(g); + if (err != 0) { + unit_return_fail(m, "ecc init failed\n"); + } + /* initialize PMU */ err = nvgpu_pmu_early_init(g); if (err != 0) {