Skip to content

Commit 0abf540

Browse files
committed
Merge: perf: Intel Arrowlake support (RAPL and perfmon)
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/6881 JIRA: https://issues.redhat.com/browse/RHEL-20094 JIRA: https://issues.redhat.com/browse/RHEL-53585 This MR adds all currently known code to enable pref features on Intel Arrow Lake. Signed-off-by: Michael Petlan <mpetlan@redhat.com> Approved-by: Lenny Szubowicz <lszubowi@redhat.com> Approved-by: ashelat <ashelat@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Augusto Caringi <acaringi@redhat.com>
2 parents 5953522 + 0e02604 commit 0abf540

File tree

6 files changed

+190
-20
lines changed

6 files changed

+190
-20
lines changed

arch/x86/events/intel/core.c

Lines changed: 121 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4598,6 +4598,28 @@ static inline bool erratum_hsw11(struct perf_event *event)
45984598
X86_CONFIG(.event=0xc0, .umask=0x01);
45994599
}
46004600

4601+
static struct event_constraint *
4602+
arl_h_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
4603+
struct perf_event *event)
4604+
{
4605+
struct x86_hybrid_pmu *pmu = hybrid_pmu(event->pmu);
4606+
4607+
if (pmu->pmu_type == hybrid_tiny)
4608+
return cmt_get_event_constraints(cpuc, idx, event);
4609+
4610+
return mtl_get_event_constraints(cpuc, idx, event);
4611+
}
4612+
4613+
static int arl_h_hw_config(struct perf_event *event)
4614+
{
4615+
struct x86_hybrid_pmu *pmu = hybrid_pmu(event->pmu);
4616+
4617+
if (pmu->pmu_type == hybrid_tiny)
4618+
return intel_pmu_hw_config(event);
4619+
4620+
return adl_hw_config(event);
4621+
}
4622+
46014623
/*
46024624
* The HSW11 requires a period larger than 100 which is the same as the BDM11.
46034625
* A minimum period of 128 is enforced as well for the INST_RETIRED.ALL.
@@ -4923,17 +4945,26 @@ static struct x86_hybrid_pmu *find_hybrid_pmu_for_cpu(void)
49234945

49244946
/*
49254947
* This essentially just maps between the 'hybrid_cpu_type'
4926-
* and 'hybrid_pmu_type' enums:
4948+
* and 'hybrid_pmu_type' enums except for ARL-H processor
4949+
* which needs to compare atom uarch native id since ARL-H
4950+
* contains two different atom uarchs.
49274951
*/
49284952
for (i = 0; i < x86_pmu.num_hybrid_pmus; i++) {
49294953
enum hybrid_pmu_type pmu_type = x86_pmu.hybrid_pmu[i].pmu_type;
4954+
u32 native_id;
49304955

4931-
if (cpu_type == HYBRID_INTEL_CORE &&
4932-
pmu_type == hybrid_big)
4933-
return &x86_pmu.hybrid_pmu[i];
4934-
if (cpu_type == HYBRID_INTEL_ATOM &&
4935-
pmu_type == hybrid_small)
4956+
if (cpu_type == HYBRID_INTEL_CORE && pmu_type == hybrid_big)
49364957
return &x86_pmu.hybrid_pmu[i];
4958+
if (cpu_type == HYBRID_INTEL_ATOM) {
4959+
if (x86_pmu.num_hybrid_pmus == 2 && pmu_type == hybrid_small)
4960+
return &x86_pmu.hybrid_pmu[i];
4961+
4962+
native_id = get_this_hybrid_cpu_native_id();
4963+
if (native_id == skt_native_id && pmu_type == hybrid_small)
4964+
return &x86_pmu.hybrid_pmu[i];
4965+
if (native_id == cmt_native_id && pmu_type == hybrid_tiny)
4966+
return &x86_pmu.hybrid_pmu[i];
4967+
}
49374968
}
49384969

