All of lore.kernel.org
 help / color / mirror / Atom feed
From: Zide Chen <zide.chen@intel.com>
To: Sean Christopherson <seanjc@google.com>,
	Paolo Bonzini <pbonzini@redhat.com>,
	Peter Zijlstra <peterz@infradead.org>
Cc: kvm@vger.kernel.org, Andi Kleen <ak@linux.intel.com>,
	Jim Mattson <jmattson@google.com>,
	Stephane Eranian <eranian@google.com>,
	linux-kernel@vger.kernel.org, Mingwei Zhang <mizhang@google.com>,
	Zide Chen <zide.chen@intel.com>,
	Das Sandipan <Sandipan.Das@amd.com>,
	Shukla Manali <Manali.Shukla@amd.com>,
	Dapeng Mi <dapeng1.mi@linux.intel.com>,
	Xudong Hao <xudong.hao@intel.com>
Subject: [PATCH 03/23] perf/x86: Add GUEST_PMU states for PMU partitioning
Date: Fri, 21 Aug 2026 15:19:42 -0700	[thread overview]
Message-ID: <20260821222002.54907-4-zide.chen@intel.com> (raw)
In-Reply-To: <20260821222002.54907-1-zide.chen@intel.com>

Currently, KVM loads a guest's mediated PMU context in a strict order:
perf_load_guest_context() runs first (it must execute in host context),
then PERF_GLOBAL_CTRL is cleared (to avoid spurious PMIs), then
perf_load_guest_lvtpc() switches the LVTPC hardware vector, and
finally the guest's PMCs are loaded.

Under PMU partitioning, host-owned counters remain available to host
events. When loading guest context, the perf scheduler must reschedule
host events off guest-owned counters.

Add GUEST_PMU_PARTITION_PRELOAD to represent the intermediate state in
which PMU partitioning constraints are needed for scheduling, but PMU
partition PMI handling is not yet active. Enter this state through the
new perf_pmu_partition_preload() helper.

Add GUEST_PMU_PARTITION_NMI for the state after the above _PRELOAD
state, i.e. the host context transition is complete and guest context
loading may proceed. LVTPC remains routed to NMI, and the PMU partition
mask can be applied in the PMI handler.

Add GUEST_PMU_MEDIATED to indicate that the LVTPC is set to the fixed
PERF_GUEST_MEDIATED_PMI_VECTOR, either in the PMU non-partitioned case,
or the partition setup where no host events are scheduled and no need
to share NMI with the host.

Signed-off-by: Zide Chen <zide.chen@intel.com>
---
 arch/x86/events/core.c            | 94 ++++++++++++++++++++++++++++---
 arch/x86/events/perf_event.h      |  2 +
 arch/x86/include/asm/perf_event.h |  1 +
 arch/x86/kvm/pmu.c                |  2 +
 4 files changed, 91 insertions(+), 8 deletions(-)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 8032311c0a47..ba441f4d5f3e 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -57,7 +57,38 @@ DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
 	.pmu = &pmu,
 };
 
-static DEFINE_PER_CPU(bool, guest_lvtpc_loaded);
+/*
+ * GUEST_PMU_NONE - No guest mediated PMU context is loaded.
+ *
+ * GUEST_PMU_MEDIATED - LVTPC is routed to the dedicated mediated PMI vector
+ *	instead of NMI, so any PMI in this state can only be guest-induced.
+ *	This covers both the non-partitioned mediated vPMU model and the PMU
+ *	partitioning case where the host currently has no events scheduled on
+ *	this CPU (see perf_load_guest_lvtpc()).
+ *
+ * GUEST_PMU_PARTITION_PRELOAD - Entering PMU partitioning guest mode, the host
+ *	context is still loaded. PMU partitioning constraints must be applied
+ *	so that host events can be rescheduled onto host-owned counters.
+ *
+ * GUEST_PMU_PARTITION_NMI - PMU partitioning is enabled, host event
+ *	rescheduling is complete, and the host currently has events scheduled
+ *	on this CPU, so LVTPC is routed to NMI and shared between host- and
+ *	guest-owned counters: a PMI in this state may be host- or
+ *	guest-induced.
+ *
+ * _PARTITION_PRELOAD and _PARTITION_NMI are distinct because PMU
+ * partitioning constraints must be visible to the scheduler before host
+ * events are rescheduled, while PMU partition masking can be applied to PMI
+ * handling only after the rescheduling completes.
+ */
+enum guest_pmu_mode {
+	GUEST_PMU_NONE,
+	GUEST_PMU_MEDIATED,
+	GUEST_PMU_PARTITION_PRELOAD,
+	GUEST_PMU_PARTITION_NMI,
+};
+
+static DEFINE_PER_CPU(enum guest_pmu_mode, guest_pmu_state);
 
 DEFINE_STATIC_KEY_FALSE(rdpmc_never_available_key);
 DEFINE_STATIC_KEY_FALSE(rdpmc_always_available_key);
