In-kernel IOAPIC does not receive EOI with AMD SVM AVIC
since the processor accelerate write to APIC EOI register and
does not trap if the interrupt is edge-triggered.

Workaround this by lazy check for pending APIC EOI at the time when
setting new IOPIC irq, and update IOAPIC EOI if no pending APIC EOI.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpa...@amd.com>
---
 arch/x86/kvm/ioapic.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
index c57b7bb..ddb41ee 100644
--- a/arch/x86/kvm/ioapic.c
+++ b/arch/x86/kvm/ioapic.c
@@ -48,6 +48,11 @@
 static int ioapic_service(struct kvm_ioapic *vioapic, int irq,
                bool line_status);
 
+static void kvm_ioapic_update_eoi_one(struct kvm_vcpu *vcpu,
+                                     struct kvm_ioapic *ioapic,
+                                     int trigger_mode,
+                                     int pin);
+
 static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
                                          unsigned long addr,
                                          unsigned long length)
@@ -174,6 +179,31 @@ static bool rtc_irq_check_coalesced(struct kvm_ioapic 
*ioapic)
        return false;
 }
 
+static void ioapic_lazy_update_eoi(struct kvm_ioapic *ioapic, int irq)
+{
+       int i;
+       struct kvm_vcpu *vcpu;
+       union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
+
+       kvm_for_each_vcpu(i, vcpu, ioapic->kvm) {
+               if (!kvm_apic_match_dest(vcpu, NULL, KVM_APIC_DEST_NOSHORT,
+                                        entry->fields.dest_id,
+                                        entry->fields.dest_mode) ||
+                   kvm_apic_pending_eoi(vcpu, entry->fields.vector))
+                       continue;
+
+               /*
+                * If no longer has pending EOI in LAPICs, update
+                * EOI for this vetor.
+                */
+               rtc_irq_eoi(ioapic, vcpu, entry->fields.vector);
+               kvm_ioapic_update_eoi_one(vcpu, ioapic,
+                                         entry->fields.trig_mode,
+                                         irq);
+               break;
+       }
+}
+
 static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
                int irq_level, bool line_status)
 {
@@ -192,6 +222,15 @@ static int ioapic_set_irq(struct kvm_ioapic *ioapic, 
unsigned int irq,
        }
 
        /*
+        * In case APICv accelerate EOI write and do not trap,
+        * in-kernel IOAPIC will not be able to receive the EOI.
+        * In this case, we do lazy update of the pending EOI when
+        * trying to set IOAPIC irq.
+        */
+       if (kvm_apicv_eoi_accelerate(ioapic->kvm, edge))
+               ioapic_lazy_update_eoi(ioapic, irq);
+
+       /*
         * Return 0 for coalesced interrupts; for edge-triggered interrupts,
         * this only happens if a previous edge has not been delivered due
         * do masking.  For level interrupts, the remote_irr field tells
-- 
1.8.3.1

Reply via email to