diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2008-10-20 04:20:03 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2008-12-31 09:51:47 -0500 |
commit | cc6e462cd54e64858ea25816df87d033229efe56 (patch) | |
tree | 3f34b8be2ec3eb63e06c223b1d75d7068a717318 | |
parent | 8fdb2351d51b040146f10a624387bbd102d851c0 (diff) |
KVM: x86: Optimize NMI watchdog delivery
As suggested by Avi, this patch introduces a counter of VCPUs that have
LVT0 set to NMI mode. Only if the counter > 0, we push the PIT ticks via
all LAPIC LVT0 lines to enable NMI watchdog support.
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>
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/i8254.c | 11 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 23 |
3 files changed, 27 insertions, 8 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 59c3ae10de6c..09e6c56572cb 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -361,6 +361,7 @@ struct kvm_arch{ | |||
361 | struct kvm_ioapic *vioapic; | 361 | struct kvm_ioapic *vioapic; |
362 | struct kvm_pit *vpit; | 362 | struct kvm_pit *vpit; |
363 | struct hlist_head irq_ack_notifier_list; | 363 | struct hlist_head irq_ack_notifier_list; |
364 | int vapics_in_nmi_mode; | ||
364 | 365 | ||
365 | int round_robin_prev_vcpu; | 366 | int round_robin_prev_vcpu; |
366 | unsigned int tss_addr; | 367 | unsigned int tss_addr; |
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index b6fcf5a9e502..e665d1c623ca 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c | |||
@@ -620,11 +620,12 @@ static void __inject_pit_timer_intr(struct kvm *kvm) | |||
620 | * LVT0 to NMI delivery. Other PIC interrupts are just sent to | 620 | * LVT0 to NMI delivery. Other PIC interrupts are just sent to |
621 | * VCPU0, and only if its LVT0 is in EXTINT mode. | 621 | * VCPU0, and only if its LVT0 is in EXTINT mode. |
622 | */ | 622 | */ |
623 | for (i = 0; i < KVM_MAX_VCPUS; ++i) { | 623 | if (kvm->arch.vapics_in_nmi_mode > 0) |
624 | vcpu = kvm->vcpus[i]; | 624 | for (i = 0; i < KVM_MAX_VCPUS; ++i) { |
625 | if (vcpu) | 625 | vcpu = kvm->vcpus[i]; |
626 | kvm_apic_nmi_wd_deliver(vcpu); | 626 | if (vcpu) |
627 | } | 627 | kvm_apic_nmi_wd_deliver(vcpu); |
628 | } | ||
628 | } | 629 | } |
629 | 630 | ||
630 | void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu) | 631 | void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu) |
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 0b0d413f0af5..afac68c0815c 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -130,6 +130,11 @@ static inline int apic_lvtt_period(struct kvm_lapic *apic) | |||
130 | return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC; | 130 | return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC; |
131 | } | 131 | } |
132 | 132 | ||
133 | static inline int apic_lvt_nmi_mode(u32 lvt_val) | ||
134 | { | ||
135 | return (lvt_val & (APIC_MODE_MASK | APIC_LVT_MASKED)) == APIC_DM_NMI; | ||
136 | } | ||
137 | |||
133 | static unsigned int apic_lvt_mask[APIC_LVT_NUM] = { | 138 | static unsigned int apic_lvt_mask[APIC_LVT_NUM] = { |
134 | LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */ | 139 | LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */ |
135 | LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ | 140 | LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ |
@@ -672,6 +677,20 @@ static void start_apic_timer(struct kvm_lapic *apic) | |||
672 | apic->timer.period))); | 677 | apic->timer.period))); |
673 | } | 678 | } |
674 | 679 | ||
680 | static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val) | ||
681 | { | ||
682 | int nmi_wd_enabled = apic_lvt_nmi_mode(apic_get_reg(apic, APIC_LVT0)); | ||
683 | |||
684 | if (apic_lvt_nmi_mode(lvt0_val)) { | ||
685 | if (!nmi_wd_enabled) { | ||
686 | apic_debug("Receive NMI setting on APIC_LVT0 " | ||
687 | "for cpu %d\n", apic->vcpu->vcpu_id); | ||
688 | apic->vcpu->kvm->arch.vapics_in_nmi_mode++; | ||
689 | } | ||
690 | } else if (nmi_wd_enabled) | ||
691 | apic->vcpu->kvm->arch.vapics_in_nmi_mode--; | ||
692 | } | ||
693 | |||
675 | static void apic_mmio_write(struct kvm_io_device *this, | 694 | static void apic_mmio_write(struct kvm_io_device *this, |
676 | gpa_t address, int len, const void *data) | 695 | gpa_t address, int len, const void *data) |
677 | { | 696 | { |
@@ -753,9 +772,7 @@ static void apic_mmio_write(struct kvm_io_device *this, | |||
753 | break; | 772 | break; |
754 | 773 | ||
755 | case APIC_LVT0: | 774 | case APIC_LVT0: |
756 | if (val == APIC_DM_NMI) | 775 | apic_manage_nmi_watchdog(apic, val); |
757 | apic_debug("Receive NMI setting on APIC_LVT0 " | ||
758 | "for cpu %d\n", apic->vcpu->vcpu_id); | ||
759 | case APIC_LVTT: | 776 | case APIC_LVTT: |
760 | case APIC_LVTTHMR: | 777 | case APIC_LVTTHMR: |
761 | case APIC_LVTPC: | 778 | case APIC_LVTPC: |