Commit 1e7dcbfa authored by Oliver Upton's avatar Oliver Upton
Browse files

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: default avatarJanne Grunau <j@jannau.net>
Reviewed-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250305202641.428114-12-oliver.upton@linux.dev


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent bed9b8ec
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -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
@@ -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);

@@ -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);
+4 −0
Original line number Diff line number Diff line
@@ -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