avoid redeliver of edge interrupt before next edge
PATCH 1/1 avoid redeliver 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.
Signed-off-by Gleb Natapov <[email protected]>
virt/kvm/ioapic.c +18 -13
@@ -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.