From 06fc453ec13de75e156261e8fe4073334d0e00c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 21 Mar 2024 16:57:18 +0100 Subject: [PATCH] lib: sbi: Add SSE support for PMU events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add SSE callbacks registration to PMU driver in order to disable interrupt delegation for PMU interrupts. When interrupts are undelegated send the PMU SSE event upon LCOFIP IRQ. Signed-off-by: Clément Léger Reviewed-by: Anup Patel --- include/sbi/sbi_pmu.h | 3 +++ lib/sbi/sbi_pmu.c | 51 +++++++++++++++++++++++++++++++++++++++++++ lib/sbi/sbi_trap.c | 6 +++++ 3 files changed, 60 insertions(+) diff --git a/include/sbi/sbi_pmu.h b/include/sbi/sbi_pmu.h index 7d32a4d..8b1e08c 100644 --- a/include/sbi/sbi_pmu.h +++ b/include/sbi/sbi_pmu.h @@ -11,6 +11,7 @@ #define __SBI_PMU_H__ #include +#include struct sbi_scratch; @@ -150,4 +151,6 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask, int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id); +void sbi_pmu_ovf_irq(); + #endif diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index 62a6465..b9e8454 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -17,6 +17,7 @@ #include #include #include +#include /** Information about hardware counters */ struct sbi_pmu_hw_event { @@ -62,6 +63,8 @@ struct sbi_pmu_hart_state { uint32_t active_events[SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX]; /* Bitmap of firmware counters started */ unsigned long fw_counters_started; + /* if true, SSE is enabled */ + bool sse_enabled; /* * Counter values for SBI firmware events and event codes * for platform firmware events. Both are mutually exclusive @@ -300,6 +303,16 @@ int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32 SBI_PMU_EVENT_RAW_IDX, cmap, select, select_mask); } +void sbi_pmu_ovf_irq() +{ + /* + * We need to disable LCOFIP before returning to S-mode or we will loop + * on LCOFIP being triggered + */ + csr_clear(CSR_MIE, MIP_LCOFIP); + sbi_sse_inject_event(SBI_SSE_EVENT_LOCAL_PMU); +} + static int pmu_ctr_enable_irq_hw(int ctr_idx) { unsigned long mhpmevent_csr; @@ -575,6 +588,10 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask, } } + /* Clear MIP_LCOFIP to avoid spurious interrupts */ + if (phs->sse_enabled) + csr_clear(CSR_MIP, MIP_LCOFIP); + return ret; } @@ -962,6 +979,7 @@ static void pmu_reset_event_map(struct sbi_pmu_hart_state *phs) for (j = 0; j < SBI_PMU_FW_CTR_MAX; j++) phs->fw_counters_data[j] = 0; phs->fw_counters_started = 0; + phs->sse_enabled = 0; } const struct sbi_pmu_device *sbi_pmu_get_device(void) @@ -993,6 +1011,37 @@ void sbi_pmu_exit(struct sbi_scratch *scratch) pmu_reset_event_map(phs); } +static void pmu_sse_enable(uint32_t event_id) +{ + struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr(); + + phs->sse_enabled = true; + csr_clear(CSR_MIDELEG, sbi_pmu_irq_bit()); + csr_clear(CSR_MIP, MIP_LCOFIP); + csr_set(CSR_MIE, MIP_LCOFIP); +} + +static void pmu_sse_disable(uint32_t event_id) +{ + struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr(); + + csr_clear(CSR_MIE, MIP_LCOFIP); + csr_clear(CSR_MIP, MIP_LCOFIP); + csr_set(CSR_MIDELEG, sbi_pmu_irq_bit()); + phs->sse_enabled = false; +} + +static void pmu_sse_complete(uint32_t event_id) +{ + csr_set(CSR_MIE, MIP_LCOFIP); +} + +static const struct sbi_sse_cb_ops pmu_sse_cb_ops = { + .enable_cb = pmu_sse_enable, + .disable_cb = pmu_sse_disable, + .complete_cb = pmu_sse_complete, +}; + int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot) { int hpm_count = sbi_fls(sbi_hart_mhpm_mask(scratch)); @@ -1032,6 +1081,8 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot) total_ctrs = num_hw_ctrs + SBI_PMU_FW_CTR_MAX; } + sbi_sse_set_cb_ops(SBI_SSE_EVENT_LOCAL_PMU, &pmu_sse_cb_ops); + phs = pmu_get_hart_state_ptr(scratch); if (!phs) { phs = sbi_zalloc(sizeof(*phs)); diff --git a/lib/sbi/sbi_trap.c b/lib/sbi/sbi_trap.c index 624b45e..b4f3a17 100644 --- a/lib/sbi/sbi_trap.c +++ b/lib/sbi/sbi_trap.c @@ -223,6 +223,9 @@ static int sbi_trap_nonaia_irq(unsigned long irq) case IRQ_M_SOFT: sbi_ipi_process(); break; + case IRQ_PMU_OVF: + sbi_pmu_ovf_irq(); + break; case IRQ_M_EXT: return sbi_irqchip_process(); default: @@ -246,6 +249,9 @@ static int sbi_trap_aia_irq(void) case IRQ_M_SOFT: sbi_ipi_process(); break; + case IRQ_PMU_OVF: + sbi_pmu_ovf_irq(); + break; case IRQ_M_EXT: rc = sbi_irqchip_process(); if (rc)