Skip to content

Commit 2d00cab

Browse files
committed
drivers/perf: apple_m1: Provide helper for mapping PMUv3 events
Apple M* parts carry some IMP DEF traps for guest accesses to PMUv3 registers, even though the underlying hardware doesn't implement PMUv3. This means it is possible to virtualize PMUv3 for KVM guests. Add a helper for mapping common PMUv3 event IDs onto hardware event IDs, keeping the implementation-specific crud in the PMU driver rather than KVM proper. Populate the pmceid_bitmap based on the supported events so KVM can provide synthetic PMCEID* values to the guest. Tested-by: Janne Grunau <j@jannau.net> Reviewed-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20250305202641.428114-13-oliver.upton@linux.dev Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent 1e7dcbf commit 2d00cab

File tree

1 file changed

+35
-0
lines changed

1 file changed

+35
-0
lines changed

drivers/perf/apple_m1_cpu_pmu.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <linux/of.h>
1414
#include <linux/perf/arm_pmu.h>
15+
#include <linux/perf/arm_pmuv3.h>
1516
#include <linux/platform_device.h>
1617

1718
#include <asm/apple_m1_pmu.h>
@@ -174,6 +175,17 @@ static const unsigned m1_pmu_perf_map[PERF_COUNT_HW_MAX] = {
174175
[PERF_COUNT_HW_BRANCH_MISSES] = M1_PMU_PERFCTR_BRANCH_MISPRED_NONSPEC,
175176
};
176177

178+
#define M1_PMUV3_EVENT_MAP(pmuv3_event, m1_event) \
179+
[ARMV8_PMUV3_PERFCTR_##pmuv3_event] = M1_PMU_PERFCTR_##m1_event
180+
181+
static const u16 m1_pmu_pmceid_map[ARMV8_PMUV3_MAX_COMMON_EVENTS] = {
182+
[0 ... ARMV8_PMUV3_MAX_COMMON_EVENTS - 1] = HW_OP_UNSUPPORTED,
183+
M1_PMUV3_EVENT_MAP(INST_RETIRED, INST_ALL),
184+
M1_PMUV3_EVENT_MAP(CPU_CYCLES, CORE_ACTIVE_CYCLE),
185+
M1_PMUV3_EVENT_MAP(BR_RETIRED, INST_BRANCH),
186+
M1_PMUV3_EVENT_MAP(BR_MIS_PRED_RETIRED, BRANCH_MISPRED_NONSPEC),
187+
};
188+
177189
/* sysfs definitions */
178190
static ssize_t m1_pmu_events_sysfs_show(struct device *dev,
179191
struct device_attribute *attr,
@@ -558,6 +570,26 @@ static int m2_pmu_map_event(struct perf_event *event)
558570
return armpmu_map_event(event, &m1_pmu_perf_map, NULL, M1_PMU_CFG_EVENT);
559571
}
560572

573+
static int m1_pmu_map_pmuv3_event(unsigned int eventsel)
574+
{
575+
u16 m1_event = HW_OP_UNSUPPORTED;
576+
577+
if (eventsel < ARMV8_PMUV3_MAX_COMMON_EVENTS)
578+
m1_event = m1_pmu_pmceid_map[eventsel];
579+
580+
return m1_event == HW_OP_UNSUPPORTED ? -EOPNOTSUPP : m1_event;
581+
}
582+
583+
static void m1_pmu_init_pmceid(struct arm_pmu *pmu)
584+
{
585+
unsigned int event;
586+
587+
for (event = 0; event < ARMV8_PMUV3_MAX_COMMON_EVENTS; event++) {
588+
if (m1_pmu_map_pmuv3_event(event) >= 0)
589+
set_bit(event, pmu->pmceid_bitmap);
590+
}
591+
}
592+
561593
static void m1_pmu_reset(void *info)
562594
{
563595
int i;
@@ -618,6 +650,9 @@ static int m1_pmu_init(struct arm_pmu *cpu_pmu, u32 flags)
618650
cpu_pmu->reset = m1_pmu_reset;
619651
cpu_pmu->set_event_filter = m1_pmu_set_event_filter;
620652

653+
cpu_pmu->map_pmuv3_event = m1_pmu_map_pmuv3_event;
654+
m1_pmu_init_pmceid(cpu_pmu);
655+
621656
bitmap_set(cpu_pmu->cntr_mask, 0, M1_PMU_NR_COUNTERS);
622657
cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
623658
cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = &m1_pmu_format_attr_group;

0 commit comments

Comments
 (0)