Skip to content

Commit 46573d9

Browse files
committed
drivers/perf: apple_m1: Support host/guest event filtering
The PMU appears to have a separate register for filtering 'guest' exception levels (i.e. EL1 and !ELIsInHost(EL0)) which has the same layout as PMCR1_EL1. Conveniently, there exists a VHE register alias (PMCR1_EL12) that can be used to configure it. Support guest events by programming the EL12 register with the intended guest kernel/userspace filters. Limit support for guest events to VHE (i.e. kernel running at EL2), as it avoids involving KVM to context switch PMU registers. VHE is the only supported mode on M* parts anyway, so this isn't an actual feature limitation. Tested-by: Janne Grunau <j@jannau.net> Reviewed-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20250305202641.428114-3-oliver.upton@linux.dev Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent 75ecffc commit 46573d9

File tree

2 files changed

+17
-4
lines changed

2 files changed

+17
-4
lines changed

arch/arm64/include/asm/apple_m1_pmu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#define PMCR0_PMI_ENABLE_8_9 GENMASK(45, 44)
3838

3939
#define SYS_IMP_APL_PMCR1_EL1 sys_reg(3, 1, 15, 1, 0)
40+
#define SYS_IMP_APL_PMCR1_EL12 sys_reg(3, 1, 15, 7, 2)
4041
#define PMCR1_COUNT_A64_EL0_0_7 GENMASK(15, 8)
4142
#define PMCR1_COUNT_A64_EL1_0_7 GENMASK(23, 16)
4243
#define PMCR1_COUNT_A64_EL0_8_9 GENMASK(41, 40)

drivers/perf/apple_m1_cpu_pmu.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ enum m1_pmu_events {
120120
*/
121121
M1_PMU_CFG_COUNT_USER = BIT(8),
122122
M1_PMU_CFG_COUNT_KERNEL = BIT(9),
123+
M1_PMU_CFG_COUNT_HOST = BIT(10),
124+
M1_PMU_CFG_COUNT_GUEST = BIT(11),
123125
};
124126

125127
/*
@@ -328,7 +330,7 @@ static void m1_pmu_disable_counter_interrupt(unsigned int index)
328330
}
329331

330332
static void __m1_pmu_configure_event_filter(unsigned int index, bool user,
331-
bool kernel)
333+
bool kernel, bool host)
332334
{
333335
u64 clear, set, user_bit, kernel_bit;
334336

@@ -356,7 +358,10 @@ static void __m1_pmu_configure_event_filter(unsigned int index, bool user,
356358
else
357359
clear |= kernel_bit;
358360

359-
sysreg_clear_set_s(SYS_IMP_APL_PMCR1_EL1, clear, set);
361+
if (host)
362+
sysreg_clear_set_s(SYS_IMP_APL_PMCR1_EL1, clear, set);
363+
else if (is_kernel_in_hyp_mode())
364+
sysreg_clear_set_s(SYS_IMP_APL_PMCR1_EL12, clear, set);
360365
}
361366

362367
static void __m1_pmu_configure_eventsel(unsigned int index, u8 event)
@@ -391,10 +396,13 @@ static void __m1_pmu_configure_eventsel(unsigned int index, u8 event)
391396
static void m1_pmu_configure_counter(unsigned int index, unsigned long config_base)
392397
{
393398
bool kernel = config_base & M1_PMU_CFG_COUNT_KERNEL;
399+
bool guest = config_base & M1_PMU_CFG_COUNT_GUEST;
400+
bool host = config_base & M1_PMU_CFG_COUNT_HOST;
394401
bool user = config_base & M1_PMU_CFG_COUNT_USER;
395402
u8 evt = config_base & M1_PMU_CFG_EVENT;
396403

397-
__m1_pmu_configure_event_filter(index, user, kernel);
404+
__m1_pmu_configure_event_filter(index, user && host, kernel && host, true);
405+
__m1_pmu_configure_event_filter(index, user && guest, kernel && guest, false);
398406
__m1_pmu_configure_eventsel(index, evt);
399407
}
400408

@@ -570,14 +578,18 @@ static int m1_pmu_set_event_filter(struct hw_perf_event *event,
570578
{
571579
unsigned long config_base = 0;
572580

573-
if (!attr->exclude_guest) {
581+
if (!attr->exclude_guest && !is_kernel_in_hyp_mode()) {
574582
pr_debug("ARM performance counters do not support mode exclusion\n");
575583
return -EOPNOTSUPP;
576584
}
577585
if (!attr->exclude_kernel)
578586
config_base |= M1_PMU_CFG_COUNT_KERNEL;
579587
if (!attr->exclude_user)
580588
config_base |= M1_PMU_CFG_COUNT_USER;
589+
if (!attr->exclude_host)
590+
config_base |= M1_PMU_CFG_COUNT_HOST;
591+
if (!attr->exclude_guest)
592+
config_base |= M1_PMU_CFG_COUNT_GUEST;
581593

582594
event->config_base = config_base;
583595

0 commit comments

Comments
 (0)