[PATCH] perf/x86/intel: Fix unchecked MSR access error for Alder Lake N

From: kan . liang
Date: Tue Jun 21 2022 - 14:16:47 EST


From: Kan Liang <kan.liang@xxxxxxxxxxxxxxx>

For some Alder Lake N machine, the below unchecked MSR access error may be
triggered.

[ 0.088017] rcu: Hierarchical SRCU implementation.
[ 0.088017] unchecked MSR access error: WRMSR to 0x38f (tried to write
0x0001000f0000003f) at rIP: 0xffffffffb5684de8 (native_write_msr+0x8/0x30)
[ 0.088017] Call Trace:
[ 0.088017] <TASK>
[ 0.088017] __intel_pmu_enable_all.constprop.46+0x4a/0xa0

The Alder Lake N only has e-cores. The X86_FEATURE_HYBRID_CPU flag is
not set. The perf cannot retrieve the correct CPU type via
get_this_hybrid_cpu_type(). The model specific get_hybrid_cpu_type() is
hardcode to p-core. The wrong CPU type is given to the PMU of the
Alder Lake N.

Add a model check to return the e-core CPU type for Alder Lake N.

Factor out x86_pmu_get_this_hybrid_cpu_type().

Fixes: c2a960f7c574 ("perf/x86: Add new Alder Lake and Raptor Lake support")
Reported-by: Gao, Jianfeng <jianfeng.gao@xxxxxxxxx>
Tested-by: Gao, Jianfeng <jianfeng.gao@xxxxxxxxx>
Signed-off-by: Kan Liang <kan.liang@xxxxxxxxxxxxxxx>
---
arch/x86/events/core.c | 15 +++++++++++----
arch/x86/events/intel/core.c | 8 ++++----
arch/x86/events/perf_event.h | 2 ++
3 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 0b19ffaa2dee..94cdf7e76b86 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -2076,6 +2076,16 @@ void x86_pmu_update_cpu_context(struct pmu *pmu, int cpu)
cpuctx->ctx.pmu = pmu;
}

+u8 x86_pmu_get_this_hybrid_cpu_type(void)
+{
+ u8 cpu_type = get_this_hybrid_cpu_type();
+
+ if (!cpu_type && x86_pmu.get_hybrid_cpu_type)
+ return x86_pmu.get_hybrid_cpu_type();
+
+ return cpu_type;
+}
+
static int __init init_hw_perf_events(void)
{
struct x86_pmu_quirk *quirk;
@@ -2175,13 +2185,10 @@ static int __init init_hw_perf_events(void)
if (err)
goto out2;
} else {
- u8 cpu_type = get_this_hybrid_cpu_type();
+ u8 cpu_type = x86_pmu_get_this_hybrid_cpu_type();
struct x86_hybrid_pmu *hybrid_pmu;
int i, j;

- if (!cpu_type && x86_pmu.get_hybrid_cpu_type)
- cpu_type = x86_pmu.get_hybrid_cpu_type();
-
for (i = 0; i < x86_pmu.num_hybrid_pmus; i++) {
hybrid_pmu = &x86_pmu.hybrid_pmu[i];

diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 217c5695cbb0..1d57cf0be806 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -4267,6 +4267,9 @@ static int adl_hw_config(struct perf_event *event)

static u8 adl_get_hybrid_cpu_type(void)
{
+ if (boot_cpu_data.x86_model == INTEL_FAM6_ALDERLAKE_N)
+ return hybrid_small;
+
return hybrid_big;
}

@@ -4430,13 +4433,10 @@ static void flip_smm_bit(void *data)
static bool init_hybrid_pmu(int cpu)
{
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
- u8 cpu_type = get_this_hybrid_cpu_type();
+ u8 cpu_type = x86_pmu_get_this_hybrid_cpu_type();
struct x86_hybrid_pmu *pmu = NULL;
int i;

- if (!cpu_type && x86_pmu.get_hybrid_cpu_type)
- cpu_type = x86_pmu.get_hybrid_cpu_type();
-
for (i = 0; i < x86_pmu.num_hybrid_pmus; i++) {
if (x86_pmu.hybrid_pmu[i].cpu_type == cpu_type) {
pmu = &x86_pmu.hybrid_pmu[i];
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index ba30f24bec41..c1bf7e6af6a0 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -1176,6 +1176,8 @@ void x86_pmu_show_pmu_cap(int num_counters, int num_counters_fixed,

void x86_pmu_update_cpu_context(struct pmu *pmu, int cpu);

+u8 x86_pmu_get_this_hybrid_cpu_type(void);
+
extern struct event_constraint emptyconstraint;

extern struct event_constraint unconstrained;
--
2.35.1