Skip to content

Commit 823437e

Browse files
committed
Merge branch 'perf/m1-guest-events' of git://git.kernel.org/pub/scm/linux/kernel/git/oupton/linux into for-next/perf
Pull Apple-M1 PMU driver changes from Oliver Upton, which form a prefix of the series in the KVM/Arm tree that allows the PMU to be virtualised. Sort of, anyway. * 'perf/m1-guest-events' of git://git.kernel.org/pub/scm/linux/kernel/git/oupton/linux: drivers/perf: apple_m1: Support host/guest event filtering drivers/perf: apple_m1: Refactor event select/filter configuration
2 parents 7f35b42 + 46573d9 commit 823437e

File tree

2 files changed

+46
-21
lines changed

2 files changed

+46
-21
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: 45 additions & 21 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
/*
@@ -327,11 +329,10 @@ static void m1_pmu_disable_counter_interrupt(unsigned int index)
327329
__m1_pmu_enable_counter_interrupt(index, false);
328330
}
329331

330-
static void m1_pmu_configure_counter(unsigned int index, u8 event,
331-
bool user, bool kernel)
332+
static void __m1_pmu_configure_event_filter(unsigned int index, bool user,
333+
bool kernel, bool host)
332334
{
333-
u64 val, user_bit, kernel_bit;
334-
int shift;
335+
u64 clear, set, user_bit, kernel_bit;
335336

336337
switch (index) {
337338
case 0 ... 7:
@@ -346,19 +347,27 @@ static void m1_pmu_configure_counter(unsigned int index, u8 event,
346347
BUG();
347348
}
348349

349-
val = read_sysreg_s(SYS_IMP_APL_PMCR1_EL1);
350-
350+
clear = set = 0;
351351
if (user)
352-
val |= user_bit;
352+
set |= user_bit;
353353
else
354-
val &= ~user_bit;
354+
clear |= user_bit;
355355

356356
if (kernel)
357-
val |= kernel_bit;
357+
set |= kernel_bit;
358358
else
359-
val &= ~kernel_bit;
359+
clear |= kernel_bit;
360360

361-
write_sysreg_s(val, SYS_IMP_APL_PMCR1_EL1);
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);
365+
}
366+
367+
static void __m1_pmu_configure_eventsel(unsigned int index, u8 event)
368+
{
369+
u64 clear = 0, set = 0;
370+
int shift;
362371

363372
/*
364373
* Counters 0 and 1 have fixed events. For anything else,
@@ -371,21 +380,32 @@ static void m1_pmu_configure_counter(unsigned int index, u8 event,
371380
break;
372381
case 2 ... 5:
373382
shift = (index - 2) * 8;
374-
val = read_sysreg_s(SYS_IMP_APL_PMESR0_EL1);
375-
val &= ~((u64)0xff << shift);
376-
val |= (u64)event << shift;
377-
write_sysreg_s(val, SYS_IMP_APL_PMESR0_EL1);
383+
clear |= (u64)0xff << shift;
384+
set |= (u64)event << shift;
385+
sysreg_clear_set_s(SYS_IMP_APL_PMESR0_EL1, clear, set);
378386
break;
379387
case 6 ... 9:
380388
shift = (index - 6) * 8;
381-
val = read_sysreg_s(SYS_IMP_APL_PMESR1_EL1);
382-
val &= ~((u64)0xff << shift);
383-
val |= (u64)event << shift;
384-
write_sysreg_s(val, SYS_IMP_APL_PMESR1_EL1);
389+
clear |= (u64)0xff << shift;
390+
set |= (u64)event << shift;
391+
sysreg_clear_set_s(SYS_IMP_APL_PMESR1_EL1, clear, set);
385392
break;
386393
}
387394
}
388395

396+
static void m1_pmu_configure_counter(unsigned int index, unsigned long config_base)
397+
{
398+
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;
401+
bool user = config_base & M1_PMU_CFG_COUNT_USER;
402+
u8 evt = config_base & M1_PMU_CFG_EVENT;
403+
404+
__m1_pmu_configure_event_filter(index, user && host, kernel && host, true);
405+
__m1_pmu_configure_event_filter(index, user && guest, kernel && guest, false);
406+
__m1_pmu_configure_eventsel(index, evt);
407+
}
408+
389409
/* arm_pmu backend */
390410
static void m1_pmu_enable_event(struct perf_event *event)
391411
{
@@ -396,7 +416,7 @@ static void m1_pmu_enable_event(struct perf_event *event)
396416
user = event->hw.config_base & M1_PMU_CFG_COUNT_USER;
397417
kernel = event->hw.config_base & M1_PMU_CFG_COUNT_KERNEL;
398418

399-
m1_pmu_configure_counter(event->hw.idx, evt, user, kernel);
419+
m1_pmu_configure_counter(event->hw.idx, event->hw.config_base);
400420
m1_pmu_enable_counter(event->hw.idx);
401421
m1_pmu_enable_counter_interrupt(event->hw.idx);
402422
isb();
@@ -554,14 +574,18 @@ static int m1_pmu_set_event_filter(struct hw_perf_event *event,
554574
{
555575
unsigned long config_base = 0;
556576

557-
if (!attr->exclude_guest) {
577+
if (!attr->exclude_guest && !is_kernel_in_hyp_mode()) {
558578
pr_debug("ARM performance counters do not support mode exclusion\n");
559579
return -EOPNOTSUPP;
560580
}
561581
if (!attr->exclude_kernel)
562582
config_base |= M1_PMU_CFG_COUNT_KERNEL;
563583
if (!attr->exclude_user)
564584
config_base |= M1_PMU_CFG_COUNT_USER;
585+
if (!attr->exclude_host)
586+
config_base |= M1_PMU_CFG_COUNT_HOST;
587+
if (!attr->exclude_guest)
588+
config_base |= M1_PMU_CFG_COUNT_GUEST;
565589

566590
event->config_base = config_base;
567591

0 commit comments

Comments
 (0)