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.

Signed-off-by: Gleb Natapov <[email protected]>
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 124ecf7..74c4b5f 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;
 }
@@ -118,28 +116,34 @@ static void ioapic_write_indirect(struct kvm_ioapic 
*ioapic, u32 val)
        case IOAPIC_REG_ARB_ID:
                break;
 
-       default:
+       default: {
+               union kvm_ioapic_redirect_entry *e;
+               
                index = (ioapic->ioregsel - 0x10) >> 1;
 
                ioapic_debug("change redir index %x val %x\n", index, val);
                if (index >= IOAPIC_NUM_PINS)
                        return;
-               mask_before = ioapic->redirtbl[index].fields.mask;
+
+               e = &ioapic->redirtbl[index];
+               mask_before = e->fields.mask;
                if (ioapic->ioregsel & 1) {
-                       ioapic->redirtbl[index].bits &= 0xffffffff;
-                       ioapic->redirtbl[index].bits |= (u64) val << 32;
+                       e->bits &= 0xffffffff;
+                       e->bits |= (u64) val << 32;
                } else {
-                       ioapic->redirtbl[index].bits &= ~0xffffffffULL;
-                       ioapic->redirtbl[index].bits |= (u32) val;
-                       ioapic->redirtbl[index].fields.remote_irr = 0;
+                       e->bits &= ~0xffffffffULL;
+                       e->bits |= (u32) val;
+                       e->fields.remote_irr = 0;
                }
-               mask_after = ioapic->redirtbl[index].fields.mask;
+               mask_after = e->fields.mask;
                if (mask_before != mask_after)
                        kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after);
-               if (ioapic->irr & (1 << index))
+               if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG &&
+                   (ioapic->irr & (1 << index)))
                        ioapic_service(ioapic, index);
                break;
        }
+       }
 }
 
 static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
@@ -186,9 +190,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);
                }
        }
--
                        Gleb.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to