Skip to content

Commit aa76829

Browse files
eaugerMarc Zyngier
authored andcommitted
KVM: arm64: pmu: Fix chained SW_INCR counters
At the moment a SW_INCR counter always overflows on 32-bit boundary, independently on whether the n+1th counter is programmed as CHAIN. Check whether the SW_INCR counter is a 64b counter and if so, implement the 64b logic. Fixes: 80f393a ("KVM: arm/arm64: Support chained PMU counters") Signed-off-by: Eric Auger <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 76c9fc5 commit aa76829

File tree

1 file changed

+30
-13
lines changed

1 file changed

+30
-13
lines changed

virt/kvm/arm/pmu.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -477,28 +477,45 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
477477
*/
478478
void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
479479
{
480+
struct kvm_pmu *pmu = &vcpu->arch.pmu;
480481
int i;
481-
u64 type, enable, reg;
482-
483-
if (val == 0)
484-
return;
485482

486483
if (!(__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E))
487484
return;
488485

489-
enable = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
486+
/* Weed out disabled counters */
487+
val &= __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
488+
490489
for (i = 0; i < ARMV8_PMU_CYCLE_IDX; i++) {
490+
u64 type, reg;
491+
491492
if (!(val & BIT(i)))
492493
continue;
493-
type = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
494-
& ARMV8_PMU_EVTYPE_EVENT;
495-
if ((type == ARMV8_PMUV3_PERFCTR_SW_INCR)
496-
&& (enable & BIT(i))) {
497-
reg = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
494+
495+
/* PMSWINC only applies to ... SW_INC! */
496+
type = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i);
497+
type &= ARMV8_PMU_EVTYPE_EVENT;
498+
if (type != ARMV8_PMUV3_PERFCTR_SW_INCR)
499+
continue;
500+
501+
/* increment this even SW_INC counter */
502+
reg = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
503+
reg = lower_32_bits(reg);
504+
__vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
505+
506+
if (reg) /* no overflow on the low part */
507+
continue;
508+
509+
if (kvm_pmu_pmc_is_chained(&pmu->pmc[i])) {
510+
/* increment the high counter */
511+
reg = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i + 1) + 1;
498512
reg = lower_32_bits(reg);
499-
__vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
500-
if (!reg)
501-
__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
513+
__vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i + 1) = reg;
514+
if (!reg) /* mark overflow on the high counter */
515+
__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i + 1);
516+
} else {
517+
/* mark overflow on low counter */
518+
__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
502519
}
503520
}
504521
}

0 commit comments

Comments
 (0)