aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
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)