kvm: ioapic: conditionally delay irq delivery during eoi broadcast
PATCH 1/1 kvm: ioapic: conditionally delay irq delivery during eoi broadcast
Currently, we call ioapic_service() immediately when we find the irq is still active during eoi broadcast. But for real hardware, there's some dealy between the EOI writing and irq delivery (system bus latency?). So we need to emulate this behavior. Otherwise, for a guest who haven't register a proper irq handler , it would stay in the interrupt routine as this irq would be re-injected immediately after guest enables interrupt. This would lead guest can't move forward and may miss the possibility to get proper irq handler registered (one example is windows guest resuming from hibernation).
As there's no way to differ the unhandled irq from new raised ones, this patch solve this problems by scheduling a delayed work when the count of irq injected during eoi broadcast exceeds a threshold value. After this patch, the guest can move a little forward when there's no suitable irq handler in case it may register one very soon and for guest who has a bad irq detection routine ( such as note_interrupt() in linux ), this bad irq would be recognized soon as in the past.
--- include/trace/events/kvm.h | 20 ++++++++++++++++++ virt/kvm/ioapic.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-- virt/kvm/ioapic.h | 6 ++++++ 3 files changed, 75 insertions(+), 2 deletions(-)
include/trace/events/kvm.h +20 -0
@@ -95,6 +95,26 @@ TRACE_EVENT(kvm_ioapic_set_irq, __entry->coalesced ? " (coalesced)" : "") ); +TRACE_EVENT (kvm_ioapic_delayed_eoi_inj, + TP_PROTO(__u64 e), +TP_ARGS (e), + +TP_STRUCT__entry ( +__field ( __u64, e ) + ), + +TP_fast_assign ( + __entry->e = e; + ), + +TP_printk ("dst %x vec=%u (%s|%s|%s%s)%s" , + (u8)(__entry->e >>56 ), (u8 )__entry->e, +__print_symbolic ((__entry->e >>8 &0x7 ), kvm_deliver_mode), + (__entry->e & (1 <<11 )) ?"logical" :"physical" , + (__entry->e & (1 <<15 )) ?"level" :"edge" , + (__entry->e & (1 <<16 )) ?"|masked" :"" ) +); + TRACE_EVENT(kvm_msi_set_irq, TP_PROTO(__u64 address, __u64 data), TP_ARGS(address, data),
virt/kvm/ioapic.c +49 -2
87 lines not on this page · raw message
virt/kvm/ioapic.h +6 -0
@@ -34,6 +34,10 @@ struct kvm_vcpu;#define IOAPIC_INIT 0x5#define IOAPIC_EXTINT 0x7 +/* max successive count of the same irq during ioapic eoi broadcast, if this limitation reached, +which can be considered as interrupt storm happened */ +#define IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT 10000 +#ifdef CONFIG_X86 #define RTC_GSI 8#else
@@ -59,6 +63,8 @@ struct kvm_ioapic {spinlock_t lock;DECLARE_BITMAP (handled_vectors,256 );struct rtc_status rtc_status; +struct delayed_work eoi_inject; +u32 irq_eoi[IOAPIC_NUM_PINS ]; };#ifdef DEBUG
Signature · 1 line
1.7.12.4
Quoted 8 lines
(quoted diff) +8
-0+static void kvm_ioapic_eoi_inject_work(struct work_struct *work) +{ + int i, ret; + struct kvm_ioapic *ioapic = container_of(work, struct kvm_ioapic, + eoi_inject.work); + spin_lock(&ioapic->lock); + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
Review
Quoted 10 lines
(quoted diff) +10
-0+ + if (ent->fields.trig_mode != IOAPIC_LEVEL_TRIG) + continue; + + if (ioapic->irr & (1 << i) && !ent->fields.remote_irr) + ret = ioapic_service(ioapic, i, false); + } + spin_unlock(&ioapic->lock); +} +
Delete unused variable, ret.
Currently, we call ioapic_service() immediately when we find the irq is still active during eoi broadcast. But for real hardware, there's some dealy between the EOI writing and irq delivery (system bus latency?). So we need to emulate this behavior. Otherwise, for a guest who haven't register a proper irq handler , it would stay in the interrupt routine as this irq would be re-injected immediately after guest enables interrupt. This would lead guest can't move forward and may miss the possibility to get proper irq handler registered (one example is windows guest resuming from hibernation).
As there's no way to differ the unhandled irq from new raised ones, this patch solve this problems by scheduling a delayed work when the count of irq injected during eoi broadcast exceeds a threshold value. After this patch, the guest can move a little forward when there's no suitable irq handler in case it may register one very soon and for guest who has a bad irq detection routine ( such as note_interrupt() in linux ), this bad irq would be recognized soon as in the past.
--- include/trace/events/kvm.h | 20 ++++++++++++++++++ virt/kvm/ioapic.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-- virt/kvm/ioapic.h | 6 ++++++ 3 files changed, 75 insertions(+), 2 deletions(-)
include/trace/events/kvm.h +20 -0
@@ -95,6 +95,26 @@ TRACE_EVENT(kvm_ioapic_set_irq, __entry->coalesced ? " (coalesced)" : "") ); +TRACE_EVENT (kvm_ioapic_delayed_eoi_inj, + TP_PROTO(__u64 e), +TP_ARGS (e), + +TP_STRUCT__entry ( +__field ( __u64, e ) + ), + +TP_fast_assign ( + __entry->e = e; + ), + +TP_printk ("dst %x vec=%u (%s|%s|%s%s)%s" , + (u8)(__entry->e >>56 ), (u8 )__entry->e, +__print_symbolic ((__entry->e >>8 &0x7 ), kvm_deliver_mode), + (__entry->e & (1 <<11 )) ?"logical" :"physical" , + (__entry->e & (1 <<15 )) ?"level" :"edge" , + (__entry->e & (1 <<16 )) ?"|masked" :"" ) +); + TRACE_EVENT(kvm_msi_set_irq, TP_PROTO(__u64 address, __u64 data), TP_ARGS(address, data),
virt/kvm/ioapic.c +49 -2
87 lines not on this page · raw message
virt/kvm/ioapic.h +6 -0
@@ -34,6 +34,10 @@ struct kvm_vcpu;#define IOAPIC_INIT 0x5#define IOAPIC_EXTINT 0x7 +/* max successive count of the same irq during ioapic eoi broadcast, if this limitation reached, +which can be considered as interrupt storm happened */ +#define IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT 10000 +#ifdef CONFIG_X86 #define RTC_GSI 8#else
@@ -59,6 +63,8 @@ struct kvm_ioapic {spinlock_t lock;DECLARE_BITMAP (handled_vectors,256 );struct rtc_status rtc_status; +struct delayed_work eoi_inject; +u32 irq_eoi[IOAPIC_NUM_PINS ]; };#ifdef DEBUG
Signature · 1 line
1.7.12.4