From patchwork Thu Dec 27 05:39:53 2012
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: [KVM,v2,1/4] KVM: fix i8254 IRQ0 to be normally high
From: Matthew Ogilvie
X-Patchwork-Id: 208251
Message-Id: <1356586796-7631-2-git-send-email-mmogilvi_qemu@miniinfo.net>
To: qemu-devel@nongnu.org
Cc: Gleb Natapov , Jan Kiszka ,
Matthew Ogilvie ,
kvm@vger.kernel.org, "Maciej W. Rozycki"
Date: Wed, 26 Dec 2012 22:39:53 -0700
Reading the spec, it is clear that most modes normally leave the IRQ
output line high, and only pulse it low to generate a leading edge.
Especially the most commonly used mode 2.
The KVM i8254 model does not try to emulate the duration of the pulse at
all, so just swap the high/low settings it to leave it high most of
the time.
This fix is a prerequisite to improving the i8259 model to handle
the trailing edge of an interupt request as indicated in its spec:
If it gets a trailing edge of an IRQ line before it starts to service
the interrupt, the request should be canceled.
See http://bochs.sourceforge.net/techspec/intel-82c54-timer.pdf.gz
or search the net for 23124406.pdf.
Risks:
There is a risk that migrating a running guest between versions
with and without this patch will lose or gain a single timer
interrupt during the migration process. The only case where
this is likely to be serious is probably losing a single-shot (mode 4)
interrupt, but if my understanding of how things work is good, then
that should only be possible if a whole slew of conditions are
all met:
1. The guest is configured to run in a "tickless" mode (like
modern Linux).
2. The guest is for some reason still using the i8254 rather
than something more modern like an HPET. (The combination
of 1 and 2 should be rare.)
3. The migration is going from a fixed version back to the
old version. (Not sure how common this is, but it should
be rarer than migrating from old to new.)
4. There are not going to be any "timely" events/interrupts
(keyboard, network, process sleeps, etc) that cause the guest
to reset the PIT mode 4 one-shot counter "soon enough".
This combination should be rare enough that more complicated
solutions are not worth the effort.
Signed-off-by: Matthew Ogilvie
---
arch/x86/kvm/i8254.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index c1d30b2..cd4ec60 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -290,8 +290,12 @@ static void pit_do_work(struct kthread_work *work)
}
spin_unlock(&ps->inject_lock);
if (inject) {
- kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1);
+ /* Clear previous interrupt, then create a rising
+ * edge to request another interupt, and leave it at
+ * level=1 until time to inject another one.
+ */
kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0);
+ kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1);
/*
* Provides NMI watchdog support via Virtual Wire mode.