aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/io_apic.c
diff options
context:
space:
mode:
authorAndrew Cooper <andrew.cooper3@citrix.com>2011-08-31 15:19:24 +0100
committerAndrew Cooper <andrew.cooper3@citrix.com>2011-08-31 15:19:24 +0100
commit12b6ea528fd6048bebcaee852d1b6be811907be3 (patch)
treed49822a6409db3602a8b945abc2f0ae9e1bc424d /xen/arch/x86/io_apic.c
parenta81d0ee933c35323f32269dad37977934b6cbb28 (diff)
downloadxen-12b6ea528fd6048bebcaee852d1b6be811907be3.tar.gz
xen-12b6ea528fd6048bebcaee852d1b6be811907be3.tar.bz2
xen-12b6ea528fd6048bebcaee852d1b6be811907be3.zip
IRQ: manually EOI migrating line interrupts
When migrating IO-APIC line level interrupts between PCPUs, the migration code rewrites the IO-APIC entry to point to the new CPU/Vector before EOI'ing it. The EOI process says that EOI'ing the Local APIC will cause a broadcast with the vector number, which the IO-APIC must listen to to clear the IRR and Status bits. In the case of migrating, the IO-APIC has already been reprogrammed so the EOI broadcast with the old vector fails to match the new vector, leaving the IO-APIC with an outstanding vector, preventing any more use of that line interrupt. This causes a lockup especially when your root device is using PCI INTA (megaraid_sas driver *ehem*) However, the problem is mostly hidden because send_cleanup_vector() causes a cleanup of all moving vectors on the current PCPU in such a way which does not cause the problem, and if the problem has occured, the writes it makes to the IO-APIC clears the IRR and Status bits which unlocks the problem. This fix is distinctly a temporary hack, waiting on a cleanup of the irq code. It checks for the edge case where we have moved the irq, and manually EOI's the old vector with the IO-APIC which correctly clears the IRR and Status bits. Also, it protects the code which updates irq_cfg by disabling interrupts. Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Diffstat (limited to 'xen/arch/x86/io_apic.c')
-rw-r--r--xen/arch/x86/io_apic.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c
index 471f7530e4..b333626791 100644
--- a/xen/arch/x86/io_apic.c
+++ b/xen/arch/x86/io_apic.c
@@ -1691,7 +1691,7 @@ static void mask_and_ack_level_ioapic_irq (unsigned int irq)
}
}
-static void end_level_ioapic_irq (unsigned int irq)
+static void end_level_ioapic_irq (unsigned int irq, u8 vector)
{
unsigned long v;
int i;
@@ -1740,6 +1740,14 @@ static void end_level_ioapic_irq (unsigned int irq)
*/
i = IO_APIC_VECTOR(irq);
+ /* Manually EOI the old vector if we are moving to the new */
+ if ( vector && i != vector )
+ {
+ int ioapic;
+ for (ioapic = 0; ioapic < nr_ioapics; ioapic++)
+ io_apic_eoi(ioapic, i);
+ }
+
v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
ack_APIC_irq();
@@ -1763,7 +1771,10 @@ static void disable_edge_ioapic_irq(unsigned int irq)
{
}
-#define end_edge_ioapic_irq disable_edge_ioapic_irq
+static void end_edge_ioapic_irq(unsigned int irq, u8 vector)
+{
+}
+
/*
* Level and edge triggered IO-APIC interrupts need different handling,
@@ -1812,7 +1823,7 @@ static void ack_msi_irq(unsigned int irq)
ack_APIC_irq(); /* ACKTYPE_NONE */
}
-static void end_msi_irq(unsigned int irq)
+static void end_msi_irq(unsigned int irq, u8 vector)
{
if ( !msi_maskable_irq(irq_desc[irq].msi_desc) )
ack_APIC_irq(); /* ACKTYPE_EOI */