On 12 Dec 2025, at 12:38 PM, Khushit Shah khushit.shah@nutanix.com wrote:
@@ -1515,6 +1552,17 @@ static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector) if (apic->vcpu->arch.highest_stale_pending_ioapic_eoi == vector) kvm_make_request(KVM_REQ_SCAN_IOAPIC, apic->vcpu);
/** Don't send the EOI to the I/O APIC if the guest has enabled Directed* EOI, a.k.a. Suppress EOI Broadcasts, in which case the local* APIC doesn't broadcast EOIs (the guest must EOI the target* I/O APIC(s) directly). Ignore the suppression if the guest has not* explicitly enabled Suppress EOI broadcast.*/if ((kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&!kvm_lapic_ignore_suppress_eoi_broadcast(apic->vcpu->kvm))return;/* Request a KVM exit to inform the userspace IOAPIC. */ if (irqchip_split(apic->vcpu->kvm)) { apic->vcpu->arch.pending_ioapic_eoi = vector;I am not entirely sure if returning from kvm_ioapic_send_eoi() early is correct for kernel IOAPIC. The original code (which is now redundant) does this very late in kvm_ioapic_update_eoi_one().
Am I correct in assuming we still need a call to rtc_irq_eoi() even if the guest has enabled SEOIB?
We will call kvm_ioapic_update_eoi_one() on I/O APIC EOIR write. But, the following condition in kvm_ioapic_update_eoi_one() blocks EOI processing:
if (trigger_mode != IOAPIC_LEVEL_TRIG || kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) return;
So, the condition needs to moved from kvm_ioapic_update_eoi_one(). It makes sense to keep it in kvm_ioapic_send_eoi() even for kernel IRQCHIP. But if a call to rtc_irq_eoi() is required (likely), then we need something similar to following:
diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index 2c2783296aed..76e511a36699 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -560,8 +560,7 @@ static void kvm_ioapic_update_eoi_one(struct kvm_vcpu *vcpu, kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, pin); spin_lock(&ioapic->lock);
- if (trigger_mode != IOAPIC_LEVEL_TRIG || - kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) + if (trigger_mode != IOAPIC_LEVEL_TRIG) return;
ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); @@ -595,6 +594,11 @@ void kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, int vector, int trigger_mode)
spin_lock(&ioapic->lock); rtc_irq_eoi(ioapic, vcpu, vector); + + if((kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) && + kvm_lapic_respect_suppress_eoi_broadcast(ioapic->kvm)) + goto out; + for (i = 0; i < IOAPIC_NUM_PINS; i++) { union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
@@ -602,6 +606,8 @@ void kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, int vector, int trigger_mode) continue; kvm_ioapic_update_eoi_one(vcpu, ioapic, trigger_mode, i); } + +out: spin_unlock(&ioapic->lock); } --- Finally, just to double-check, it is safe to not call kvm_notify_acked_irq() on LAPIC EOI when guest has enabled Suppress EOI Broadcast, right? As it will anyway be called on Direct EOI.
Thanks, Khushit