[PATCH 1/3] perf/x86: Add x86_pmu::print_debug

Sandipan Das <[email protected]> Thu, 6 Aug 2026 15:33:26 +0530
Newsgroups org.kernel.vger.linux-perf-users,org.kernel.vger.linux-kernel
Message-ID <fc6ff612d26c2f5b0f015d9fac309cc58e913c1f.1786010408.git.sandipan.das@amd.com>
perf_event_print_debug() dumps the global control and status MSRs
whenever x86_pmu.version >= 2, reading registers that exist only on
Intel-compatible PMUs. This is not safe since x86_pmu.version is not
Intel-specific and is now set by other vendors whose global registers
use different addresses.

As a first step, split perf_event_print_debug() in two. The register
dump moves into a new common helper, x86_pmu_print_debug(), leaving
perf_event_print_debug() to handle the preamble and dispatch to an
optional x86_pmu::print_debug method. This lets each vendor-specific
PMU dump its own global state before chaining into the common helper.
PMUs that do not implement the method, such as those with
x86_pmu.version < 2, get the common helper alone.

No functional change intended.

Signed-off-by: Sandipan Das <[email protected]>
---
 arch/x86/events/core.c       | 29 ++++++++++++++++++++++-------
 arch/x86/events/perf_event.h |  4 ++++
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index af0b67ffb43d..17dc53a62378 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -1557,7 +1557,7 @@ static void x86_pmu_start(struct perf_event *event, int flags)
 	perf_event_update_userpage(event);
 }
 
-void perf_event_print_debug(void)
+void x86_pmu_print_debug(int cpu)
 {
 	u64 ctrl, status, overflow, pmc_ctrl, pmc_count, prev_left, fixed;
 	unsigned long *cntr_mask, *fixed_cntr_mask;
@@ -1566,17 +1566,11 @@ void perf_event_print_debug(void)
 	u64 pebs, debugctl;
 	int cpu, idx;
 
-	guard(irqsave)();
-
-	cpu = smp_processor_id();
 	cpuc = &per_cpu(cpu_hw_events, cpu);
 	cntr_mask = hybrid(cpuc->pmu, cntr_mask);
 	fixed_cntr_mask = hybrid(cpuc->pmu, fixed_cntr_mask);
 	pebs_constraints = hybrid(cpuc->pmu, pebs_constraints);
 
-	if (!*(u64 *)cntr_mask)
-		return;
-
 	if (x86_pmu.version >= 2) {
 		rdmsrq(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
 		rdmsrq(MSR_CORE_PERF_GLOBAL_STATUS, status);
@@ -1622,6 +1616,27 @@ void perf_event_print_debug(void)
 	}
 }
 
+void perf_event_print_debug(void)
+{
+	struct cpu_hw_events *cpuc;
+	unsigned long *cntr_mask;
+	int cpu;
+
+	guard(irqsave)();
+
+	cpu = smp_processor_id();
+	cpuc = &per_cpu(cpu_hw_events, cpu);
+	cntr_mask = hybrid(cpuc->pmu, cntr_mask);
+
+	if (!*(u64 *)cntr_mask)
+		return;
+
+	if (x86_pmu.print_debug)
+		x86_pmu.print_debug(cpu);
+	else
+		x86_pmu_print_debug(cpu);
+}
+
 void x86_pmu_stop(struct perf_event *event, int flags)
 {
 	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index a8afea8d38f0..465bf513bb82 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -1052,6 +1052,8 @@ struct x86_pmu {
 	int				num_hybrid_pmus;
 	struct x86_hybrid_pmu		*hybrid_pmu;
 	enum intel_cpu_type (*get_hybrid_cpu_type)	(void);
+
+	void (*print_debug)(int cpu);
 };
 
 struct x86_perf_task_context_opt {
@@ -1316,6 +1318,8 @@ int x86_pmu_handle_irq(struct pt_regs *regs);
 
 void x86_pmu_show_pmu_cap(struct pmu *pmu);
 
+void x86_pmu_print_debug(int cpu);
+
 static inline int x86_pmu_num_counters(struct pmu *pmu)
 {
 	return hweight64(hybrid(pmu, cntr_mask64));
-- 
2.53.0