From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Yang, Sheng" Subject: [RFC][PATCH 4/4] KVM: Enable NMI Watchdog by PIT source Date: Thu, 8 May 2008 16:55:41 +0800 Message-ID: <200805081655.42087.sheng.yang@intel.com> Mime-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_OAsIIfcgaOy8pOO" To: " kvm-devel" Return-path: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: kvm-devel-bounces@lists.sourceforge.net Errors-To: kvm-devel-bounces@lists.sourceforge.net List-Id: kvm.vger.kernel.org --Boundary-00=_OAsIIfcgaOy8pOO Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline =46rom 176a066e5fd0d98cb63e910c93d57f7ec2850105 Mon Sep 17 00:00:00 2001 =46rom: Sheng Yang Date: Thu, 8 May 2008 16:00:59 +0800 Subject: [PATCH 4/4] KVM: Enable NMI Watchdog by PIT source The NMI watchdog used LINT0 of LAPIC to deliver NMI. It didn't disable PIC= =20 after switch to IOAPIC, but program LVT0 of every LAPIC as NMI, then delive= r=20 PIT interrupt to LINT0. So NMIs got the same generate freqency as PIT=20 interrupts. The patch emulated this process and enabled NMI watchdog. For currently KVM= ,=20 in fact we didn't connected PIC to LAPIC, so the patch bypassed PIC, sent t= he signal directly to the LAPIC. Signed-off-by: Sheng Yang =2D-- arch/x86/kvm/i8254.c | 16 ++++++++++++++++ arch/x86/kvm/irq.h | 1 + arch/x86/kvm/lapic.c | 32 ++++++++++++++++++++++++++++---- arch/x86/kvm/vmx.c | 1 - 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 6d6dc6c..7c6ea62 100644 =2D-- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -563,12 +563,28 @@ void kvm_free_pit(struct kvm *kvm) static void __inject_pit_timer_intr(struct kvm *kvm) { + int i; + struct kvm_vcpu *vcpu; + mutex_lock(&kvm->lock); kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 1); kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 0); kvm_pic_set_irq(pic_irqchip(kvm), 0, 1); kvm_pic_set_irq(pic_irqchip(kvm), 0, 0); mutex_unlock(&kvm->lock); + + /* + * For NMI watchdog in IOAPIC mode + * After IOAPIC enabled, NMI watchdog programmed LVT0 of lapic as NMI, + * then a timer interrupt through IOAPIC and a NMI through PIC to lapic + * would be delivered when PIT time up. + */ + for (i =3D 0; i < KVM_MAX_VCPUS; ++i) { + vcpu =3D kvm->vcpus[i]; + if (!vcpu) + continue; + kvm_apic_local_deliver(vcpu, APIC_LVT0); + } } void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 1802134..7066660 100644 =2D-- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h @@ -84,6 +84,7 @@ 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); void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); +int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type); int pit_has_pending_timer(struct kvm_vcpu *vcpu); int apic_has_pending_timer(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index df5aba9..d790996 100644 =2D-- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -383,6 +383,14 @@ static int __apic_accept_irq(struct kvm_lapic *apic, i= nt=20 delivery_mode, } 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); @@ -748,6 +756,9 @@ static void apic_mmio_write(struct kvm_io_device *this, case APIC_LVTTHMR: case APIC_LVTPC: case APIC_LVT0: + if (val =3D=3D 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 */ @@ -963,12 +974,25 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu) return 0; } =2Dstatic int __inject_apic_timer_irq(struct kvm_lapic *apic) +int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type) { =2D int vector; + struct kvm_lapic *apic =3D vcpu->arch.apic; + int vector, mode, trig_mode; + u32 reg; + + if (apic && apic_enabled(apic)) { + reg =3D apic_get_reg(apic, lvt_type); + vector =3D reg & APIC_VECTOR_MASK; + mode =3D reg & APIC_MODE_MASK; + trig_mode =3D reg & APIC_LVT_LEVEL_TRIGGER; + return __apic_accept_irq(apic, mode, vector, 1, trig_mode); + } + return 0; +} =2D vector =3D apic_lvt_vector(apic, APIC_LVTT); =2D return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0); +static 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) =2D- 1.5.5 --Boundary-00=_OAsIIfcgaOy8pOO Content-Type: text/x-diff; charset="utf-8"; name="0004-KVM-Enable-NMI-Watchdog-by-PIT-source.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="0004-KVM-Enable-NMI-Watchdog-by-PIT-source.patch" =46rom 176a066e5fd0d98cb63e910c93d57f7ec2850105 Mon Sep 17 00:00:00 2001 =46rom: Sheng Yang Date: Thu, 8 May 2008 16:00:59 +0800 Subject: [PATCH 4/4] KVM: Enable NMI Watchdog by PIT source The NMI watchdog used LINT0 of LAPIC to deliver NMI. It didn't disable PIC = after switch to IOAPIC, but program LVT0 of every LAPIC as NMI, then deliver PIT interrupt to LINT0. So NMIs got the same generate freqency as PIT interrupt= s. The patch emulated this process and enabled NMI watchdog. For currently KVM= , in fact we didn't connected PIC to LAPIC, so the patch bypassed PIC, sent the signal directly to the LAPIC. Signed-off-by: Sheng Yang =2D-- arch/x86/kvm/i8254.c | 16 ++++++++++++++++ arch/x86/kvm/irq.h | 1 + arch/x86/kvm/lapic.c | 32 ++++++++++++++++++++++++++++---- arch/x86/kvm/vmx.c | 1 - 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 6d6dc6c..7c6ea62 100644 =2D-- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -563,12 +563,28 @@ void kvm_free_pit(struct kvm *kvm) =20 static void __inject_pit_timer_intr(struct kvm *kvm) { + int i; + struct kvm_vcpu *vcpu; + mutex_lock(&kvm->lock); kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 1); kvm_ioapic_set_irq(kvm->arch.vioapic, 0, 0); kvm_pic_set_irq(pic_irqchip(kvm), 0, 1); kvm_pic_set_irq(pic_irqchip(kvm), 0, 0); mutex_unlock(&kvm->lock); + + /* + * For NMI watchdog in IOAPIC mode + * After IOAPIC enabled, NMI watchdog programmed LVT0 of lapic as NMI, + * then a timer interrupt through IOAPIC and a NMI through PIC to lapic + * would be delivered when PIT time up. + */ + for (i =3D 0; i < KVM_MAX_VCPUS; ++i) { + vcpu =3D kvm->vcpus[i]; + if (!vcpu) + continue; + kvm_apic_local_deliver(vcpu, APIC_LVT0); + } } =20 void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 1802134..7066660 100644 =2D-- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h @@ -84,6 +84,7 @@ 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); void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); +int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type); =20 int pit_has_pending_timer(struct kvm_vcpu *vcpu); int apic_has_pending_timer(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index df5aba9..d790996 100644 =2D-- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -383,6 +383,14 @@ static int __apic_accept_irq(struct kvm_lapic *apic, i= nt delivery_mode, } break; =20 + 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); @@ -748,6 +756,9 @@ static void apic_mmio_write(struct kvm_io_device *this, case APIC_LVTTHMR: case APIC_LVTPC: case APIC_LVT0: + if (val =3D=3D 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 */ @@ -963,12 +974,25 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu) return 0; } =20 =2Dstatic int __inject_apic_timer_irq(struct kvm_lapic *apic) +int kvm_apic_local_deliver(struct kvm_vcpu *vcpu, int lvt_type) { =2D int vector; + struct kvm_lapic *apic =3D vcpu->arch.apic; + int vector, mode, trig_mode; + u32 reg; + + if (apic && apic_enabled(apic)) { + reg =3D apic_get_reg(apic, lvt_type); + vector =3D reg & APIC_VECTOR_MASK; + mode =3D reg & APIC_MODE_MASK; + trig_mode =3D reg & APIC_LVT_LEVEL_TRIGGER; + return __apic_accept_irq(apic, mode, vector, 1, trig_mode); + } + return 0; +} =20 =2D vector =3D apic_lvt_vector(apic, APIC_LVTT); =2D return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0); +static int __inject_apic_timer_irq(struct kvm_lapic *apic) +{ + return kvm_apic_local_deliver(apic->vcpu, APIC_LVTT); } =20 static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) =2D-=20 1.5.5 --Boundary-00=_OAsIIfcgaOy8pOO Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone --Boundary-00=_OAsIIfcgaOy8pOO Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel --Boundary-00=_OAsIIfcgaOy8pOO--