Skip to content

Commit bdb9594

Browse files
ouptonjannau
authored andcommitted
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. Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent 984a9f1 commit bdb9594

2 files changed

Lines changed: 33 additions & 0 deletions

File tree

drivers/perf/apple_m1_cpu_pmu.c

Lines changed: 32 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,14 @@ 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 unsigned int 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(CPU_CYCLES, CORE_ACTIVE_CYCLE),
184+
};
185+
177186
/* sysfs definitions */
178187
static ssize_t m1_pmu_events_sysfs_show(struct device *dev,
179188
struct device_attribute *attr,
@@ -558,6 +567,26 @@ static int m2_pmu_map_event(struct perf_event *event)
558567
return armpmu_map_event(event, &m1_pmu_perf_map, NULL, M1_PMU_CFG_EVENT);
559568
}
560569

570+
static int m1_pmu_map_pmuv3_event(unsigned int eventsel)
571+
{
572+
int m1_event = HW_OP_UNSUPPORTED;
573+
574+
if (eventsel < ARMV8_PMUV3_MAX_COMMON_EVENTS)
575+
m1_event = m1_pmu_pmceid_map[eventsel];
576+
577+
return m1_event == HW_OP_UNSUPPORTED ? -EOPNOTSUPP : m1_event;
578+
}
579+
580+
static void m1_pmu_init_pmceid(struct arm_pmu *pmu)
581+
{
582+
unsigned int event;
583+
584+
for (event = 0; event < ARMV8_PMUV3_MAX_COMMON_EVENTS; event++) {
585+
if (m1_pmu_map_pmuv3_event(event) >= 0)
586+
set_bit(event, pmu->pmceid_bitmap);
587+
}
588+
}
589+
561590
static void m1_pmu_reset(void *info)
562591
{
563592
int i;
@@ -618,6 +647,9 @@ static int m1_pmu_init(struct arm_pmu *cpu_pmu, u32 flags)
618647
cpu_pmu->reset = m1_pmu_reset;
619648
cpu_pmu->set_event_filter = m1_pmu_set_event_filter;
620649

650+
cpu_pmu->map_pmuv3_event = m1_pmu_map_pmuv3_event;
651+
m1_pmu_init_pmceid(cpu_pmu);
652+
621653
bitmap_set(cpu_pmu->cntr_mask, 0, M1_PMU_NR_COUNTERS);
622654
cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
623655
cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = &m1_pmu_format_attr_group;

include/linux/perf/arm_pmu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ struct arm_pmu {
100100
void (*stop)(struct arm_pmu *);
101101
void (*reset)(void *);
102102
int (*map_event)(struct perf_event *event);
103+
int (*map_pmuv3_event)(unsigned int eventsel);
103104
DECLARE_BITMAP(cntr_mask, ARMPMU_MAX_HWEVENTS);
104105
bool secure_access; /* 32-bit ARM only */
105106
#define ARMV8_PMUV3_MAX_COMMON_EVENTS 0x40

0 commit comments

Comments
 (0)