* KVM: IOAPIC: don't clear remote_irr if IRQ is reinjected from EOI
@ 2008-06-05 3:08 Marcelo Tosatti
2008-06-05 3:13 ` Marcelo Tosatti
2008-06-05 7:55 ` Avi Kivity
0 siblings, 2 replies; 3+ messages in thread
From: Marcelo Tosatti @ 2008-06-05 3:08 UTC (permalink / raw)
To: Avi Kivity, Gerd von Egidy; +Cc: kvm-devel
There's a bug in the IOAPIC code for level-triggered interrupts. Its
relatively easy to trigger by sharing (virtio-blk + usbtablet was the
testcase, initially reported by Gerd von Egidy).
The "remote_irr" variable is used to indicate accepted but not yet acked
interrupts. Its cleared from the EOI handler.
Problem is that the EOI handler clears remote_irr unconditionally, even
if it reinjected another pending interrupt.
In that case, kvm_ioapic_set_irq() proceeds to ioapic_service() which
sets remote_irr even if it failed to inject (since the IRR was high due
to EOI reinjection).
Since the TMR bit has been cleared by the first EOI, the second one
fails to clear remote_irr.
End result is interrupt line dead.
Fix it by setting remote_irr only if a new pending interrupt has been
generated (and the TMR bit for vector in question set).
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 99a1736..92ed191 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -45,7 +45,7 @@
#else
#define ioapic_debug(fmt, arg...)
#endif
-static void ioapic_deliver(struct kvm_ioapic *vioapic, int irq);
+static int ioapic_deliver(struct kvm_ioapic *vioapic, int irq);
static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
unsigned long addr,
@@ -89,8 +89,8 @@ static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
pent = &ioapic->redirtbl[idx];
if (!pent->fields.mask) {
- ioapic_deliver(ioapic, idx);
- if (pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
+ int injected = ioapic_deliver(ioapic, idx);
+ if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
pent->fields.remote_irr = 1;
}
if (!pent->fields.trig_mode)
@@ -133,7 +133,7 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
}
}
-static void ioapic_inj_irq(struct kvm_ioapic *ioapic,
+static int ioapic_inj_irq(struct kvm_ioapic *ioapic,
struct kvm_vcpu *vcpu,
u8 vector, u8 trig_mode, u8 delivery_mode)
{
@@ -143,7 +143,7 @@ static void ioapic_inj_irq(struct kvm_ioapic *ioapic,
ASSERT((delivery_mode == IOAPIC_FIXED) ||
(delivery_mode == IOAPIC_LOWEST_PRIORITY));
- kvm_apic_set_irq(vcpu, vector, trig_mode);
+ return kvm_apic_set_irq(vcpu, vector, trig_mode);
}
static void ioapic_inj_nmi(struct kvm_vcpu *vcpu)
@@ -191,7 +191,7 @@ static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
return mask;
}
-static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
+static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
{
u8 dest = ioapic->redirtbl[irq].fields.dest_id;
u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode;
@@ -200,7 +200,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode;
u32 deliver_bitmask;
struct kvm_vcpu *vcpu;
- int vcpu_id;
+ int vcpu_id, r = 0;
ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
"vector=%x trig_mode=%x\n",
@@ -209,7 +209,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
deliver_bitmask = ioapic_get_delivery_bitmask(ioapic, dest, dest_mode);
if (!deliver_bitmask) {
ioapic_debug("no target on destination\n");
- return;
+ return 0;
}
switch (delivery_mode) {
@@ -221,7 +221,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
vcpu = ioapic->kvm->vcpus[0];
#endif
if (vcpu != NULL)
- ioapic_inj_irq(ioapic, vcpu, vector,
+ r = ioapic_inj_irq(ioapic, vcpu, vector,
trig_mode, delivery_mode);
else
ioapic_debug("null lowest prio vcpu: "
@@ -239,7 +239,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
deliver_bitmask &= ~(1 << vcpu_id);
vcpu = ioapic->kvm->vcpus[vcpu_id];
if (vcpu) {
- ioapic_inj_irq(ioapic, vcpu, vector,
+ r = ioapic_inj_irq(ioapic, vcpu, vector,
trig_mode, delivery_mode);
}
}
@@ -262,6 +262,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
delivery_mode);
break;
}
+ return r;
}
void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: KVM: IOAPIC: don't clear remote_irr if IRQ is reinjected from EOI
2008-06-05 3:08 KVM: IOAPIC: don't clear remote_irr if IRQ is reinjected from EOI Marcelo Tosatti
@ 2008-06-05 3:13 ` Marcelo Tosatti
2008-06-05 7:55 ` Avi Kivity
1 sibling, 0 replies; 3+ messages in thread
From: Marcelo Tosatti @ 2008-06-05 3:13 UTC (permalink / raw)
To: Avi Kivity, Gerd von Egidy; +Cc: kvm-devel
On Thu, Jun 05, 2008 at 12:08:11AM -0300, Marcelo Tosatti wrote:
>
> There's a bug in the IOAPIC code for level-triggered interrupts. Its
> relatively easy to trigger by sharing (virtio-blk + usbtablet was the
> testcase, initially reported by Gerd von Egidy).
Err, subject should be "only set remote_irr if interrupt was injected".
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: KVM: IOAPIC: don't clear remote_irr if IRQ is reinjected from EOI
2008-06-05 3:08 KVM: IOAPIC: don't clear remote_irr if IRQ is reinjected from EOI Marcelo Tosatti
2008-06-05 3:13 ` Marcelo Tosatti
@ 2008-06-05 7:55 ` Avi Kivity
1 sibling, 0 replies; 3+ messages in thread
From: Avi Kivity @ 2008-06-05 7:55 UTC (permalink / raw)
To: Marcelo Tosatti; +Cc: Gerd von Egidy, kvm-devel
Marcelo Tosatti wrote:
> There's a bug in the IOAPIC code for level-triggered interrupts. Its
> relatively easy to trigger by sharing (virtio-blk + usbtablet was the
> testcase, initially reported by Gerd von Egidy).
>
> The "remote_irr" variable is used to indicate accepted but not yet acked
> interrupts. Its cleared from the EOI handler.
>
> Problem is that the EOI handler clears remote_irr unconditionally, even
> if it reinjected another pending interrupt.
>
> In that case, kvm_ioapic_set_irq() proceeds to ioapic_service() which
> sets remote_irr even if it failed to inject (since the IRR was high due
> to EOI reinjection).
>
> Since the TMR bit has been cleared by the first EOI, the second one
> fails to clear remote_irr.
>
> End result is interrupt line dead.
>
> Fix it by setting remote_irr only if a new pending interrupt has been
> generated (and the TMR bit for vector in question set).
>
Applied, thanks.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2008-06-05 7:55 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-05 3:08 KVM: IOAPIC: don't clear remote_irr if IRQ is reinjected from EOI Marcelo Tosatti
2008-06-05 3:13 ` Marcelo Tosatti
2008-06-05 7:55 ` Avi Kivity
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox