Skip to content

Commit

Permalink
drivers/perf: apple_m1: Provide helper for mapping PMUv3 events
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Oliver Upton committed Mar 11, 2025
1 parent 1e7dcbf commit 2d00cab
Showing 1 changed file with 35 additions and 0 deletions.
35 changes: 35 additions & 0 deletions drivers/perf/apple_m1_cpu_pmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include <linux/of.h>
#include <linux/perf/arm_pmu.h>
#include <linux/perf/arm_pmuv3.h>
#include <linux/platform_device.h>

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

#define M1_PMUV3_EVENT_MAP(pmuv3_event, m1_event) \
[ARMV8_PMUV3_PERFCTR_##pmuv3_event] = M1_PMU_PERFCTR_##m1_event

static const u16 m1_pmu_pmceid_map[ARMV8_PMUV3_MAX_COMMON_EVENTS] = {
[0 ... ARMV8_PMUV3_MAX_COMMON_EVENTS - 1] = HW_OP_UNSUPPORTED,
M1_PMUV3_EVENT_MAP(INST_RETIRED, INST_ALL),
M1_PMUV3_EVENT_MAP(CPU_CYCLES, CORE_ACTIVE_CYCLE),
M1_PMUV3_EVENT_MAP(BR_RETIRED, INST_BRANCH),
M1_PMUV3_EVENT_MAP(BR_MIS_PRED_RETIRED, BRANCH_MISPRED_NONSPEC),
};

/* sysfs definitions */
static ssize_t m1_pmu_events_sysfs_show(struct device *dev,
struct device_attribute *attr,
Expand Down Expand Up @@ -558,6 +570,26 @@ static int m2_pmu_map_event(struct perf_event *event)
return armpmu_map_event(event, &m1_pmu_perf_map, NULL, M1_PMU_CFG_EVENT);
}

static int m1_pmu_map_pmuv3_event(unsigned int eventsel)
{
u16 m1_event = HW_OP_UNSUPPORTED;

if (eventsel < ARMV8_PMUV3_MAX_COMMON_EVENTS)
m1_event = m1_pmu_pmceid_map[eventsel];

return m1_event == HW_OP_UNSUPPORTED ? -EOPNOTSUPP : m1_event;
}

static void m1_pmu_init_pmceid(struct arm_pmu *pmu)
{
unsigned int event;

for (event = 0; event < ARMV8_PMUV3_MAX_COMMON_EVENTS; event++) {
if (m1_pmu_map_pmuv3_event(event) >= 0)
set_bit(event, pmu->pmceid_bitmap);
}
}

static void m1_pmu_reset(void *info)
{
int i;
Expand Down Expand Up @@ -618,6 +650,9 @@ static int m1_pmu_init(struct arm_pmu *cpu_pmu, u32 flags)
cpu_pmu->reset = m1_pmu_reset;
cpu_pmu->set_event_filter = m1_pmu_set_event_filter;

cpu_pmu->map_pmuv3_event = m1_pmu_map_pmuv3_event;
m1_pmu_init_pmceid(cpu_pmu);

bitmap_set(cpu_pmu->cntr_mask, 0, M1_PMU_NR_COUNTERS);
cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = &m1_pmu_events_attr_group;
cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = &m1_pmu_format_attr_group;
Expand Down

0 comments on commit 2d00cab

Please sign in to comment.