kvm: ioapic: Lazy update IOAPIC EOI
authorSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Thu, 14 Nov 2019 20:15:19 +0000 (14:15 -0600)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 5 Feb 2020 14:17:44 +0000 (15:17 +0100)
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.suthikulpanit@amd.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/ioapic.c

index 453c795509179ce7572bf0e4a28d59c1384ca4f4..7668fed1ce6527767fbf6c8e10647c6627686f58 100644 (file)
 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)
@@ -177,6 +182,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, 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)
 {
@@ -194,6 +224,15 @@ static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
                goto out;
        }
 
+       /*
+        * AMD SVM AVIC 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_activated(ioapic->kvm))
+               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