@@ -1769,21 +1800,63 @@ void perf_events_lapic_init(void)
 	apic_write(APIC_LVTPC, APIC_DM_NMI);
 }
 
+bool pmu_partition_configured(void)
+{
+	return READ_ONCE(x86_pmu.partition_mask) != 0;
+}
+
 #ifdef CONFIG_PERF_GUEST_MEDIATED_PMU
+/*
+ * Mark this CPU as running a PMU partitioned guest. Guest PMU partition
+ * constraints apply from this point, even if host PMU context remains loaded.
+ */
+void perf_pmu_partition_preload(void)
+{
+	if (pmu_partition_configured())
+		this_cpu_write(guest_pmu_state, GUEST_PMU_PARTITION_PRELOAD);
+}
+EXPORT_SYMBOL_FOR_KVM(perf_pmu_partition_preload);
+
 void perf_load_guest_lvtpc(u32 guest_lvtpc)
 {
-	u32 masked = guest_lvtpc & APIC_LVT_MASKED;
+	struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+	bool is_pmu_partitioned = pmu_partition_configured();
+	bool use_nmi;
 
-	apic_write(APIC_LVTPC,
-		   APIC_DM_FIXED | PERF_GUEST_MEDIATED_PMI_VECTOR | masked);
-	this_cpu_write(guest_lvtpc_loaded, true);
+	if (is_pmu_partitioned)
+		WARN_ON_ONCE(this_cpu_read(guest_pmu_state) !=
+			     GUEST_PMU_PARTITION_PRELOAD);
+
+	/*
+	 * If the host has events scheduled on this CPU, a PMI could be host-
+	 * or guest-induced, so share NMI with the guest. Otherwise, route
+	 * LVTPC to the dedicated mediated PMI vector for better
+	 * performance and simpler handling.
+	 */
+	use_nmi = is_pmu_partitioned && cpuc->n_events;
+	if (!use_nmi)
+		apic_write(APIC_LVTPC, APIC_DM_FIXED |
+			   PERF_GUEST_MEDIATED_PMI_VECTOR |
+			   (guest_lvtpc & APIC_LVT_MASKED));
+
+	this_cpu_write(guest_pmu_state,
+		       use_nmi ? GUEST_PMU_PARTITION_NMI : GUEST_PMU_MEDIATED);
 }
 EXPORT_SYMBOL_FOR_KVM(perf_load_guest_lvtpc);
 
 void perf_put_guest_lvtpc(void)
 {
-	this_cpu_write(guest_lvtpc_loaded, false);
-	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	enum guest_pmu_mode state = this_cpu_read(guest_pmu_state);
+
+	this_cpu_write(guest_pmu_state, GUEST_PMU_NONE);
+
+	/*
+	 * LVTPC needs restoring to NMI unless it's already routed there, i.e.
+	 * unless LVTPC was left routed to the dedicated mediated PMI vector
+	 * (see perf_load_guest_lvtpc()).
+	 */
+	if (state == GUEST_PMU_MEDIATED)
+		apic_write(APIC_LVTPC, APIC_DM_NMI);
 }
 EXPORT_SYMBOL_FOR_KVM(perf_put_guest_lvtpc);
 #endif /* CONFIG_PERF_GUEST_MEDIATED_PMU */
@@ -1802,8 +1875,13 @@ perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs)
 	 * loaded will generate false positives and clobber guest state.  Note,
 	 * the LVTPC is switched to/from the dedicated mediated PMI IRQ vector
 	 * while host events are quiesced.
+	 *
+	 * GUEST_PMU_PARTITION_NMI is intentionally excluded here: LVTPC stays
+	 * routed to NMI in that state, and an NMI there can be host- or
+	 * guest-induced. GUEST_PMU_PARTITION_PRELOAD is likewise excluded, as
+	 * PMU is still loaded with host context.
 	 */
