diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kvm/i8254.c | 15 | ||||
-rw-r--r-- | arch/x86/kvm/irq.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 34 |
3 files changed, 45 insertions, 5 deletions
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 59ebd37ad79e..580cc1d01c7d 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c | |||
@@ -603,10 +603,25 @@ void kvm_free_pit(struct kvm *kvm) | |||
603 | 603 | ||
604 | static void __inject_pit_timer_intr(struct kvm *kvm) | 604 | static void __inject_pit_timer_intr(struct kvm *kvm) |
605 | { | 605 | { |
606 | struct kvm_vcpu *vcpu; | ||
607 | int i; | ||
608 | |||
606 | mutex_lock(&kvm->lock); | 609 | mutex_lock(&kvm->lock); |
607 | kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1); | 610 | kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1); |
608 | kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0); | 611 | kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0); |
609 | mutex_unlock(&kvm->lock); | 612 | mutex_unlock(&kvm->lock); |
613 | |||
614 | /* | ||
615 | * Provides NMI watchdog support in IOAPIC mode. | ||
616 | * The route is: PIT -> PIC -> LVT0 in NMI mode, | ||
617 | * timer IRQs will continue to flow through the IOAPIC. | ||
618 | */ | ||
619 | for (i = 0; i < KVM_MAX_VCPUS; ++i) { | ||
620 | vcpu = kvm->vcpus[i]; | ||
621 | if (!vcpu) | ||
622 | continue; | ||
623 | kvm_apic_local_deliver(vcpu, APIC_LVT0); | ||
624 | } | ||
610 | } | 625 | } |
611 | 626 | ||
612 | void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu) | 627 | void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu) |
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index f17c8f5bbf31..71e37a530cf7 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h | |||
@@ -87,6 +87,7 @@ void kvm_pic_reset(struct kvm_kpic_state *s); | |||
87 | void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec); | 87 | void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec); |
88 | void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); | 88 | void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); |
89 | void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); | 89 | void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); |
90 | int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type); | ||
90 | void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); | 91 | void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); |
91 | void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu); | 92 | void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu); |
92 | void __kvm_migrate_timers(struct kvm_vcpu *vcpu); | 93 | void __kvm_migrate_timers(struct kvm_vcpu *vcpu); |
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 0fc3cab48943..206cc11a1c97 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -380,6 +380,14 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
380 | } | 380 | } |
381 | break; | 381 | break; |
382 | 382 | ||
383 | case APIC_DM_EXTINT: | ||
384 | /* | ||
385 | * Should only be called by kvm_apic_local_deliver() with LVT0, | ||
386 | * before NMI watchdog was enabled. Already handled by | ||
387 | * kvm_apic_accept_pic_intr(). | ||
388 | */ | ||
389 | break; | ||
390 | |||
383 | default: | 391 | default: |
384 | printk(KERN_ERR "TODO: unsupported delivery mode %x\n", | 392 | printk(KERN_ERR "TODO: unsupported delivery mode %x\n", |
385 | delivery_mode); | 393 | delivery_mode); |
@@ -743,10 +751,13 @@ static void apic_mmio_write(struct kvm_io_device *this, | |||
743 | apic_set_reg(apic, APIC_ICR2, val & 0xff000000); | 751 | apic_set_reg(apic, APIC_ICR2, val & 0xff000000); |
744 | break; | 752 | break; |
745 | 753 | ||
754 | case APIC_LVT0: | ||
755 | if (val == APIC_DM_NMI) | ||
756 | apic_debug("Receive NMI setting on APIC_LVT0 " | ||
757 | "for cpu %d\n", apic->vcpu->vcpu_id); | ||
746 | case APIC_LVTT: | 758 | case APIC_LVTT: |
747 | case APIC_LVTTHMR: | 759 | case APIC_LVTTHMR: |
748 | case APIC_LVTPC: | 760 | case APIC_LVTPC: |
749 | case APIC_LVT0: | ||
750 | case APIC_LVT1: | 761 | case APIC_LVT1: |
751 | case APIC_LVTERR: | 762 | case APIC_LVTERR: |
752 | /* TODO: Check vector */ | 763 | /* TODO: Check vector */ |
@@ -961,12 +972,25 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu) | |||
961 | return 0; | 972 | return 0; |
962 | } | 973 | } |
963 | 974 | ||
964 | static int __inject_apic_timer_irq(struct kvm_lapic *apic) | 975 | int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type) |
965 | { | 976 | { |
966 | int vector; | 977 | struct kvm_lapic *apic = vcpu->arch.apic; |
978 | int vector, mode, trig_mode; | ||
979 | u32 reg; | ||
980 | |||
981 | if (apic && apic_enabled(apic)) { | ||
982 | reg = apic_get_reg(apic, lvt_type); | ||
983 | vector = reg & APIC_VECTOR_MASK; | ||
984 | mode = reg & APIC_MODE_MASK; | ||
985 | trig_mode = reg & APIC_LVT_LEVEL_TRIGGER; | ||
986 | return __apic_accept_irq(apic, mode, vector, 1, trig_mode); | ||
987 | } | ||
988 | return 0; | ||
989 | } | ||
967 | 990 | ||
968 | vector = apic_lvt_vector(apic, APIC_LVTT); | 991 | static inline int __inject_apic_timer_irq(struct kvm_lapic *apic) |
969 | return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0); | 992 | { |
993 | return kvm_apic_local_deliver(apic->vcpu, APIC_LVTT); | ||
970 | } | 994 | } |
971 | 995 | ||
972 | static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) | 996 | static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) |