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) {