Skip to content

Commit

Permalink
KVM: arm64: Remap PMUv3 events onto hardware
Browse files Browse the repository at this point in the history
Map PMUv3 event IDs onto hardware, if the driver exposes such a helper.
This is expected to be quite rare, and only useful for non-PMUv3 hardware.

Tested-by: Janne Grunau <j@jannau.net>
Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250305202641.428114-12-oliver.upton@linux.dev
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
  • Loading branch information
Oliver Upton committed Mar 11, 2025
1 parent bed9b8e commit 1e7dcbf
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 1 deletion.
25 changes: 24 additions & 1 deletion arch/arm64/kvm/pmu-emul.c
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,20 @@ static bool kvm_pmc_counts_at_el2(struct kvm_pmc *pmc)
return kvm_pmc_read_evtreg(pmc) & ARMV8_PMU_INCLUDE_EL2;
}

static int kvm_map_pmu_event(struct kvm *kvm, unsigned int eventsel)
{
struct arm_pmu *pmu = kvm->arch.arm_pmu;

/*
* The CPU PMU likely isn't PMUv3; let the driver provide a mapping
* for the guest's PMUv3 event ID.
*/
if (unlikely(pmu->map_pmuv3_event))
return pmu->map_pmuv3_event(eventsel);

return eventsel;
}

/**
* kvm_pmu_create_perf_event - create a perf event for a counter
* @pmc: Counter context
Expand All @@ -687,7 +701,8 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
struct arm_pmu *arm_pmu = vcpu->kvm->arch.arm_pmu;
struct perf_event *event;
struct perf_event_attr attr;
u64 eventsel, evtreg;
int eventsel;
u64 evtreg;

evtreg = kvm_pmc_read_evtreg(pmc);

Expand All @@ -713,6 +728,14 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
!test_bit(eventsel, vcpu->kvm->arch.pmu_filter))
return;

/*
* Don't create an event if we're running on hardware that requires
* PMUv3 event translation and we couldn't find a valid mapping.
*/
eventsel = kvm_map_pmu_event(vcpu->kvm, eventsel);
if (eventsel < 0)
return;

memset(&attr, 0, sizeof(struct perf_event_attr));
attr.type = arm_pmu->pmu.type;
attr.size = sizeof(attr);
Expand Down
4 changes: 4 additions & 0 deletions include/linux/perf/arm_pmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ struct arm_pmu {
void (*stop)(struct arm_pmu *);
void (*reset)(void *);
int (*map_event)(struct perf_event *event);
/*
* Called by KVM to map the PMUv3 event space onto non-PMUv3 hardware.
*/
int (*map_pmuv3_event)(unsigned int eventsel);
DECLARE_BITMAP(cntr_mask, ARMPMU_MAX_HWEVENTS);
bool secure_access; /* 32-bit ARM only */
#define ARMV8_PMUV3_MAX_COMMON_EVENTS 0x40
Expand Down

0 comments on commit 1e7dcbf

Please sign in to comment.