49394970
return NULL;
@@ -5971,6 +6002,37 @@ static struct attribute *lnl_hybrid_events_attrs[] = {
59716002
NULL
59726003
};
59736004

6005+
/* The event string must be in PMU IDX order. */
6006+
EVENT_ATTR_STR_HYBRID(topdown-retiring,
6007+
td_retiring_arl_h,
6008+
"event=0xc2,umask=0x02;event=0x00,umask=0x80;event=0xc2,umask=0x0",
6009+
hybrid_big_small_tiny);
6010+
EVENT_ATTR_STR_HYBRID(topdown-bad-spec,
6011+
td_bad_spec_arl_h,
6012+
"event=0x73,umask=0x0;event=0x00,umask=0x81;event=0x73,umask=0x0",
6013+
hybrid_big_small_tiny);
6014+
EVENT_ATTR_STR_HYBRID(topdown-fe-bound,
6015+
td_fe_bound_arl_h,
6016+
"event=0x9c,umask=0x01;event=0x00,umask=0x82;event=0x71,umask=0x0",
6017+
hybrid_big_small_tiny);
6018+
EVENT_ATTR_STR_HYBRID(topdown-be-bound,
6019+
td_be_bound_arl_h,
6020+
"event=0xa4,umask=0x02;event=0x00,umask=0x83;event=0x74,umask=0x0",
6021+
hybrid_big_small_tiny);
6022+
6023+
static struct attribute *arl_h_hybrid_events_attrs[] = {
6024+
EVENT_PTR(slots_adl),
6025+
EVENT_PTR(td_retiring_arl_h),
6026+
EVENT_PTR(td_bad_spec_arl_h),
6027+
EVENT_PTR(td_fe_bound_arl_h),
6028+
EVENT_PTR(td_be_bound_arl_h),
6029+
EVENT_PTR(td_heavy_ops_adl),
6030+
EVENT_PTR(td_br_mis_adl),
6031+
EVENT_PTR(td_fetch_lat_adl),
6032+
EVENT_PTR(td_mem_bound_adl),
6033+
NULL,
6034+
};
6035+
59746036
/* Must be in IDX order */
59756037
EVENT_ATTR_STR_HYBRID(mem-loads, mem_ld_adl, "event=0xd0,umask=0x5,ldlat=3;event=0xcd,umask=0x1,ldlat=3", hybrid_big_small);
59766038
EVENT_ATTR_STR_HYBRID(mem-stores, mem_st_adl, "event=0xd0,umask=0x6;event=0xcd,umask=0x2", hybrid_big_small);
@@ -5989,6 +6051,21 @@ static struct attribute *mtl_hybrid_mem_attrs[] = {
59896051
NULL
59906052
};
59916053

