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: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Родитель
1ec2405c7c
Коммит
f458d039db
|
@ -49,6 +49,11 @@
|
||||||
static int ioapic_service(struct kvm_ioapic *vioapic, int irq,
|
static int ioapic_service(struct kvm_ioapic *vioapic, int irq,
|
||||||
bool line_status);
|
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,
|
static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
|
||||||
unsigned long addr,
|
unsigned long addr,
|
||||||
unsigned long length)
|
unsigned long length)
|
||||||
|
@ -177,6 +182,31 @@ static bool rtc_irq_check_coalesced(struct kvm_ioapic *ioapic)
|
||||||
return false;
|
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,
|
static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
|
||||||
int irq_level, bool line_status)
|
int irq_level, bool line_status)
|
||||||
{
|
{
|
||||||
|
@ -194,6 +224,15 @@ static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
|
||||||
goto out;
|
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,
|
* Return 0 for coalesced interrupts; for edge-triggered interrupts,
|
||||||
* this only happens if a previous edge has not been delivered due
|
* this only happens if a previous edge has not been delivered due
|
||||||
|
|
Загрузка…
Ссылка в новой задаче