[PATCH 14/23] KVM: x86/pmu, perf/x86: Update effective PMU partition mask

Zide Chen <[email protected]>
Newsgroups org.kernel.vger.kvm,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
The static system-wide mask x86_pmu.partition_mask defines the global
maximum guest capability, while a guest may have its own mask, which
is a subset of x86_pmu.partition_mask.

The per-guest mask, which on Intel is backed by the PERFMON_MASK VMCS
field, is the effective mask while a vCPU is loaded. Whenever it
changes -- e.g. during kvm_arch_vcpu_{load,put}() -- perf/x86 needs to
be told so it can keep its own per-CPU copy in sync.

Suggested-by: Andi Kleen <[email protected]>
Signed-off-by: Zide Chen <[email protected]>
---
 arch/x86/events/core.c            |  8 ++++++++
 arch/x86/include/asm/perf_event.h |  1 +
 arch/x86/kvm/pmu.c                | 13 +++++++++++++
 arch/x86/kvm/pmu.h                |  3 +++
 arch/x86/kvm/x86.c                |  4 ++++
 5 files changed, 29 insertions(+)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 282170f7c1e1..f485f927967a 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -1883,6 +1883,14 @@ void perf_put_guest_lvtpc(void)
 		apic_write(APIC_LVTPC, APIC_DM_NMI);
 }
 EXPORT_SYMBOL_FOR_KVM(perf_put_guest_lvtpc);
+
+void perf_set_current_partition_mask(u64 mask)
+{
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+
+	cpuc->partition_mask = mask & READ_ONCE(x86_pmu.partition_mask);
+}
+EXPORT_SYMBOL_FOR_KVM(perf_set_current_partition_mask);
 #endif /* CONFIG_PERF_GUEST_MEDIATED_PMU */
 
 static int
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index aaaa34062f8c..5be4f6a93b14 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -794,6 +794,7 @@ static inline void perf_check_microcode(void) { }
 extern void perf_pmu_partition_preload(void);
 extern void perf_load_guest_lvtpc(u32 guest_lvtpc);
 extern void perf_put_guest_lvtpc(void);
+extern void perf_set_current_partition_mask(u64 mask);
 #endif
 
 #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL)
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index f944a15160cb..c447f32c1cb1 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -46,6 +46,19 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_mediated_pmu);
 u64 __read_mostly perfmon_mask;
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(perfmon_mask);
 
+void kvm_pmu_vcpu_load(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+	perf_set_current_partition_mask(kvm_vcpu_has_perfmon_mask(vcpu) ?
+					pmu->perfmon_mask : 0);
+}
+
+void kvm_pmu_vcpu_put(struct kvm_vcpu *vcpu)
+{
+	perf_set_current_partition_mask(0);
+}
+
 struct kvm_x86_pmu_event_filter {
 	__u32 action;
 	__u32 nevents;
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 057e3258e473..c5feeb60bcf6 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -70,6 +70,9 @@ void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops);
 
 void kvm_handle_guest_mediated_pmi(void);
 
+void kvm_pmu_vcpu_load(struct kvm_vcpu *vcpu);
+void kvm_pmu_vcpu_put(struct kvm_vcpu *vcpu);
+
 static inline bool kvm_pmu_has_perf_global_ctrl(struct kvm_pmu *pmu)
 {
 	/*
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 26a3b7a267b5..07e3fe5b53f8 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2538,6 +2538,8 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
 	kvm_request_l1tf_flush_l1d();
 
+	kvm_pmu_vcpu_load(vcpu);
+
 	if (vcpu->scheduled_out && pmu->version && pmu->event_count) {
 		pmu->need_cleanup = true;
 		kvm_make_request(KVM_REQ_PMU, vcpu);
@@ -2686,6 +2688,8 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 
 	kvm_x86_call(vcpu_put)(vcpu);
 	vcpu->arch.last_host_tsc = rdtsc();
+
+	kvm_pmu_vcpu_put(vcpu);
 }
 
 static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.