From 8aa136dcb689a4002f21220c8896d971331e0384 Mon Sep 17 00:00:00 2001 From: Gleb Natapov <gleb@redhat.com> Date: Mon, 27 Jul 2009 12:15:05 +0300 Subject: [PATCH 2/2] Avoid redelivery of edge interrupt before next edge The check for an edge is broken in current ioapic code. ioapic->irr is cleared on each edge interrupt by ioapic_service() and this makes old_irr != ioapic->irr condition in kvm_ioapic_set_irq() to be always true. The patch fixes the code to properly recognise edge. Some HW emulation calls set_irq() without level change. If each such call is propagated to an OS it may confuse a device driver. This is the case with keyboard device emulation and Windows XP x64 installer on SMP VM. Each keystroke produce two interrupts (down/up) one interrupt is submitted to CPU0 and another to CPU1. This confuses Windows somehow and it ignores keystrokes. BZ:513946 Upstream status: commit 5b996e12a8e9ab44581bc53996419046a768c54e Message-ID: <20090727091505.GA25811@redhat.com> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> Bugzilla: 513946 RH-Upstream-status: applied Acked-by: Avi Kivity <avi@redhat.com> Acked-by: Juan Quintela <quintela@redhat.com> Acked-by: john cooper <john.cooper@redhat.com> --- virt/kvm/ioapic.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 5b275a6..442915b 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c @@ -95,8 +95,6 @@ static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) pent->fields.remote_irr = 1; } - if (!pent->fields.trig_mode) - ioapic->irr &= ~(1 << idx); return injected; } @@ -136,7 +134,8 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) mask_after = ioapic->redirtbl[index].fields.mask; if (mask_before != mask_after) kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after); - if (ioapic->irr & (1 << index)) + if (ioapic->redirtbl[index].fields.trig_mode == IOAPIC_LEVEL_TRIG + && ioapic->irr & (1 << index)) ioapic_service(ioapic, index); break; } @@ -231,9 +230,10 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) if (!level) ioapic->irr &= ~mask; else { + int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); ioapic->irr |= mask; - if ((!entry.fields.trig_mode && old_irr != ioapic->irr) - || !entry.fields.remote_irr) + if ((edge && old_irr != ioapic->irr) || + (!edge && !entry.fields.remote_irr)) ret = ioapic_service(ioapic, irq); } } -- 1.6.3.rc4.29.g8146