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 <[email protected]>
---
 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


Reply via email to