]> xenbits.xensource.com Git - people/julieng/xen-unstable.git/commitdiff
x86: fixup IRQs when CPUs go down during shutdown
authorRoss Lagerwall <ross.lagerwall@citrix.com>
Thu, 10 Dec 2015 12:14:53 +0000 (13:14 +0100)
committerJan Beulich <jbeulich@suse.com>
Thu, 10 Dec 2015 12:14:53 +0000 (13:14 +0100)
Commit fc0c3fa2ad5c ("x86/IO-APIC: fix setup of Xen internally used IRQs
(take 2)") introduced a regression on some hardware where Xen would hang
during shutdown, repeating the following message:
APIC error on CPU0: 08(08), Receive accept error

This appears to be because an interrupt (in this case from the serial
console) destined for a CPU other than the boot CPU is left unhandled so
an APIC error on CPU 0 is generated instead.

To fix this, before taking down the non-boot CPUs, call fixup_irqs()
with a CPU mask of only the boot CPU to reset the IRQ affinities
correctly.

Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
xen/arch/x86/irq.c
xen/arch/x86/smp.c
xen/arch/x86/smpboot.c
xen/include/asm-x86/irq.h

index 5f515a09f942d19188053906a39ed980b8e30f5f..122856827520653ff94cd6f6935fae92d4f21bf8 100644 (file)
@@ -2328,14 +2328,12 @@ static int __init setup_dump_irqs(void)
 }
 __initcall(setup_dump_irqs);
 
-/* A cpu has been removed from cpu_online_mask.  Re-set irq affinities. */
-void fixup_irqs(void)
+/* Reset irq affinities to match the given CPU mask. */
+void fixup_irqs(const cpumask_t *mask, bool_t verbose)
 {
-    unsigned int irq, sp;
+    unsigned int irq;
     static int warned;
     struct irq_desc *desc;
-    irq_guest_action_t *action;
-    struct pending_eoi *peoi;
 
     for ( irq = 0; irq < nr_irqs; irq++ )
     {
@@ -2355,21 +2353,20 @@ void fixup_irqs(void)
         vector = irq_to_vector(irq);
         if ( vector >= FIRST_HIPRIORITY_VECTOR &&
              vector <= LAST_HIPRIORITY_VECTOR )
-            cpumask_and(desc->arch.cpu_mask, desc->arch.cpu_mask,
-                        &cpu_online_map);
+            cpumask_and(desc->arch.cpu_mask, desc->arch.cpu_mask, mask);
 
         cpumask_copy(&affinity, desc->affinity);
-        if ( !desc->action || cpumask_subset(&affinity, &cpu_online_map) )
+        if ( !desc->action || cpumask_subset(&affinity, mask) )
         {
             spin_unlock(&desc->lock);
             continue;
         }
 
-        cpumask_and(&affinity, &affinity, &cpu_online_map);
+        cpumask_and(&affinity, &affinity, mask);
         if ( cpumask_empty(&affinity) )
         {
             break_affinity = 1;
-            cpumask_copy(&affinity, &cpu_online_map);
+            cpumask_copy(&affinity, mask);
         }
 
         if ( desc->handler->disable )
@@ -2385,6 +2382,9 @@ void fixup_irqs(void)
 
         spin_unlock(&desc->lock);
 
+        if ( !verbose )
+            continue;
+
         if ( break_affinity && set_affinity )
             printk("Broke affinity for irq %i\n", irq);
         else if ( !set_affinity )
@@ -2395,6 +2395,14 @@ void fixup_irqs(void)
     local_irq_enable();
     mdelay(1);
     local_irq_disable();
+}
+
+void fixup_eoi(void)
+{
+    unsigned int irq, sp;
+    struct irq_desc *desc;
+    irq_guest_action_t *action;
+    struct pending_eoi *peoi;
 
     /* Clean up cpu_eoi_map of every interrupt to exclude this CPU. */
     for ( irq = 0; irq < nr_irqs; irq++ )
index 50ff6c2efd82b9ea1e6943c5e42701f821d98c9d..988b9c2557776b1e762f0f0248e30b1e8007c4ff 100644 (file)
@@ -299,6 +299,10 @@ void smp_send_stop(void)
 {
     int timeout = 10;
 
+    local_irq_disable();
+    fixup_irqs(cpumask_of(smp_processor_id()), 0);
+    local_irq_enable();
+
     smp_call_function(stop_this_cpu, NULL, 0);
 
     /* Wait 10ms for all other CPUs to go offline. */
index 5d48bac1cad33c647e22bb4865e68b7dfb518405..1eb16cb934d202c6703dcf796af621ade0c1750f 100644 (file)
@@ -922,7 +922,8 @@ void __cpu_disable(void)
 
     /* It's now safe to remove this processor from the online map */
     cpumask_clear_cpu(cpu, &cpu_online_map);
-    fixup_irqs();
+    fixup_irqs(&cpu_online_map, 1);
+    fixup_eoi();
 
     if ( cpu_disable_scheduler(cpu) )
         BUG();
index fcf37a3a483dc064e30ffdfa5a4e674a5b30580a..7efdd37de37bc9606dde2cb7f9b6c46c521f9a2d 100644 (file)
@@ -148,8 +148,9 @@ int map_domain_emuirq_pirq(struct domain *d, int pirq, int irq);
 int unmap_domain_pirq_emuirq(struct domain *d, int pirq);
 bool_t hvm_domain_use_pirq(const struct domain *, const struct pirq *);
 
-/* A cpu has been removed from cpu_online_mask.  Re-set irq affinities. */
-void fixup_irqs(void);
+/* Reset irq affinities to match the given CPU mask. */
+void fixup_irqs(const cpumask_t *mask, bool_t verbose);
+void fixup_eoi(void);
 
 int  init_irq_data(void);