diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2008-10-20 04:20:02 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2008-12-31 09:51:46 -0500 |
commit | 8fdb2351d51b040146f10a624387bbd102d851c0 (patch) | |
tree | c28ff5ec61f51cb1a04b7e29923e4ce3f2aba421 /arch/x86/kvm | |
parent | 291fd39bfc2089c2dae79cf2d7cfca81b14ca769 (diff) |
KVM: x86: Fix and refactor NMI watchdog emulation
This patch refactors the NMI watchdog delivery patch, consolidating
tests and providing a proper API for delivering watchdog events.
An included micro-optimization is to check only for apic_hw_enabled in
kvm_apic_local_deliver (the test for LVT mask is covering the
soft-disabled case already).
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Acked-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r-- | arch/x86/kvm/i8254.c | 15 | ||||
-rw-r--r-- | arch/x86/kvm/irq.h | 2 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 20 |
3 files changed, 20 insertions, 17 deletions
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 580cc1d01c7d..b6fcf5a9e502 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c | |||
@@ -612,15 +612,18 @@ static void __inject_pit_timer_intr(struct kvm *kvm) | |||
612 | mutex_unlock(&kvm->lock); | 612 | mutex_unlock(&kvm->lock); |
613 | 613 | ||
614 | /* | 614 | /* |
615 | * Provides NMI watchdog support in IOAPIC mode. | 615 | * Provides NMI watchdog support via Virtual Wire mode. |
616 | * The route is: PIT -> PIC -> LVT0 in NMI mode, | 616 | * The route is: PIT -> PIC -> LVT0 in NMI mode. |
617 | * timer IRQs will continue to flow through the IOAPIC. | 617 | * |
618 | * Note: Our Virtual Wire implementation is simplified, only | ||
619 | * propagating PIT interrupts to all VCPUs when they have set | ||
620 | * LVT0 to NMI delivery. Other PIC interrupts are just sent to | ||
621 | * VCPU0, and only if its LVT0 is in EXTINT mode. | ||
618 | */ | 622 | */ |
619 | for (i = 0; i < KVM_MAX_VCPUS; ++i) { | 623 | for (i = 0; i < KVM_MAX_VCPUS; ++i) { |
620 | vcpu = kvm->vcpus[i]; | 624 | vcpu = kvm->vcpus[i]; |
621 | if (!vcpu) | 625 | if (vcpu) |
622 | continue; | 626 | kvm_apic_nmi_wd_deliver(vcpu); |
623 | kvm_apic_local_deliver(vcpu, APIC_LVT0); | ||
624 | } | 627 | } |
625 | } | 628 | } |
626 | 629 | ||
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 71e37a530cf7..b9e9051650ea 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h | |||
@@ -87,7 +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_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu); |
91 | void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); | 91 | void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); |
92 | void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu); | 92 | void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu); |
93 | 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 304f9ddbdd51..0b0d413f0af5 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -973,14 +973,12 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu) | |||
973 | return 0; | 973 | return 0; |
974 | } | 974 | } |
975 | 975 | ||
976 | int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type) | 976 | static int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type) |
977 | { | 977 | { |
978 | struct kvm_lapic *apic = vcpu->arch.apic; | 978 | u32 reg = apic_get_reg(apic, lvt_type); |
979 | int vector, mode, trig_mode; | 979 | int vector, mode, trig_mode; |
980 | u32 reg; | ||
981 | 980 | ||
982 | if (apic && apic_enabled(apic)) { | 981 | if (apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) { |
983 | reg = apic_get_reg(apic, lvt_type); | ||
984 | vector = reg & APIC_VECTOR_MASK; | 982 | vector = reg & APIC_VECTOR_MASK; |
985 | mode = reg & APIC_MODE_MASK; | 983 | mode = reg & APIC_MODE_MASK; |
986 | trig_mode = reg & APIC_LVT_LEVEL_TRIGGER; | 984 | trig_mode = reg & APIC_LVT_LEVEL_TRIGGER; |
@@ -989,9 +987,12 @@ int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type) | |||
989 | return 0; | 987 | return 0; |
990 | } | 988 | } |
991 | 989 | ||
992 | static inline int __inject_apic_timer_irq(struct kvm_lapic *apic) | 990 | void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu) |
993 | { | 991 | { |
994 | return kvm_apic_local_deliver(apic->vcpu, APIC_LVTT); | 992 | struct kvm_lapic *apic = vcpu->arch.apic; |
993 | |||
994 | if (apic) | ||
995 | kvm_apic_local_deliver(apic, APIC_LVT0); | ||
995 | } | 996 | } |
996 | 997 | ||
997 | static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) | 998 | static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) |
@@ -1086,9 +1087,8 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) | |||
1086 | { | 1087 | { |
1087 | struct kvm_lapic *apic = vcpu->arch.apic; | 1088 | struct kvm_lapic *apic = vcpu->arch.apic; |
1088 | 1089 | ||
1089 | if (apic && apic_lvt_enabled(apic, APIC_LVTT) && | 1090 | if (apic && atomic_read(&apic->timer.pending) > 0) { |
1090 | atomic_read(&apic->timer.pending) > 0) { | 1091 | if (kvm_apic_local_deliver(apic, APIC_LVTT)) |
1091 | if (__inject_apic_timer_irq(apic)) | ||
1092 | atomic_dec(&apic->timer.pending); | 1092 | atomic_dec(&apic->timer.pending); |
1093 | } | 1093 | } |
1094 | } | 1094 | } |