diff options
-rw-r--r-- | include/trace/events/kvm.h | 20 | ||||
-rw-r--r-- | virt/kvm/ioapic.c | 46 | ||||
-rw-r--r-- | virt/kvm/ioapic.h | 2 |
3 files changed, 66 insertions, 2 deletions
diff --git a/include/trace/events/kvm.h b/include/trace/events/kvm.h index 908925ace776..ab679c395042 100644 --- a/include/trace/events/kvm.h +++ b/include/trace/events/kvm.h | |||
@@ -95,6 +95,26 @@ TRACE_EVENT(kvm_ioapic_set_irq, | |||
95 | __entry->coalesced ? " (coalesced)" : "") | 95 | __entry->coalesced ? " (coalesced)" : "") |
96 | ); | 96 | ); |
97 | 97 | ||
98 | TRACE_EVENT(kvm_ioapic_delayed_eoi_inj, | ||
99 | TP_PROTO(__u64 e), | ||
100 | TP_ARGS(e), | ||
101 | |||
102 | TP_STRUCT__entry( | ||
103 | __field( __u64, e ) | ||
104 | ), | ||
105 | |||
106 | TP_fast_assign( | ||
107 | __entry->e = e; | ||
108 | ), | ||
109 | |||
110 | TP_printk("dst %x vec=%u (%s|%s|%s%s)", | ||
111 | (u8)(__entry->e >> 56), (u8)__entry->e, | ||
112 | __print_symbolic((__entry->e >> 8 & 0x7), kvm_deliver_mode), | ||
113 | (__entry->e & (1<<11)) ? "logical" : "physical", | ||
114 | (__entry->e & (1<<15)) ? "level" : "edge", | ||
115 | (__entry->e & (1<<16)) ? "|masked" : "") | ||
116 | ); | ||
117 | |||
98 | TRACE_EVENT(kvm_msi_set_irq, | 118 | TRACE_EVENT(kvm_msi_set_irq, |
99 | TP_PROTO(__u64 address, __u64 data), | 119 | TP_PROTO(__u64 address, __u64 data), |
100 | TP_ARGS(address, data), | 120 | TP_ARGS(address, data), |
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index e8ce34c9db32..0ba4057d271b 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c | |||
@@ -405,6 +405,26 @@ void kvm_ioapic_clear_all(struct kvm_ioapic *ioapic, int irq_source_id) | |||
405 | spin_unlock(&ioapic->lock); | 405 | spin_unlock(&ioapic->lock); |
406 | } | 406 | } |
407 | 407 | ||
408 | static void kvm_ioapic_eoi_inject_work(struct work_struct *work) | ||
409 | { | ||
410 | int i; | ||
411 | struct kvm_ioapic *ioapic = container_of(work, struct kvm_ioapic, | ||
412 | eoi_inject.work); | ||
413 | spin_lock(&ioapic->lock); | ||
414 | for (i = 0; i < IOAPIC_NUM_PINS; i++) { | ||
415 | union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i]; | ||
416 | |||
417 | if (ent->fields.trig_mode != IOAPIC_LEVEL_TRIG) | ||
418 | continue; | ||
419 | |||
420 | if (ioapic->irr & (1 << i) && !ent->fields.remote_irr) | ||
421 | ioapic_service(ioapic, i, false); | ||
422 | } | ||
423 | spin_unlock(&ioapic->lock); | ||
424 | } | ||
425 | |||
426 | #define IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT 10000 | ||
427 | |||
408 | static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, | 428 | static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, |
409 | struct kvm_ioapic *ioapic, int vector, int trigger_mode) | 429 | struct kvm_ioapic *ioapic, int vector, int trigger_mode) |
410 | { | 430 | { |
@@ -435,8 +455,26 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, | |||
435 | 455 | ||
436 | ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); | 456 | ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); |
437 | ent->fields.remote_irr = 0; | 457 | ent->fields.remote_irr = 0; |
438 | if (ioapic->irr & (1 << i)) | 458 | if (!ent->fields.mask && (ioapic->irr & (1 << i))) { |
439 | ioapic_service(ioapic, i, false); | 459 | ++ioapic->irq_eoi[i]; |
460 | if (ioapic->irq_eoi[i] == IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT) { | ||
461 | /* | ||
462 | * Real hardware does not deliver the interrupt | ||
463 | * immediately during eoi broadcast, and this | ||
464 | * lets a buggy guest make slow progress | ||
465 | * even if it does not correctly handle a | ||
466 | * level-triggered interrupt. Emulate this | ||
467 | * behavior if we detect an interrupt storm. | ||
468 | */ | ||
469 | schedule_delayed_work(&ioapic->eoi_inject, HZ / 100); | ||
470 | ioapic->irq_eoi[i] = 0; | ||
471 | trace_kvm_ioapic_delayed_eoi_inj(ent->bits); | ||
472 | } else { | ||
473 | ioapic_service(ioapic, i, false); | ||
474 | } | ||
475 | } else { | ||
476 | ioapic->irq_eoi[i] = 0; | ||
477 | } | ||
440 | } | 478 | } |
441 | } | 479 | } |
442 | 480 | ||
@@ -565,12 +603,14 @@ static void kvm_ioapic_reset(struct kvm_ioapic *ioapic) | |||
565 | { | 603 | { |
566 | int i; | 604 | int i; |
567 | 605 | ||
606 | cancel_delayed_work_sync(&ioapic->eoi_inject); | ||
568 | for (i = 0; i < IOAPIC_NUM_PINS; i++) | 607 | for (i = 0; i < IOAPIC_NUM_PINS; i++) |
569 | ioapic->redirtbl[i].fields.mask = 1; | 608 | ioapic->redirtbl[i].fields.mask = 1; |
570 | ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS; | 609 | ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS; |
571 | ioapic->ioregsel = 0; | 610 | ioapic->ioregsel = 0; |
572 | ioapic->irr = 0; | 611 | ioapic->irr = 0; |
573 | ioapic->id = 0; | 612 | ioapic->id = 0; |
613 | memset(ioapic->irq_eoi, 0x00, IOAPIC_NUM_PINS); | ||
574 | rtc_irq_eoi_tracking_reset(ioapic); | 614 | rtc_irq_eoi_tracking_reset(ioapic); |
575 | update_handled_vectors(ioapic); | 615 | update_handled_vectors(ioapic); |
576 | } | 616 | } |
@@ -589,6 +629,7 @@ int kvm_ioapic_init(struct kvm *kvm) | |||
589 | if (!ioapic) | 629 | if (!ioapic) |
590 | return -ENOMEM; | 630 | return -ENOMEM; |
591 | spin_lock_init(&ioapic->lock); | 631 | spin_lock_init(&ioapic->lock); |
632 | INIT_DELAYED_WORK(&ioapic->eoi_inject, kvm_ioapic_eoi_inject_work); | ||
592 | kvm->arch.vioapic = ioapic; | 633 | kvm->arch.vioapic = ioapic; |
593 | kvm_ioapic_reset(ioapic); | 634 | kvm_ioapic_reset(ioapic); |
594 | kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops); | 635 | kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops); |
@@ -609,6 +650,7 @@ void kvm_ioapic_destroy(struct kvm *kvm) | |||
609 | { | 650 | { |
610 | struct kvm_ioapic *ioapic = kvm->arch.vioapic; | 651 | struct kvm_ioapic *ioapic = kvm->arch.vioapic; |
611 | 652 | ||
653 | cancel_delayed_work_sync(&ioapic->eoi_inject); | ||
612 | if (ioapic) { | 654 | if (ioapic) { |
613 | kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &ioapic->dev); | 655 | kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &ioapic->dev); |
614 | kvm->arch.vioapic = NULL; | 656 | kvm->arch.vioapic = NULL; |
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h index 90d43e95dcf8..e23b70634f1e 100644 --- a/virt/kvm/ioapic.h +++ b/virt/kvm/ioapic.h | |||
@@ -59,6 +59,8 @@ struct kvm_ioapic { | |||
59 | spinlock_t lock; | 59 | spinlock_t lock; |
60 | DECLARE_BITMAP(handled_vectors, 256); | 60 | DECLARE_BITMAP(handled_vectors, 256); |
61 | struct rtc_status rtc_status; | 61 | struct rtc_status rtc_status; |
62 | struct delayed_work eoi_inject; | ||
63 | u32 irq_eoi[IOAPIC_NUM_PINS]; | ||
62 | }; | 64 | }; |
63 | 65 | ||
64 | #ifdef DEBUG | 66 | #ifdef DEBUG |