kvm_reset_sys_regs() resets PMCR_EL0, PMEVTYPERn_EL0, PMCCFILTR_EL0, and MDCR_EL2 before requesting a PMU reload. A reload reuses existing perf events even when their sample periods, event selections, or filters no longer match the reset system registers. Add a deferred event-recreation request. It stops existing events on the vCPU thread before reprogramming counters. Use it during system-register reset so the next vCPU run rebuilds all backing events from reset state. Fixes: fe53538069bb ("KVM: arm64: PMU: Reload when resetting") Assisted-by: Codex:gpt-5.6-sol Signed-off-by: Akihiko Odaki --- arch/arm64/kvm/pmu-emul.c | 15 +++++++++++++++ arch/arm64/kvm/sys_regs.c | 2 +- include/kvm/arm_pmu.h | 3 +++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index a5ccb6ae44d5..8530cc907b56 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -571,6 +571,12 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) kvm_pmu_counter_increment(vcpu, val, ARMV8_PMUV3_PERFCTR_SW_INCR); } +void kvm_pmu_request_recreate(struct kvm_vcpu *vcpu) +{ + vcpu->arch.pmu.events_need_recreate = true; + kvm_make_request(KVM_REQ_RELOAD_PMU, vcpu); +} + /** * kvm_pmu_handle_pmcr - handle PMCR register * @vcpu: The vcpu pointer @@ -900,7 +906,16 @@ u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1) void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu) { + struct kvm_pmu *pmu = &vcpu->arch.pmu; u64 mask = kvm_pmu_implemented_counter_mask(vcpu); + int i; + + if (pmu->events_need_recreate) { + for (i = 0; i < KVM_ARMV8_PMU_MAX_COUNTERS; i++) + kvm_pmu_stop_counter(kvm_vcpu_idx_to_pmc(vcpu, i)); + + pmu->events_need_recreate = false; + } __vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, &=, mask); __vcpu_rmw_sys_reg(vcpu, PMINTENSET_EL1, &=, mask); diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 42b6705bc21d..1a57e07cec9a 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -5390,7 +5390,7 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu) set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags); if (kvm_vcpu_has_pmu(vcpu)) - kvm_make_request(KVM_REQ_RELOAD_PMU, vcpu); + kvm_pmu_request_recreate(vcpu); } /** diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h index 6b4a118d17ca..65cf9b49a0c0 100644 --- a/include/kvm/arm_pmu.h +++ b/include/kvm/arm_pmu.h @@ -32,6 +32,7 @@ struct kvm_pmu { struct kvm_pmc pmc[KVM_ARMV8_PMU_MAX_COUNTERS]; int irq_num; bool created; + bool events_need_recreate; }; struct arm_pmu_entry { @@ -55,6 +56,7 @@ void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu); bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu); bool kvm_pmu_update_run(struct kvm_vcpu *vcpu); void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val); +void kvm_pmu_request_recreate(struct kvm_vcpu *vcpu); void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val); void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data, u64 select_idx); @@ -135,6 +137,7 @@ static inline bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu) } static inline bool kvm_pmu_update_run(struct kvm_vcpu *vcpu) { return false; } static inline void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {} +static inline void kvm_pmu_request_recreate(struct kvm_vcpu *vcpu) {} static inline void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) {} static inline void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data, u64 select_idx) {} -- 2.55.0