[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-4.0-testing] IRQ: manually EOI migrating line interrupts



# HG changeset patch
# User Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
# Date 1314801477 -3600
# Node ID 0383662ea34cb24314ff614a6abed8294e6c14c3
# Parent  4b7b75ace86391ca337198857be65491adf08756
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@xxxxxxxxxx>
xen-unstable changeset:   23805:7048810180de
xen-unstable date:        Wed Aug 31 15:19:24 2011 +0100
---


diff -r 4b7b75ace863 -r 0383662ea34c xen/arch/x86/hpet.c
--- a/xen/arch/x86/hpet.c       Thu Aug 25 15:36:50 2011 +0100
+++ b/xen/arch/x86/hpet.c       Wed Aug 31 15:37:57 2011 +0100
@@ -297,7 +297,7 @@
     ack_APIC_irq();
 }
 
-static void hpet_msi_end(unsigned int irq)
+static void hpet_msi_end(unsigned int irq, u8 vector)
 {
 }
 
diff -r 4b7b75ace863 -r 0383662ea34c xen/arch/x86/hvm/vmx/vpmu_core2.c
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c Thu Aug 25 15:36:50 2011 +0100
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c Wed Aug 31 15:37:57 2011 +0100
@@ -55,7 +55,8 @@
     is_pmc_quirk = 0;
     if ( family == 6 )
     {
-        if ( cpu_model == 46 || cpu_model == 26 )
+        if ( cpu_model == 47 || cpu_model == 46 || cpu_model == 42 ||
+             cpu_model == 26 )
             is_pmc_quirk = 1;
     }
 }
diff -r 4b7b75ace863 -r 0383662ea34c xen/arch/x86/i8259.c
--- a/xen/arch/x86/i8259.c      Thu Aug 25 15:36:50 2011 +0100
+++ b/xen/arch/x86/i8259.c      Wed Aug 31 15:37:57 2011 +0100
@@ -91,7 +91,7 @@
     return 0; /* never anything pending */
 }
 
-static void end_8259A_irq(unsigned int irq)
+static void end_8259A_irq(unsigned int irq, u8 vector)
 {
     if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
         enable_8259A_irq(irq);
diff -r 4b7b75ace863 -r 0383662ea34c xen/arch/x86/io_apic.c
--- a/xen/arch/x86/io_apic.c    Thu Aug 25 15:36:50 2011 +0100
+++ b/xen/arch/x86/io_apic.c    Wed Aug 31 15:37:57 2011 +0100
@@ -1651,7 +1651,7 @@
     }
 }
 
-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;
@@ -1700,6 +1700,14 @@
  */
     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();
@@ -1724,9 +1732,9 @@
 {
 }
 
-static void end_edge_ioapic_irq(unsigned int irq)
- {
- }
+static void end_edge_ioapic_irq(unsigned int irq, u8 vector)
+{
+}
 
 /*
  * Level and edge triggered IO-APIC interrupts need different handling,
@@ -1775,7 +1783,7 @@
         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 */
@@ -1828,7 +1836,7 @@
     ack_APIC_irq();
 }
 
-static void end_lapic_irq(unsigned int irq) { /* nothing */ }
+#define end_lapic_irq end_edge_ioapic_irq
 
 static hw_irq_controller lapic_irq_type = {
     .typename  = "local-APIC-edge",
diff -r 4b7b75ace863 -r 0383662ea34c xen/arch/x86/irq.c
--- a/xen/arch/x86/irq.c        Thu Aug 25 15:36:50 2011 +0100
+++ b/xen/arch/x86/irq.c        Wed Aug 31 15:37:57 2011 +0100
@@ -307,6 +307,7 @@
 void no_action(int cpl, void *dev_id, struct cpu_user_regs *regs) { }
 
 static void enable_none(unsigned int vector) { }
+static void end_none(unsigned int irq, u8 vector) { }
 static unsigned int startup_none(unsigned int vector) { return 0; }
 static void disable_none(unsigned int vector) { }
 static void ack_none(unsigned int irq)
@@ -315,7 +316,6 @@
 }
 
 #define shutdown_none   disable_none
