Skip to content

Commit 1e7dcbf

Browse files
committed
KVM: arm64: Remap PMUv3 events onto hardware
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 <[email protected]> Reviewed-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent bed9b8e commit 1e7dcbf

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

arch/arm64/kvm/pmu-emul.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,20 @@ static bool kvm_pmc_counts_at_el2(struct kvm_pmc *pmc)
677677
return kvm_pmc_read_evtreg(pmc) & ARMV8_PMU_INCLUDE_EL2;
678678
}
679679

680+
static int kvm_map_pmu_event(struct kvm *kvm, unsigned int eventsel)
681+
{
682+
struct arm_pmu *pmu = kvm->arch.arm_pmu;
683+
684+
/*
685+
* The CPU PMU likely isn't PMUv3; let the driver provide a mapping
686+
* for the guest's PMUv3 event ID.
687+
*/
688+
if (unlikely(pmu->map_pmuv3_event))
689+
return pmu->map_pmuv3_event(eventsel);
690+
691+
return eventsel;
692+
}
693+
680694
/**
681695
* kvm_pmu_create_perf_event - create a perf event for a counter
682696
* @pmc: Counter context
@@ -687,7 +701,8 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
687701
struct arm_pmu *arm_pmu = vcpu->kvm->arch.arm_pmu;
688702
struct perf_event *event;
689703
struct perf_event_attr attr;
690-
u64 eventsel, evtreg;
704+
int eventsel;
705+
u64 evtreg;
691706

692707
evtreg = kvm_pmc_read_evtreg(pmc);
693708

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

731+
/*
732+
* Don't create an event if we're running on hardware that requires
733+
* PMUv3 event translation and we couldn't find a valid mapping.
734+
*/
735+
eventsel = kvm_map_pmu_event(vcpu->kvm, eventsel);
736+
if (eventsel < 0)
737+
return;
738+
716739
memset(&attr, 0, sizeof(struct perf_event_attr));
717740
attr.type = arm_pmu->pmu.type;
718741
attr.size = sizeof(attr);

include/linux/perf/arm_pmu.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ struct arm_pmu {
100100
void (*stop)(struct arm_pmu *);
101101
void (*reset)(void *);
102102
int (*map_event)(struct perf_event *event);
103+
/*
104+
* Called by KVM to map the PMUv3 event space onto non-PMUv3 hardware.
105+
*/
106+
int (*map_pmuv3_event)(unsigned int eventsel);
103107
DECLARE_BITMAP(cntr_mask, ARMPMU_MAX_HWEVENTS);
104108
bool secure_access; /* 32-bit ARM only */
105109
#define ARMV8_PMUV3_MAX_COMMON_EVENTS 0x40

0 commit comments

Comments
 (0)