]> xenbits.xensource.com Git - people/iwj/xen.git/commitdiff
xen/gic: EOI irqs on the right pcpu
authorStefano Stabellini <stefano.stabellini@eu.citrix.com>
Tue, 7 May 2013 13:33:08 +0000 (14:33 +0100)
committerIan Campbell <ian.campbell@citrix.com>
Wed, 8 May 2013 10:06:26 +0000 (11:06 +0100)
We need to write the irq number to GICC_DIR on the physical cpu that
previously received the interrupt, but currently we are doing it on the
pcpu that received the maintenance interrupt. As a consequence if a
vcpu is migrated to a different pcpu, the irq is going to be EOI'ed on
the wrong pcpu.

This covers the case where dom0 vcpu0 is running on pcpu1 for example
(you can test this scenario by using xl vcpu-pin).

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
xen/arch/arm/gic.c
xen/arch/arm/irq.c
xen/include/asm-arm/irq.h

index 1bcb0ca28c7c60e121128bba622ed99f4b958d64..2a44cf83be730664952ec9fca6b7157e2873c9ad 100644 (file)
@@ -709,6 +709,12 @@ int gicv_setup(struct domain *d)
                         gic.vbase);
 }
 
+static void gic_irq_eoi(void *info)
+{
+    int virq = (int) info;
+    GICC[GICC_DIR] = virq;
+}
+
 static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
 {
     int i = 0, virq;
@@ -719,6 +725,10 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
     while ((i = find_next_bit((const long unsigned int *) &eisr,
                               64, i)) < 64) {
         struct pending_irq *p;
+        int cpu, eoi;
+
+        cpu = -1;
+        eoi = 0;
 
         spin_lock_irq(&gic.lock);
         lr = GICH[GICH_LR + i];
@@ -740,11 +750,22 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
         p = irq_to_pending(v, virq);
         if ( p->desc != NULL ) {
             p->desc->status &= ~IRQ_INPROGRESS;
-            GICC[GICC_DIR] = virq;
+            /* Assume only one pcpu needs to EOI the irq */
+            cpu = p->desc->arch.eoi_cpu;
+            eoi = 1;
         }
         list_del_init(&p->inflight);
         spin_unlock_irq(&v->arch.vgic.lock);
 
+        if ( eoi ) {
+            /* this is not racy because we can't receive another irq of the
+             * same type until we EOI it.  */
+            if ( cpu == smp_processor_id() )
+                gic_irq_eoi((void*)virq);
+            else
+                on_selected_cpus(cpumask_of(cpu), gic_irq_eoi, (void*)virq, 0);
+        }
+
         i++;
     }
 }
index 8c96a0acb309434503c882edfface051b3dcb977..b2e486f89152a16243201712a85a52b4190fbb10 100644 (file)
@@ -156,6 +156,7 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, int is_fiq)
         desc->handler->end(desc);
 
         desc->status |= IRQ_INPROGRESS;
+        desc->arch.eoi_cpu = smp_processor_id();
 
         /* XXX: inject irq into all guest vcpus */
         vgic_vcpu_inject_irq(d->vcpu[0], irq, 0);
index 9fc008ce617014693e9ee82d3f0d04e48a97afae..eeb733a07722d845277aa49c75ba326239f22e1f 100644 (file)
@@ -15,6 +15,7 @@ struct arch_pirq
 
 struct irq_cfg {
 #define arch_irq_desc irq_cfg
+    int eoi_cpu;
 };
 
 #define NR_LOCAL_IRQS  32