# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 9a273aabb839dff897be39a581d716dfed952c79
# Parent bb0dc0ae23bb1fe49c197f38951fc424eef2905e
New IO-APIC ACK method seems to cause problems on some systems
(e.g., Dell 1850). Disable it by default for now, but allow the
new mwethod to be tested by passing boot parameter 'new_ack'
to Xen.
You can tell which ACK method you are using because Xen prints
out "Using old ACK method" or "Using new ACK method" during boot.
This workaround can be removed if/when the problems with the new
ACK method are flushed out.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
diff -r bb0dc0ae23bb -r 9a273aabb839 xen/arch/x86/io_apic.c
--- a/xen/arch/x86/io_apic.c Fri Apr 14 11:01:15 2006
+++ b/xen/arch/x86/io_apic.c Fri Apr 14 13:14:24 2006
@@ -188,6 +188,18 @@
static void __unmask_IO_APIC_irq (unsigned int irq)
{
__modify_IO_APIC_irq(irq, 0, 0x00010000);
+}
+
+/* trigger = 0 */
+static void __edge_IO_APIC_irq (unsigned int irq)
+{
+ __modify_IO_APIC_irq(irq, 0, 0x00008000);
+}
+
+/* trigger = 1 */
+static void __level_IO_APIC_irq (unsigned int irq)
+{
+ __modify_IO_APIC_irq(irq, 0x00008000, 0);
}
/* mask = 1, trigger = 0 */
@@ -1321,15 +1333,18 @@
return 0; /* don't check for pending */
}
+static int new_ack;
+boolean_param("new_ack", new_ack);
+
static void mask_and_ack_level_ioapic_irq (unsigned int irq)
-{
-}
-
-static void end_level_ioapic_irq (unsigned int irq)
{
unsigned long v;
int i;
+ if ( new_ack )
+ return;
+
+ mask_IO_APIC_irq(irq);
/*
* It appears there is an erratum which affects at least version 0x11
* of I/O APIC (that's the 82093AA and cores integrated into various
@@ -1358,6 +1373,51 @@
if (!(v & (1 << (i & 0x1f)))) {
atomic_inc(&irq_mis_count);
spin_lock(&ioapic_lock);
+ __edge_IO_APIC_irq(irq);
+ __level_IO_APIC_irq(irq);
+ spin_unlock(&ioapic_lock);
+ }
+}
+
+static void end_level_ioapic_irq (unsigned int irq)
+{
+ unsigned long v;
+ int i;
+
+ if ( !new_ack )
+ {
+ unmask_IO_APIC_irq(irq);
+ return;
+ }
+
+/*
+ * It appears there is an erratum which affects at least version 0x11
+ * of I/O APIC (that's the 82093AA and cores integrated into various
+ * chipsets). Under certain conditions a level-triggered interrupt is
+ * erroneously delivered as edge-triggered one but the respective IRR
+ * bit gets set nevertheless. As a result the I/O unit expects an EOI
+ * message but it will never arrive and further interrupts are blocked
+ * from the source. The exact reason is so far unknown, but the
+ * phenomenon was observed when two consecutive interrupt requests
+ * from a given source get delivered to the same CPU and the source is
+ * temporarily disabled in between.
+ *
+ * A workaround is to simulate an EOI message manually. We achieve it
+ * by setting the trigger mode to edge and then to level when the edge
+ * trigger mode gets detected in the TMR of a local APIC for a
+ * level-triggered interrupt. We mask the source for the time of the
+ * operation to prevent an edge-triggered interrupt escaping meanwhile.
+ * The idea is from Manfred Spraul. --macro
+ */
+ i = IO_APIC_VECTOR(irq);
+
+ v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
+
+ ack_APIC_irq();
+
+ if (!(v & (1 << (i & 0x1f)))) {
+ atomic_inc(&irq_mis_count);
+ spin_lock(&ioapic_lock);
__mask_and_edge_IO_APIC_irq(irq);
__unmask_and_level_IO_APIC_irq(irq);
spin_unlock(&ioapic_lock);
@@ -1693,6 +1753,7 @@
io_apic_irqs = ~PIC_IRQS;
printk("ENABLING IO-APIC IRQs\n");
+ printk(" -> Using %s ACK method\n", new_ack ? "new" : "old");
/*
* Set up IO-APIC IRQ routing.
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|