[PATCH v3 3/3] lib: sbi: Add SSE support for PMU events
Samuel Holland
samuel.holland at sifive.com
Fri Apr 5 09:52:57 PDT 2024
Hi Clément,
On 2024-03-21 10:57 AM, Clément Léger wrote:
> 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 <cleger at rivosinc.com>
> ---
> 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 <sbi/sbi_types.h>
> +#include <sbi/sbi_trap.h>
>
> 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 <sbi/sbi_pmu.h>
> #include <sbi/sbi_scratch.h>
> #include <sbi/sbi_string.h>
> +#include <sbi/sbi_sse.h>
>
> /** 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);
This needs to use sbi_pmu_irq_bit(), along with the all of the other new
references to 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;
nit: false instead of 0 for a Boolean variable.
> }
>
> 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;
This also needs to use sbi_pmu_irq_bit(). If you don't want to support
non-Sscofpmf implementations, then attempting to enable the SSE event should
fail for those implementations.
Regards,
Samuel
> 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)
More information about the opensbi
mailing list