From 65bb705f7b59d8f2a5683160f31db15b4e2c64d7 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 24 Mar 2026 23:29:20 +1100 Subject: [PATCH] lib/sbi_pmu: Don't fallback to fixed counters when sscofpmf && !smcntrpmf Currently when searching for a hardware counter for an event, if no programmable counter is available, the code falls back to using a fixed counter (mcycle/minstret) if one matches the event. However the fallback is incorrect when sscofpmf is present but smcntrpmf is not. That's because with sscofpmf, programmable counters support mode filtering, but the fixed counters do not (without smcntrpmf). Even if the caller didn't configure mode filtering, by default programmable counters don't count M mode when sscofpmf is present, whereas mcycle/minstret do. Fix the logic to not fallback to a fixed counter if sscofpmf is present but smcntrpmf is not. Fixes: 0c304b661965 ("lib: sbi: Allow programmable counters to monitor cycle/instret events") Signed-off-by: Michael Ellerman Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20260324-mcycle-fix-v1-1-1444e9fe5c32@kernel.org Signed-off-by: Anup Patel --- lib/sbi/sbi_pmu.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index ae00ad58..8a9021e2 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -830,13 +830,20 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs, if (ctr_idx == SBI_ENOTSUPP) { /** - * We can't find any programmable counters for cycle/instret. - * Return the fixed counter as they are mandatory anyways. + * We can't find a programmable counter, see if we can use a + * fixed counter instead if one was found for this event. + * + * If sscofpmf is present but smcntrpmf is not, we can't + * fallback to a fixed counter, because the fixed counter + * doesn't support filtering whereas a programmable counter + * would. */ - if (fixed_ctr >= 0) - return pmu_fixed_ctr_update_inhibit_bits(fixed_ctr, flags); - else + if (fixed_ctr < 0 || + ((sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF) && + !sbi_hart_has_extension(scratch, SBI_HART_EXT_SMCNTRPMF)))) return SBI_EFAIL; + + return pmu_fixed_ctr_update_inhibit_bits(fixed_ctr, flags); } ret = pmu_update_hw_mhpmevent(temp, ctr_idx, flags, event_idx, data);