This creates a way to detect when kvm_set_irq(...,0) was run twice with the same source id by returning 0 in this case. Signed-off-by: Michael S. Tsirkin <mst@xxxxxxxxxx> --- This is on top of my bugfix patch. Uncompiled and untested. Alex, I think something like this patch will make it possible for you to simply do if (kvm_set_irq(...., 0)) eventfd_signal() without need for further tricks. arch/x86/include/asm/kvm_host.h | 9 ++++----- arch/x86/kvm/i8259.c | 11 +++++++---- virt/kvm/ioapic.c | 17 ++++++++++------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index fe6e9f1..6f5ed0a 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -802,16 +802,15 @@ int kvm_read_guest_page_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, void kvm_propagate_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault); bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl); -static inline int kvm_irq_line_state(unsigned long *irq_state, +/* Tweak line state. Return true if state was changed. */ +static inline bool kvm_irq_line_state(unsigned long *irq_state, int irq_source_id, int level) { /* Logical OR for level trig interrupt */ if (level) - __set_bit(irq_source_id, irq_state); + return !__test_and_set_bit(irq_source_id, irq_state); else - __clear_bit(irq_source_id, irq_state); - - return !!(*irq_state); + return __test_and_clear_bit(irq_source_id, irq_state); } int kvm_pic_set_irq(struct kvm_pic *pic, int irq, int irq_source_id, int level); diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index 95b504b..44e3635 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c @@ -190,12 +190,15 @@ void kvm_pic_update_irq(struct kvm_pic *s) int kvm_pic_set_irq(struct kvm_pic *s, int irq, int src_id, int l) { - int ret = -1; - int level; + int ret, level; pic_lock(s); - if (irq >= 0 && irq < PIC_NUM_PINS) { - level = kvm_irq_line_state(&s->irq_states[irq], src_id, l); + if (irq < 0 || irq >= PIC_NUM_PINS) { + ret = -1; + } else if (!kvm_irq_line_state(&s->irq_states[irq], src_id, l)) { + ret = 0; + } else { + level = !!s->irq_states[irq]; ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); pic_update_irq(s); trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr, diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 268b332..edc9445 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c @@ -196,18 +196,21 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int src_id, int l) u32 old_irr; u32 mask = 1 << irq; union kvm_ioapic_redirect_entry entry; - int ret = 1; - int level; + int ret, level; spin_lock(&ioapic->lock); old_irr = ioapic->irr; - if (irq >= 0 && irq < IOAPIC_NUM_PINS) { + if (irq < 0 || irq >= IOAPIC_NUM_PINS) { + ret = -1; + } else if (!kvm_irq_line_state(&ioapic->irq_states[irq], src_id, l)) { + ret = 0; + } else { entry = ioapic->redirtbl[irq]; - level = kvm_irq_line_state(&ioapic->irq_states[irq], src_id, l); - level ^= entry.fields.polarity; - if (!level) + level = (!!ioapic->irq_states[irq]) ^ entry.fields.polarity; + if (!level) { ioapic->irr &= ~mask; - else { + ret = 1; + } else { int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); ioapic->irr |= mask; if ((edge && old_irr != ioapic->irr) || -- MST -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html