From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Yang, Sheng" Subject: Re: [PATCH 5/9] kvm-x86: Enable NMI Watchdog via in-kernel PIT source Date: Tue, 23 Sep 2008 14:10:32 +0800 Message-ID: <200809231410.33041.sheng.yang@intel.com> References: <48D392F2.300@siemens.com> <48D394F6.6050606@siemens.com> Mime-Version: 1.0 Content-Type: text/plain; charset="iso-8859-15" Content-Transfer-Encoding: 7bit Cc: "kvm-devel" , Avi Kivity To: Jan Kiszka Return-path: Received: from mga02.intel.com ([134.134.136.20]:27798 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751271AbYIWGKD (ORCPT ); Tue, 23 Sep 2008 02:10:03 -0400 In-Reply-To: <48D394F6.6050606@siemens.com> Content-Disposition: inline Sender: kvm-owner@vger.kernel.org List-ID: On Friday 19 September 2008 20:03:02 Jan Kiszka wrote: > 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 patch and slightly polished patch originally posted by Sheng > Yang. Signed-off-by: Sheng Yang Thanks for pick up this patch again! Have you test some Windows guest with this watchdog? Last time I dropped it because it cause BSOD on some version of Windows(IRQ_NOT_EQUAL_OR_LESS). I don't remember the exactly situation there, but you may have a try. -- regards Yang, Sheng > > Signed-off-by: Jan Kiszka > --- > arch/x86/kvm/i8254.c | 15 +++++++++++++++ > arch/x86/kvm/irq.h | 1 + > arch/x86/kvm/lapic.c | 32 ++++++++++++++++++++++++++++---- > 3 files changed, 44 insertions(+), 4 deletions(-) > > Index: b/arch/x86/kvm/i8254.c > =================================================================== > --- a/arch/x86/kvm/i8254.c > +++ b/arch/x86/kvm/i8254.c > @@ -594,10 +594,25 @@ void kvm_free_pit(struct kvm *kvm) > > static void __inject_pit_timer_intr(struct kvm *kvm) > { > + struct kvm_vcpu *vcpu; > + int i; > + > mutex_lock(&kvm->lock); > kvm_set_irq(kvm, 0, 1); > kvm_set_irq(kvm, 0, 0); > mutex_unlock(&kvm->lock); > + > + /* > + * Provideds NMI watchdog support in IOAPIC mode. > + * The route is: PIT -> PIC -> LVT0 in NMI mode, > + * timer IRQs will continue to flow through the IOAPIC. > + */ > + for (i = 0; i < KVM_MAX_VCPUS; ++i) { > + vcpu = kvm->vcpus[i]; > + if (!vcpu) > + continue; > + kvm_apic_local_deliver(vcpu, APIC_LVT0); > + } > } > > void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu) > Index: b/arch/x86/kvm/irq.h > =================================================================== > --- a/arch/x86/kvm/irq.h > +++ b/arch/x86/kvm/irq.h > @@ -93,6 +93,7 @@ void kvm_unregister_irq_ack_notifier(str > void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec); > void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); > void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); > +int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type); > void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); > void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu); > void __kvm_migrate_timers(struct kvm_vcpu *vcpu); > Index: b/arch/x86/kvm/lapic.c > =================================================================== > --- a/arch/x86/kvm/lapic.c > +++ b/arch/x86/kvm/lapic.c > @@ -382,6 +382,14 @@ static int __apic_accept_irq(struct kvm_ > } > break; > > + case APIC_DM_EXTINT: > + /* > + * Should only be called by kvm_apic_local_deliver() with > LVT0, + * before NMI watchdog was enabled. Already handled > by + * kvm_apic_accept_pic_intr(). > + */ > + break; > + > default: > printk(KERN_ERR "TODO: unsupported delivery mode %x\n", > delivery_mode); > @@ -749,6 +757,9 @@ static void apic_mmio_write(struct kvm_i > case APIC_LVTTHMR: > case APIC_LVTPC: > case APIC_LVT0: > + if (val == APIC_DM_NMI) > + apic_debug("Receive NMI setting on APIC_LVT0 " > + "for cpu %d\n", apic->vcpu->vcpu_id); > case APIC_LVT1: > case APIC_LVTERR: > /* TODO: Check vector */ > @@ -965,12 +976,25 @@ int apic_has_pending_timer(struct kvm_vc > return 0; > } > > -static int __inject_apic_timer_irq(struct kvm_lapic *apic) > +int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type) > { > - int vector; > + struct kvm_lapic *apic = vcpu->arch.apic; > + int vector, mode, trig_mode; > + u32 reg; > + > + if (apic && apic_enabled(apic)) { > + reg = apic_get_reg(apic, lvt_type); > + vector = reg & APIC_VECTOR_MASK; > + mode = reg & APIC_MODE_MASK; > + trig_mode = reg & APIC_LVT_LEVEL_TRIGGER; > + return __apic_accept_irq(apic, mode, vector, 1, trig_mode); > + } > + return 0; > +} > > - vector = apic_lvt_vector(apic, APIC_LVTT); > - return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0); > +static inline int __inject_apic_timer_irq(struct kvm_lapic *apic) > +{ > + return kvm_apic_local_deliver(apic->vcpu, APIC_LVTT); > } > > static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)