summaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorAndrew Murray <andrew.murray@arm.com>2019-06-17 15:01:03 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2019-07-05 08:56:14 -0400
commit30d97754b2d1bc4fd20f27c25fed92fc7ce39ce3 (patch)
treeea0c47cbc46a38bef2edd0373e56d675be9acd5d /virt
parent6f4d2a0b0b1e9a1f7594e666eebad98372901818 (diff)
KVM: arm/arm64: Re-create event when setting counter value
The perf event sample_period is currently set based upon the current counter value, when PMXEVTYPER is written to and the perf event is created. However the user may choose to write the type before the counter value in which case sample_period will be set incorrectly. Let's instead decouple event creation from PMXEVTYPER and (re)create the event in either suitation. Signed-off-by: Andrew Murray <andrew.murray@arm.com> Reviewed-by: Julien Thierry <julien.thierry@arm.com> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/arm/pmu.c42
1 files changed, 33 insertions, 9 deletions
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index efdc7f6db6cd..f77643f4274c 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -13,6 +13,7 @@
13#include <kvm/arm_pmu.h> 13#include <kvm/arm_pmu.h>
14#include <kvm/arm_vgic.h> 14#include <kvm/arm_vgic.h>
15 15
16static void kvm_pmu_create_perf_event(struct kvm_vcpu *vcpu, u64 select_idx);
16/** 17/**
17 * kvm_pmu_get_counter_value - get PMU counter value 18 * kvm_pmu_get_counter_value - get PMU counter value
18 * @vcpu: The vcpu pointer 19 * @vcpu: The vcpu pointer
@@ -51,6 +52,9 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val)
51 reg = (select_idx == ARMV8_PMU_CYCLE_IDX) 52 reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
52 ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx; 53 ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
53 __vcpu_sys_reg(vcpu, reg) += (s64)val - kvm_pmu_get_counter_value(vcpu, select_idx); 54 __vcpu_sys_reg(vcpu, reg) += (s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
55
56 /* Recreate the perf event to reflect the updated sample_period */
57 kvm_pmu_create_perf_event(vcpu, select_idx);
54} 58}
55 59
56/** 60/**
@@ -367,23 +371,21 @@ static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u64 select_idx)
367} 371}
368 372
369/** 373/**
370 * kvm_pmu_set_counter_event_type - set selected counter to monitor some event 374 * kvm_pmu_create_perf_event - create a perf event for a counter
371 * @vcpu: The vcpu pointer 375 * @vcpu: The vcpu pointer
372 * @data: The data guest writes to PMXEVTYPER_EL0
373 * @select_idx: The number of selected counter 376 * @select_idx: The number of selected counter
374 *
375 * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to count an
376 * event with given hardware event number. Here we call perf_event API to
377 * emulate this action and create a kernel perf event for it.
378 */ 377 */
379void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data, 378static void kvm_pmu_create_perf_event(struct kvm_vcpu *vcpu, u64 select_idx)
380 u64 select_idx)
381{ 379{
382 struct kvm_pmu *pmu = &vcpu->arch.pmu; 380 struct kvm_pmu *pmu = &vcpu->arch.pmu;
383 struct kvm_pmc *pmc = &pmu->pmc[select_idx]; 381 struct kvm_pmc *pmc = &pmu->pmc[select_idx];
384 struct perf_event *event; 382 struct perf_event *event;
385 struct perf_event_attr attr; 383 struct perf_event_attr attr;
386 u64 eventsel, counter; 384 u64 eventsel, counter, reg, data;
385
386 reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
387 ? PMCCFILTR_EL0 : PMEVTYPER0_EL0 + select_idx;
388 data = __vcpu_sys_reg(vcpu, reg);
387 389
388 kvm_pmu_stop_counter(vcpu, pmc); 390 kvm_pmu_stop_counter(vcpu, pmc);
389 eventsel = data & ARMV8_PMU_EVTYPE_EVENT; 391 eventsel = data & ARMV8_PMU_EVTYPE_EVENT;
@@ -420,6 +422,28 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
420 pmc->perf_event = event; 422 pmc->perf_event = event;
421} 423}
422 424
425/**
426 * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
427 * @vcpu: The vcpu pointer
428 * @data: The data guest writes to PMXEVTYPER_EL0
429 * @select_idx: The number of selected counter
430 *
431 * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to count an
432 * event with given hardware event number. Here we call perf_event API to
433 * emulate this action and create a kernel perf event for it.
434 */
435void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
436 u64 select_idx)
437{
438 u64 reg, event_type = data & ARMV8_PMU_EVTYPE_MASK;
439
440 reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
441 ? PMCCFILTR_EL0 : PMEVTYPER0_EL0 + select_idx;
442
443 __vcpu_sys_reg(vcpu, reg) = event_type;
444 kvm_pmu_create_perf_event(vcpu, select_idx);
445}
446
423bool kvm_arm_support_pmu_v3(void) 447bool kvm_arm_support_pmu_v3(void)
424{ 448{
425 /* 449 /*