[RFC PATCH 3/3] perf/riscv: Use Sspesa for precise sample attribution

Mayuresh Chitale mayuresh.chitale at oss.qualcomm.com
Mon Aug 17 09:02:19 PDT 2026


When the Sspesa (Precise Event Sample Attribution) extension is
available and a counter overflows, the hardware records a sample PC in
shpmspc register and the counter ID and additional implementation-defined
data in shpmsdata register.

In the SBI PMU overflow handler, use shpmspc to report sample PC via
PERF_SAMPLE_IP for the counter that caused the overflow. Shpmsdata is
exported as raw data to userspace when events request PERF_SAMPLE_RAW
sample type and it assists in deriving the sample PC from shpmspc if
precise attribution is not supported for the event.

If sspesa is not available or for counters that don't match
shpmsdata.CNTRID, fallback to epc for PERF_SAMPLE_IP.

Signed-off-by: Mayuresh Chitale <mayuresh.chitale at oss.qualcomm.com>
---
 drivers/perf/riscv_pmu_sbi.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index dfc886dee5ad..1b0b1cc612de 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -63,6 +63,8 @@ PMU_FORMAT_ATTR(firmware, "config:62-63");
 
 static bool sbi_v2_available;
 static bool sbi_v3_available;
+static bool sspesa_available;
+
 static DEFINE_STATIC_KEY_FALSE(sbi_pmu_snapshot_available);
 #define sbi_pmu_snapshot_available() \
 	static_branch_unlikely(&sbi_pmu_snapshot_available)
@@ -1051,6 +1053,11 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
 	struct cpu_hw_events *cpu_hw_evt = dev;
 	u64 start_clock = sched_clock();
 	struct riscv_pmu_snapshot_data *sdata = cpu_hw_evt->snapshot_addr;
+	unsigned long sample_pc = 0;
+	unsigned long sample_data = 0;
+	int sample_cntrid = -1;
+	u64 raw_sample;
+	struct perf_raw_record raw = { 0 };
 
 	if (WARN_ON_ONCE(!cpu_hw_evt))
 		return IRQ_NONE;
@@ -1088,6 +1095,16 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
 		return IRQ_NONE;
 
 	regs = get_irq_regs();
+	/*
+	 * Sspesa records the PC and metadata of the overflowing counter in
+	 * hardware. The PC is precise only for events that support precise
+	 * attribution; otherwise it is best-effort.
+	 */
+	if (sspesa_available) {
+		sample_pc = csr_read(CSR_SHPMSPC);
+		sample_data = csr_read(CSR_SHPMSDATA);
+		sample_cntrid = sample_data & SHPMSDATA_CNTRID;
+	}
 
 	for_each_set_bit(lidx, cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS) {
 		struct perf_event *event = cpu_hw_evt->events[lidx];
@@ -1123,6 +1140,15 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
 		riscv_pmu_event_update(event);
 		hw_evt->state |= PERF_HES_UPTODATE;
 		perf_sample_data_init(&data, 0, hw_evt->last_period);
+		if (sspesa_available && hidx == sample_cntrid) {
+			data.ip = sample_pc;
+			data.sample_flags |= PERF_SAMPLE_IP;
+
+			raw_sample = sample_data;
+			raw.frag.size = sizeof(raw_sample);
+			raw.frag.data = &raw_sample;
+			perf_sample_save_raw_data(&data, event, &raw);
+		}
 		if (riscv_pmu_event_set_period(event)) {
 			/*
 			 * Unlike other ISAs, RISC-V don't have to disable interrupts
@@ -1194,6 +1220,9 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
 	struct cpu_hw_events __percpu *hw_events = pmu->hw_events;
 	struct irq_domain *domain = NULL;
 
+	if (riscv_isa_extension_available(NULL, SSPESA))
+		sspesa_available = true;
+
 	if (riscv_isa_extension_available(NULL, SSCOFPMF)) {
 		riscv_pmu_irq_num = RV_IRQ_PMU;
 		riscv_pmu_use_irq = true;
-- 
2.43.0




More information about the linux-riscv mailing list