-#define end_none        enable_none
 
 hw_irq_controller no_irq_type = {
     "none",
@@ -345,6 +345,7 @@
     static int current_vector = FIRST_DYNAMIC_VECTOR, current_offset = 0;
     unsigned int old_vector;
     int cpu, err;
+    unsigned long flags;
     cpumask_t tmp_mask;
 
     if ((cfg->move_in_progress) || cfg->move_cleanup_count)
@@ -392,6 +393,7 @@
         /* Found one! */
         current_vector = vector;
         current_offset = offset;
+        local_irq_save(flags);
         if (old_vector) {
             cfg->move_in_progress = 1;
             cpus_copy(cfg->old_domain, cfg->domain);
@@ -405,6 +407,7 @@
             if (IO_APIC_IRQ(irq))
                     irq_vector[irq] = vector;
         err = 0;
+        local_irq_restore(flags);
         break;
     }
     return err;
@@ -599,7 +602,7 @@
     desc->status &= ~IRQ_INPROGRESS;
 
  out:
-    desc->handler->end(irq);
+    desc->handler->end(irq, regs->entry_vector);
  out_no_end:
     spin_unlock(&desc->lock);
     irq_exit();
@@ -815,7 +818,7 @@
     switch ( action->ack_type )
     {
     case ACKTYPE_UNMASK:
-        desc->handler->end(irq);
+        desc->handler->end(irq, 0);
         break;
     case ACKTYPE_EOI:
         cpu_eoi_map = action->cpu_eoi_map;
@@ -846,7 +849,7 @@
         /* An interrupt may slip through while freeing an ACKTYPE_EOI irq. */
         ASSERT(action->ack_type == ACKTYPE_EOI);
         ASSERT(desc->status & IRQ_DISABLED);
-        desc->handler->end(irq);
+        desc->handler->end(irq, vector);
         return;
     }
 
@@ -957,7 +960,7 @@
         ASSERT(irq > 0);
         desc = irq_to_desc(irq);
         spin_lock(&desc->lock);
-        desc->handler->end(irq);
+        desc->handler->end(irq, peoi[sp].vector);
         spin_unlock(&desc->lock);
     }
 
@@ -1038,7 +1041,7 @@
     if ( action->ack_type == ACKTYPE_UNMASK )
     {
         ASSERT(cpus_empty(action->cpu_eoi_map));
-        desc->handler->end(irq);
+        desc->handler->end(irq, 0);
         spin_unlock_irq(&desc->lock);
         return;
     }
@@ -1298,7 +1301,7 @@
     case ACKTYPE_UNMASK:
         if ( test_and_clear_bit(pirq, d->pirq_mask) &&
              (--action->in_flight == 0) )
-            desc->handler->end(irq);
+            desc->handler->end(irq, 0);
         break;
     case ACKTYPE_EOI:
         /* NB. If #guests == 0 then we clear the eoi_map later on. */
diff -r 4b7b75ace863 -r 0383662ea34c xen/drivers/passthrough/amd/iommu_init.c
--- a/xen/drivers/passthrough/amd/iommu_init.c  Thu Aug 25 15:36:50 2011 +0100
+++ b/xen/drivers/passthrough/amd/iommu_init.c  Wed Aug 31 15:37:57 2011 +0100
@@ -437,7 +437,7 @@
     return 0;
 }
 
-static void iommu_msi_end(unsigned int irq)
+static void iommu_msi_end(unsigned int irq, u8 vector)
 {
     iommu_msi_unmask(irq);
     ack_APIC_irq();
diff -r 4b7b75ace863 -r 0383662ea34c xen/drivers/passthrough/vtd/iommu.c
--- a/xen/drivers/passthrough/vtd/iommu.c       Thu Aug 25 15:36:50 2011 +0100
+++ b/xen/drivers/passthrough/vtd/iommu.c       Wed Aug 31 15:37:57 2011 +0100
@@ -967,7 +967,7 @@
     return 0;
 }
 
-static void dma_msi_end(unsigned int irq)
+static void dma_msi_end(unsigned int irq, u8 vector)
 {
     dma_msi_unmask(irq);
     ack_APIC_irq();
diff -r 4b7b75ace863 -r 0383662ea34c xen/include/xen/irq.h
--- a/xen/include/xen/irq.h     Thu Aug 25 15:36:50 2011 +0100
+++ b/xen/include/xen/irq.h     Wed Aug 31 15:37:57 2011 +0100
@@ -43,7 +43,7 @@
     void (*enable)(unsigned int irq);
     void (*disable)(unsigned int irq);
     void (*ack)(unsigned int irq);
-    void (*end)(unsigned int irq);
+    void (*end)(unsigned int irq, u8 vector);
     void (*set_affinity)(unsigned int irq, cpumask_t mask);
 };
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.