6054+
EVENT_ATTR_STR_HYBRID(mem-loads,
6055+
mem_ld_arl_h,
6056+
"event=0xd0,umask=0x5,ldlat=3;event=0xcd,umask=0x1,ldlat=3;event=0xd0,umask=0x5,ldlat=3",
6057+
hybrid_big_small_tiny);
6058+
EVENT_ATTR_STR_HYBRID(mem-stores,
6059+
mem_st_arl_h,
6060+
"event=0xd0,umask=0x6;event=0xcd,umask=0x2;event=0xd0,umask=0x6",
6061+
hybrid_big_small_tiny);
6062+
6063+
static struct attribute *arl_h_hybrid_mem_attrs[] = {
6064+
EVENT_PTR(mem_ld_arl_h),
6065+
EVENT_PTR(mem_st_arl_h),
6066+
NULL,
6067+
};
6068+
59926069
EVENT_ATTR_STR_HYBRID(tx-start, tx_start_adl, "event=0xc9,umask=0x1", hybrid_big);
59936070
EVENT_ATTR_STR_HYBRID(tx-commit, tx_commit_adl, "event=0xc9,umask=0x2", hybrid_big);
59946071
EVENT_ATTR_STR_HYBRID(tx-abort, tx_abort_adl, "event=0xc9,umask=0x4", hybrid_big);
@@ -6012,8 +6089,8 @@ static struct attribute *adl_hybrid_tsx_attrs[] = {
60126089

60136090
FORMAT_ATTR_HYBRID(in_tx, hybrid_big);
60146091
FORMAT_ATTR_HYBRID(in_tx_cp, hybrid_big);
6015-
FORMAT_ATTR_HYBRID(offcore_rsp, hybrid_big_small);
6016-
FORMAT_ATTR_HYBRID(ldlat, hybrid_big_small);
6092+
FORMAT_ATTR_HYBRID(offcore_rsp, hybrid_big_small_tiny);
6093+
FORMAT_ATTR_HYBRID(ldlat, hybrid_big_small_tiny);
60176094
FORMAT_ATTR_HYBRID(frontend, hybrid_big);
60186095

60196096
#define ADL_HYBRID_RTM_FORMAT_ATTR \
@@ -6036,7 +6113,7 @@ static struct attribute *adl_hybrid_extra_attr[] = {
60366113
NULL
60376114
};
60386115

6039-
FORMAT_ATTR_HYBRID(snoop_rsp, hybrid_small);
6116+
FORMAT_ATTR_HYBRID(snoop_rsp, hybrid_small_tiny);
60406117

60416118
static struct attribute *mtl_hybrid_extra_attr_rtm[] = {
60426119
ADL_HYBRID_RTM_FORMAT_ATTR,
@@ -6244,8 +6321,9 @@ static inline int intel_pmu_v6_addr_offset(int index, bool eventsel)
62446321
}
62456322

62466323
static const struct { enum hybrid_pmu_type id; char *name; } intel_hybrid_pmu_type_map[] __initconst = {
6247-
{ hybrid_small, "cpu_atom" },
6248-
{ hybrid_big, "cpu_core" },
6324+
{ hybrid_small, "cpu_atom" },
6325+
{ hybrid_big, "cpu_core" },
6326+
{ hybrid_tiny, "cpu_lowpower" },
62496327
};
62506328

62516329
static __always_inline int intel_pmu_init_hybrid(enum hybrid_pmu_type pmus)
@@ -6278,7 +6356,7 @@ static __always_inline int intel_pmu_init_hybrid(enum hybrid_pmu_type pmus)
62786356
0, x86_pmu_num_counters(&pmu->pmu), 0, 0);
62796357

62806358
pmu->intel_cap.capabilities = x86_pmu.intel_cap.capabilities;
6281-
if (pmu->pmu_type & hybrid_small) {
6359+
if (pmu->pmu_type & hybrid_small_tiny) {
62826360
pmu->intel_cap.perf_metrics = 0;
62836361
pmu->intel_cap.pebs_output_pt_available = 1;
62846362
pmu->mid_ack = true;
@@ -7118,6 +7196,37 @@ __init int intel_pmu_init(void)
71187196
name = "lunarlake_hybrid";
71197197
break;
71207198

7199+
case INTEL_ARROWLAKE_H:
7200+
intel_pmu_init_hybrid(hybrid_big_small_tiny);
7201+
7202+
x86_pmu.pebs_latency_data = arl_h_latency_data;
7203+
x86_pmu.get_event_constraints = arl_h_get_event_constraints;
7204+
x86_pmu.hw_config = arl_h_hw_config;
7205+
7206+
td_attr = arl_h_hybrid_events_attrs;
7207+
mem_attr = arl_h_hybrid_mem_attrs;
7208+
tsx_attr = adl_hybrid_tsx_attrs;
7209+
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
7210+
mtl_hybrid_extra_attr_rtm : mtl_hybrid_extra_attr;
7211+
7212+
/* Initialize big core specific PerfMon capabilities. */
7213+
pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX];
7214+
intel_pmu_init_lnc(&pmu->pmu);
7215+
7216+
/* Initialize Atom core specific PerfMon capabilities. */
7217+
pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_ATOM_IDX];
7218+
intel_pmu_init_skt(&pmu->pmu);
7219+
7220+
/* Initialize Lower Power Atom specific PerfMon capabilities. */
7221+
pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_TINY_IDX];
7222+
intel_pmu_init_grt(&pmu->pmu);
7223+
pmu->extra_regs = intel_cmt_extra_regs;
7224+
7225+
intel_pmu_pebs_data_source_arl_h();
7226+
pr_cont("ArrowLake-H Hybrid events, ");
7227+
name = "arrowlake_h_hybrid";
7228+
break;
7229+
71217230
default:
71227231
switch (x86_pmu.version) {
71237232
case 1:

arch/x86/events/intel/ds.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,17 @@ void __init intel_pmu_pebs_data_source_mtl(void)
176176
__intel_pmu_pebs_data_source_cmt(data_source);
177177
}
178178