-	if (this_cpu_read(guest_lvtpc_loaded))
+	if (this_cpu_read(guest_pmu_state) == GUEST_PMU_MEDIATED)
 		return NMI_DONE;
 
 	/*
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index 19beb16baa8e..29ea11421874 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -1602,6 +1602,8 @@ static inline int is_pebs_pt(struct perf_event *event)
 	return !!(event->hw.flags & PERF_X86_EVENT_PEBS_VIA_PT);
 }
 
+bool pmu_partition_configured(void);
+
 #ifdef CONFIG_CPU_SUP_INTEL
 
 static inline bool intel_pmu_has_bts_period(struct perf_event *event, u64 period)
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 17b0bc7dfce7..18f1ac5e008b 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -790,6 +790,7 @@ static inline void perf_check_microcode(void) { }
 #endif
 
 #ifdef CONFIG_PERF_GUEST_MEDIATED_PMU
+extern void perf_pmu_partition_preload(void);
 extern void perf_load_guest_lvtpc(u32 guest_lvtpc);
 extern void perf_put_guest_lvtpc(void);
 #endif
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index b5a9fbd415d1..7f619a99a152 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -1388,6 +1388,8 @@ void kvm_mediated_pmu_load(struct kvm_vcpu *vcpu)
 
 	lockdep_assert_irqs_disabled();
 
+	perf_pmu_partition_preload();
+
 	perf_load_guest_context();
 
 	/*
-- 
2.55.0


  parent reply	other threads:[~2026-08-21 22:30 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-21 22:19 [PATCH 00/23] perf/KVM: Support PMU partitioning for x86 platforms Zide Chen
2026-08-21 22:19 ` [PATCH 01/23] perf/x86/intel: Guard counter masks against zero counters Zide Chen
2026-08-21 22:19 ` [PATCH 02/23] perf, perf/x86: Pass partition mask from KVM to perf/x86 Zide Chen
2026-08-21 22:19 ` Zide Chen [this message]
2026-08-21 22:19 ` [PATCH 04/23] perf/x86: Split host/guest PMI handling under PMU partitioning Zide Chen
2026-08-21 22:19 ` [PATCH 05/23] perf/x86: Allow exclude_host events to run in non-root mode Zide Chen
2026-08-21 22:19 ` [PATCH 06/23] perf/x86: Restrict !exclude_guest events to host-owned counters Zide Chen
2026-08-21 22:19 ` [PATCH 07/23] perf/x86: Apply PMU partition mask on static constraints Zide Chen
2026-08-21 22:19 ` [PATCH 08/23] perf/x86: Export available PMU counters to sysfs Zide Chen
2026-08-21 22:19 ` [PATCH 09/23] perf: Skip exclude_guest events on PMU partitioned counters Zide Chen
2026-08-21 22:19 ` [PATCH 10/23] perf: Reschedule events across PMU partition transitions Zide Chen
2026-08-21 22:19 ` [PATCH 11/23] perf, perf/x86: Allow host !exclude_guest events in PMU partitioning Zide Chen
2026-08-21 22:19 ` [PATCH 12/23] KVM: x86/pmu: Add the perfmon_mask module parameter Zide Chen
2026-08-21 22:19 ` [PATCH 13/23] KVM: x86/pmu: Set up the PERFMON_MASK VMCS field Zide Chen
2026-08-21 22:19 ` [PATCH 14/23] KVM: x86/pmu, perf/x86: Update effective PMU partition mask Zide Chen
2026-08-21 22:19 ` [PATCH 15/23] KVM: x86/pmu: Relax MSR intercept policy under PerfMon masking Zide Chen
2026-08-21 22:19 ` [PATCH 16/23] KVM: x86/pmu: Handle FIXED_CTR_CTRL " Zide Chen
2026-08-21 22:19 ` [PATCH 17/23] KVM: x86/pmu: Handle GLOBAL_CTRL " Zide Chen
2026-08-21 22:19 ` [PATCH 18/23] KVM: x86/pmu: Handle GLOBAL_STATUS MSRs " Zide Chen
2026-08-21 22:19 ` [PATCH 19/23] KVM: x86/pmu: Always intercept GLOBAL_INUSE " Zide Chen
2026-08-21 22:19 ` [PATCH 20/23] KVM: x86/pmu: Request guest PMI for guest-induced PMIs Zide Chen
2026-08-21 22:20 ` [PATCH 21/23] KVM: x86/pmu: Enable PerfMon masking Zide Chen
2026-08-21 22:20 ` [PATCH 22/23] KVM: selftests: Fix PERF_METRICS test by checking FC3 availability Zide Chen
2026-08-21 22:20 ` [PATCH 23/23] KVM: selftests: Allow no general purpose counters on the host Zide Chen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260821222002.54907-4-zide.chen@intel.com \
    --to=zide.chen@intel.com \
    --cc=Manali.Shukla@amd.com \
    --cc=Sandipan.Das@amd.com \
    --cc=ak@linux.intel.com \
    --cc=dapeng1.mi@linux.intel.com \
    --cc=eranian@google.com \
    --cc=jmattson@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mizhang@google.com \
    --cc=pbonzini@redhat.com \
    --cc=peterz@infradead.org \
    --cc=seanjc@google.com \
    --cc=xudong.hao@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.