Skip to content

Commit c82d28c

Browse files
author
Marc Zyngier
committed
KVM: arm64: PMU: Distinguish between 64bit counter and 64bit overflow
The PMU architecture makes a subtle difference between a 64bit counter and a counter that has a 64bit overflow. This is for example the case of the cycle counter, which can generate an overflow on a 32bit boundary if PMCR_EL0.LC==0 despite the accumulation being done on 64 bits. Use this distinction in the few cases where it matters in the code, as we will reuse this with PMUv3p5 long counters. Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent acdd8a4 commit c82d28c

File tree

1 file changed

+31
-12
lines changed

1 file changed

+31
-12
lines changed

arch/arm64/kvm/pmu-emul.c

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,20 @@ static u32 kvm_pmu_event_mask(struct kvm *kvm)
5050
* @select_idx: The counter index
5151
*/
5252
static bool kvm_pmu_idx_is_64bit(struct kvm_vcpu *vcpu, u64 select_idx)
53+
{
54+
return (select_idx == ARMV8_PMU_CYCLE_IDX);
55+
}
56+
57+
static bool kvm_pmu_idx_has_64bit_overflow(struct kvm_vcpu *vcpu, u64 select_idx)
5358
{
5459
return (select_idx == ARMV8_PMU_CYCLE_IDX &&
5560
__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_LC);
5661
}
5762

5863
static bool kvm_pmu_counter_can_chain(struct kvm_vcpu *vcpu, u64 idx)
5964
{
60-
return (!(idx & 1) && (idx + 1) < ARMV8_PMU_CYCLE_IDX);
65+
return (!(idx & 1) && (idx + 1) < ARMV8_PMU_CYCLE_IDX &&
66+
!kvm_pmu_idx_has_64bit_overflow(vcpu, idx));
6167
}
6268

6369
static struct kvm_vcpu *kvm_pmc_to_vcpu(struct kvm_pmc *pmc)
@@ -97,7 +103,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
97103
counter += perf_event_read_value(pmc->perf_event, &enabled,
98104
&running);
99105

100-
if (select_idx != ARMV8_PMU_CYCLE_IDX)
106+
if (!kvm_pmu_idx_is_64bit(vcpu, select_idx))
101107
counter = lower_32_bits(counter);
102108

103109
return counter;
@@ -423,6 +429,23 @@ static void kvm_pmu_counter_increment(struct kvm_vcpu *vcpu,
423429
}
424430
}
425431

432+
/* Compute the sample period for a given counter value */
433+
static u64 compute_period(struct kvm_vcpu *vcpu, u64 select_idx, u64 counter)
434+
{
435+
u64 val;
436+
437+
if (kvm_pmu_idx_is_64bit(vcpu, select_idx)) {
438+
if (!kvm_pmu_idx_has_64bit_overflow(vcpu, select_idx))
439+
val = -(counter & GENMASK(31, 0));
440+
else
441+
val = (-counter) & GENMASK(63, 0);
442+
} else {
443+
val = (-counter) & GENMASK(31, 0);
444+
}
445+
446+
return val;
447+
}
448+
426449
/**
427450
* When the perf event overflows, set the overflow status and inform the vcpu.
428451
*/
@@ -442,10 +465,7 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
442465
* Reset the sample period to the architectural limit,
443466
* i.e. the point where the counter overflows.
444467
*/
445-
period = -(local64_read(&perf_event->count));
446-
447-
if (!kvm_pmu_idx_is_64bit(vcpu, pmc->idx))
448-
period &= GENMASK(31, 0);
468+
period = compute_period(vcpu, idx, local64_read(&perf_event->count));
449469

450470
local64_set(&perf_event->hw.period_left, 0);
451471
perf_event->attr.sample_period = period;
@@ -571,14 +591,13 @@ static void kvm_pmu_create_perf_event(struct kvm_vcpu *vcpu, u64 select_idx)
571591

572592
/*
573593
* If counting with a 64bit counter, advertise it to the perf
574-
* code, carefully dealing with the initial sample period.
594+
* code, carefully dealing with the initial sample period
595+
* which also depends on the overflow.
575596
*/
576-
if (kvm_pmu_idx_is_64bit(vcpu, select_idx)) {
597+
if (kvm_pmu_idx_is_64bit(vcpu, select_idx))
577598
attr.config1 |= PERF_ATTR_CFG1_COUNTER_64BIT;
578-
attr.sample_period = (-counter) & GENMASK(63, 0);
579-
} else {
580-
attr.sample_period = (-counter) & GENMASK(31, 0);
581-
}
599+
600+
attr.sample_period = compute_period(vcpu, select_idx, counter);
582601

583602
event = perf_event_create_kernel_counter(&attr, -1, current,
584603
kvm_pmu_perf_overflow, pmc);

0 commit comments

Comments
 (0)