179+
void __init intel_pmu_pebs_data_source_arl_h(void)
180+
{
181+
u64 *data_source;
182+
183+
intel_pmu_pebs_data_source_lnl();
184+
185+
data_source = x86_pmu.hybrid_pmu[X86_HYBRID_PMU_TINY_IDX].pebs_data_source;
186+
memcpy(data_source, pebs_data_source, sizeof(pebs_data_source));
187+
__intel_pmu_pebs_data_source_cmt(data_source);
188+
}
189+
179190
void __init intel_pmu_pebs_data_source_cmt(void)
180191
{
181192
__intel_pmu_pebs_data_source_cmt(pebs_data_source);
@@ -387,6 +398,16 @@ u64 lnl_latency_data(struct perf_event *event, u64 status)
387398
return lnc_latency_data(event, status);
388399
}
389400

401+
u64 arl_h_latency_data(struct perf_event *event, u64 status)
402+
{
403+
struct x86_hybrid_pmu *pmu = hybrid_pmu(event->pmu);
404+
405+
if (pmu->pmu_type == hybrid_tiny)
406+
return cmt_latency_data(event, status);
407+
408+
return lnl_latency_data(event, status);
409+
}
410+
390411
static u64 load_latency_data(struct perf_event *event, u64 status)
391412
{
392413
union intel_x86_pebs_dse dse;

arch/x86/events/perf_event.h

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -668,24 +668,38 @@ enum {
668668
#define PERF_PEBS_DATA_SOURCE_GRT_MAX 0x10
669669
#define PERF_PEBS_DATA_SOURCE_GRT_MASK (PERF_PEBS_DATA_SOURCE_GRT_MAX - 1)
670670

671+
/*
672+
* CPUID.1AH.EAX[31:0] uniquely identifies the microarchitecture
673+
* of the core. Bits 31-24 indicates its core type (Core or Atom)
674+
* and Bits [23:0] indicates the native model ID of the core.
675+
* Core type and native model ID are defined in below enumerations.
676+
*/
671677
enum hybrid_cpu_type {
672678
HYBRID_INTEL_NONE,
673679
HYBRID_INTEL_ATOM = 0x20,
674680
HYBRID_INTEL_CORE = 0x40,
675681
};
676682

683+
#define X86_HYBRID_PMU_ATOM_IDX 0
684+
#define X86_HYBRID_PMU_CORE_IDX 1
685+
#define X86_HYBRID_PMU_TINY_IDX 2
686+
677687
enum hybrid_pmu_type {
678688
not_hybrid,
679-
hybrid_small = BIT(0),
680-
hybrid_big = BIT(1),
681-
682-
hybrid_big_small = hybrid_big | hybrid_small, /* only used for matching */
689+
hybrid_small = BIT(X86_HYBRID_PMU_ATOM_IDX),
690+
hybrid_big = BIT(X86_HYBRID_PMU_CORE_IDX),
691+
hybrid_tiny = BIT(X86_HYBRID_PMU_TINY_IDX),
692+
693+
/* The belows are only used for matching */
694+
hybrid_big_small = hybrid_big | hybrid_small,
695+
hybrid_small_tiny = hybrid_small | hybrid_tiny,
696+
hybrid_big_small_tiny = hybrid_big | hybrid_small_tiny,
683697
};
684698

685-
#define X86_HYBRID_PMU_ATOM_IDX 0
686-
#define X86_HYBRID_PMU_CORE_IDX 1
687-
688-
#define X86_HYBRID_NUM_PMUS 2
699+
enum atom_native_id {
700+
cmt_native_id = 0x2, /* Crestmont */
701+
skt_native_id = 0x3, /* Skymont */
702+
};
689703

690704
struct x86_hybrid_pmu {
691705
struct pmu pmu;
@@ -1578,6 +1592,8 @@ u64 cmt_latency_data(struct perf_event *event, u64 status);
15781592

15791593
u64 lnl_latency_data(struct perf_event *event, u64 status);
15801594

1595+
u64 arl_h_latency_data(struct perf_event *event, u64 status);
1596+
15811597
extern struct event_constraint intel_core2_pebs_event_constraints[];
15821598

15831599
extern struct event_constraint intel_atom_pebs_event_constraints[];
@@ -1697,6 +1713,8 @@ void intel_pmu_pebs_data_source_grt(void);
16971713

16981714
void intel_pmu_pebs_data_source_mtl(void);
16991715

1716+
void intel_pmu_pebs_data_source_arl_h(void);
1717+
17001718
void intel_pmu_pebs_data_source_cmt(void);
17011719

17021720
void intel_pmu_pebs_data_source_lnl(void);

arch/x86/events/rapl.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,7 @@ static const struct x86_cpu_id rapl_model_match[] __initconst = {
846846
X86_MATCH_VFM(INTEL_METEORLAKE_L, &model_skl),
847847
X86_MATCH_VFM(INTEL_ARROWLAKE_H, &model_skl),
848848
X86_MATCH_VFM(INTEL_ARROWLAKE, &model_skl),
849+
X86_MATCH_VFM(INTEL_ARROWLAKE_U, &model_skl),
849850
X86_MATCH_VFM(INTEL_LUNARLAKE_M, &model_skl),
850851
{},
851852
};

arch/x86/include/asm/cpu.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ extern bool handle_user_split_lock(struct pt_regs *regs, long error_code);
3636
extern bool handle_guest_split_lock(unsigned long ip);
3737
extern void handle_bus_lock(struct pt_regs *regs);
3838
u8 get_this_hybrid_cpu_type(void);
39+
u32 get_this_hybrid_cpu_native_id(void);
3940
#else
4041
static inline void __init sld_setup(struct cpuinfo_x86 *c) {}
4142
static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code)
@@ -54,6 +55,11 @@ static inline u8 get_this_hybrid_cpu_type(void)
5455
{
5556
return 0;
5657
}
58+
59+
static inline u32 get_this_hybrid_cpu_native_id(void)
60+
{
61+
return 0;
62+
}
5763
#endif
5864
#ifdef CONFIG_IA32_FEAT_CTL
5965
void init_ia32_feat_ctl(struct cpuinfo_x86 *c);

arch/x86/kernel/cpu/intel.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,3 +1348,18 @@ u8 get_this_hybrid_cpu_type(void)
13481348

13491349
return cpuid_eax(0x0000001a) >> X86_HYBRID_CPU_TYPE_ID_SHIFT;
13501350
}
1351+
1352+
/**
1353+
* get_this_hybrid_cpu_native_id() - Get the native id of this hybrid CPU
1354+
*
1355+
* Returns the uarch native ID [23:0] of a CPU in a hybrid processor.
1356+
* If the processor is not hybrid, returns 0.
1357+
*/
1358+
u32 get_this_hybrid_cpu_native_id(void)
1359+
{
1360+
if (!cpu_feature_enabled(X86_FEATURE_HYBRID_CPU))
1361+
return 0;
1362+
1363+
return cpuid_eax(0x0000001a) &
1364+
(BIT_ULL(X86_HYBRID_CPU_TYPE_ID_SHIFT) - 1);
1365+
}

0 commit comments

Comments
 (0)