[PATCH v2 1/3] perf/x86: Add x86_pmu::print_debug
From: Sandipan Das
Date: Fri Aug 14 2026 - 13:49:45 EST
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 <sandipan.das@xxxxxxx>
---
arch/x86/events/core.c | 35 +++++++++++++++++++++++++++--------
arch/x86/events/perf_event.h | 4 ++++
2 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 8b3ea0adb965..364a4c83f677 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -105,6 +105,8 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_disable, *x86_pmu.pebs_disable);
DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_enable_all, *x86_pmu.pebs_enable_all);
DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_disable_all, *x86_pmu.pebs_disable_all);
+DEFINE_STATIC_CALL_NULL(x86_pmu_print_debug, *x86_pmu.print_debug);
+
/*
* This one is magic, it will get called even when PMU init fails (because
* there is no PMU), in which case it should simply return NULL.
@@ -1571,26 +1573,20 @@ 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;
struct event_constraint *pebs_constraints;
struct cpu_hw_events *cpuc;
u64 pebs, debugctl;
- int cpu, idx;
-
- guard(irqsave)();
+ int idx;
- 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);
@@ -1634,6 +1630,24 @@ 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;
+
+ static_call(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);
@@ -2122,6 +2136,8 @@ static void x86_pmu_static_call_update(void)
static_call_update(x86_pmu_pebs_disable, x86_pmu.pebs_disable);
static_call_update(x86_pmu_pebs_enable_all, x86_pmu.pebs_enable_all);
static_call_update(x86_pmu_pebs_disable_all, x86_pmu.pebs_disable_all);
+
+ static_call_update(x86_pmu_print_debug, x86_pmu.print_debug);
}
static void _x86_pmu_read(struct perf_event *event)
@@ -2233,6 +2249,9 @@ static int __init init_hw_perf_events(void)
if (!x86_pmu.update)
x86_pmu.update = x86_perf_event_update;
+ if (!x86_pmu.print_debug)
+ x86_pmu.print_debug = x86_pmu_print_debug;
+
x86_pmu_static_call_update();
/*
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index fa381110f7a7..a5d15ff50a2d 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 {
@@ -1317,6 +1319,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