[RFC PATCH v2 10/31] KVM: x86: Keep APICv off on higher-plane vCPUs
From: David Woodhouse
Date: Fri Nov 13 2026 - 15:22:26 EST
From: David Woodhouse <dwmw@xxxxxxxxxxxx>
A higher-plane twin is switched in software and spends most of its
time suspended. With APICv active, an interrupt posted to it sits in
the PIR, where the lower plane's checks for a pending higher-plane
event cannot reliably see it while the twin is not running.
Leave APICv inactive on every vCPU with a non-zero plane_level: at LAPIC
creation, and in __kvm_vcpu_update_apicv() so a later APICv update
cannot turn it back on. Higher planes use the legacy delivery path,
whose IRR the pending-event checks read directly.
Signed-off-by: David Woodhouse <dwmw@xxxxxxxxxxxx>
---
arch/x86/kvm/lapic.c | 8 +++++++-
arch/x86/kvm/x86.c | 6 +++++-
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index ccf01b263ebf..7842d0f53e9f 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -3192,7 +3192,13 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
* that vCPU creation is guaranteed to run with a deterministic value,
* the request will ensure the vCPU gets the correct state before VM-Entry.
*/
- if (enable_apicv) {
+ /*
+ * Higher-plane twins are software-switched and mostly suspended;
+ * hardware interrupt virtualization on them only leaves pending
+ * vectors in the PIR where a suspended plane's state cannot be
+ * reliably observed. Keep them on the legacy delivery path.
+ */
+ if (enable_apicv && !vcpu->plane_level) {
apic->apicv_active = true;
kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu);
}
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0fda04f6114a..8cd3415d23f6 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8426,8 +8426,12 @@ void __kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu)
down_read(&vcpu->kvm->arch.apicv_update_lock);
preempt_disable();
- /* Do not activate APICV when APIC is disabled */
+ /*
+ * Do not activate APICV when APIC is disabled, nor on higher-plane
+ * twins (see kvm_create_lapic).
+ */
activate = kvm_vcpu_apicv_activated(vcpu) &&
+ !vcpu->plane_level &&
(kvm_get_apic_mode(vcpu) != LAPIC_MODE_DISABLED);
if (apic->apicv_active == activate)
--
2.50.1