Commit f458d039 authored by Suravee Suthikulpanit's avatar Suravee Suthikulpanit Committed by Paolo Bonzini
Browse files

kvm: ioapic: Lazy update IOAPIC EOI



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: default avatarSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 1ec2405c
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
@@ -49,6 +49,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)
@@ -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