aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2008-09-26 03:30:52 -0400
committerAvi Kivity <avi@redhat.com>2008-12-31 09:51:41 -0500
commit23930f9521c9c4d4aa96cdb9d1e1703f3782bb94 (patch)
treef5bf96bdc4515cc976e1dcf1fb950454276aabf8 /arch/x86/kvm
parent66a5a347c2690db4c0756524a8eb5a05e0437aa8 (diff)
KVM: x86: Enable NMI Watchdog via in-kernel PIT source
LINT0 of the LAPIC can be used to route PIT events as NMI watchdog ticks into the guest. This patch aligns the in-kernel irqchip emulation with the user space irqchip with already supports this feature. The trick is to route PIT interrupts to all LAPIC's LVT0 lines. Rebased and slightly polished patch originally posted by Sheng Yang. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Sheng Yang <sheng.yang@intel.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/i8254.c15
-rw-r--r--arch/x86/kvm/irq.h1
-rw-r--r--arch/x86/kvm/lapic.c34
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
604static void __inject_pit_timer_intr(struct kvm *kvm) 604static 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
612void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu) 627void 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);
87void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec); 87void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
88void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); 88void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
89void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); 89void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
90int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type);
90void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); 91void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu);
91void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu); 92void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu);
92void __kvm_migrate_timers(struct kvm_vcpu *vcpu); 93void __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
964static int __inject_apic_timer_irq(struct kvm_lapic *apic) 975int 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); 991static 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
972static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) 996static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)