From mboxrd@z Thu Jan 1 00:00:00 1970 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Subject: [PATCH v2 01/14] KVM: x86: change PIT discard tick policy Date: Wed, 17 Feb 2016 20:14:43 +0100 Message-ID: <1455736496-374-2-git-send-email-rkrcmar@redhat.com> References: <1455736496-374-1-git-send-email-rkrcmar@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: kvm@vger.kernel.org, Paolo Bonzini , Yuki Shibuya To: linux-kernel@vger.kernel.org Return-path: In-Reply-To: <1455736496-374-1-git-send-email-rkrcmar@redhat.com> Sender: linux-kernel-owner@vger.kernel.org List-Id: kvm.vger.kernel.org Discard policy uses ack_notifiers to prevent injection of PIT interrupt= s before EOI from the last one. This patch changes the policy to always try to deliver the interrupt, which makes a difference when its vector is in ISR. Old implementation would drop the interrupt, but proposed one injects t= o IRR, like real hardware would. The old policy breaks legacy NMI watchdogs, where PIT is used through virtual wire (LVT0): PIT never sends an interrupt before receiving EOI, thus a guest deadlock with disabled interrupts will stop NMIs. Note that NMI doesn't do EOI, so PIT also had to send a normal interrup= t through IOAPIC. (KVM's PIT is deeply rotten and luckily not used much in modern systems.) Even though there is a chance of regressions, I think we can fix the LVT0 NMI bug without introducing a new tick policy. Cc: Reported-by: Yuki Shibuya Signed-off-by: Radim Kr=C4=8Dm=C3=A1=C5=99 --- v2: resolve dependencies to make it the first patch arch/x86/kvm/i8254.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index b0ea42b78ccd..ab5318727579 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -245,7 +245,7 @@ static void kvm_pit_ack_irq(struct kvm_irq_ack_noti= fier *kian) * PIC is being reset. Handle it gracefully here */ atomic_inc(&ps->pending); - else if (value > 0) + else if (value > 0 && ps->reinject) /* in this case, we had multiple outstanding pit interrupts * that we needed to inject. Reinject */ @@ -288,7 +288,9 @@ static void pit_do_work(struct kthread_work *work) * last one has been acked. */ spin_lock(&ps->inject_lock); - if (ps->irq_ack) { + if (!ps->reinject) + inject =3D 1; + else if (ps->irq_ack) { ps->irq_ack =3D 0; inject =3D 1; } @@ -317,10 +319,10 @@ static enum hrtimer_restart pit_timer_fn(struct h= rtimer *data) struct kvm_kpit_state *ps =3D container_of(data, struct kvm_kpit_stat= e, timer); struct kvm_pit *pt =3D ps->kvm->arch.vpit; =20 - if (ps->reinject || !atomic_read(&ps->pending)) { + if (ps->reinject) atomic_inc(&ps->pending); - queue_kthread_work(&pt->worker, &pt->expired); - } + + queue_kthread_work(&pt->worker, &pt->expired); =20 if (ps->is_periodic) { hrtimer_add_expires_ns(&ps->timer, ps->period); --=20 2.7.1