]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/powerpc/sysdev/mpic.c
powerpc/mpic: Fix regression caused by change of default IRQ affinity
[linux-2.6-omap-h63xx.git] / arch / powerpc / sysdev / mpic.c
index 6c90c95b454e897f3210c01692c8f2c867d47e62..f6299cca7814b8eda0434e94953db9fe6b38ba9e 100644 (file)
@@ -563,6 +563,51 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
 
 #endif /* CONFIG_MPIC_U3_HT_IRQS */
 
+#ifdef CONFIG_SMP
+static int irq_choose_cpu(unsigned int virt_irq)
+{
+       cpumask_t mask = irq_desc[virt_irq].affinity;
+       int cpuid;
+
+       if (cpus_equal(mask, CPU_MASK_ALL)) {
+               static int irq_rover;
+               static DEFINE_SPINLOCK(irq_rover_lock);
+               unsigned long flags;
+
+               /* Round-robin distribution... */
+       do_round_robin:
+               spin_lock_irqsave(&irq_rover_lock, flags);
+
+               while (!cpu_online(irq_rover)) {
+                       if (++irq_rover >= NR_CPUS)
+                               irq_rover = 0;
+               }
+               cpuid = irq_rover;
+               do {
+                       if (++irq_rover >= NR_CPUS)
+                               irq_rover = 0;
+               } while (!cpu_online(irq_rover));
+
+               spin_unlock_irqrestore(&irq_rover_lock, flags);
+       } else {
+               cpumask_t tmp;
+
+               cpus_and(tmp, cpu_online_map, mask);
+
+               if (cpus_empty(tmp))
+                       goto do_round_robin;
+
+               cpuid = first_cpu(tmp);
+       }
+
+       return cpuid;
+}
+#else
+static int irq_choose_cpu(unsigned int virt_irq)
+{
+       return hard_smp_processor_id();
+}
+#endif
 
 #define mpic_irq_to_hw(virq)   ((unsigned int)irq_map[virq].hwirq)
 
@@ -777,12 +822,18 @@ void mpic_set_affinity(unsigned int irq, cpumask_t cpumask)
        struct mpic *mpic = mpic_from_irq(irq);
        unsigned int src = mpic_irq_to_hw(irq);
 
-       cpumask_t tmp;
+       if (mpic->flags & MPIC_SINGLE_DEST_CPU) {
+               int cpuid = irq_choose_cpu(irq);
 
-       cpus_and(tmp, cpumask, cpu_online_map);
+               mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
+       } else {
+               cpumask_t tmp;
+
+               cpus_and(tmp, cpumask, cpu_online_map);
 
-       mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION),
-                      mpic_physmask(cpus_addr(tmp)[0]));       
+               mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION),
+                              mpic_physmask(cpus_addr(tmp)[0]));
+       }
 }
 
 static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type)
@@ -1016,13 +1067,11 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        memset(mpic, 0, sizeof(struct mpic));
        mpic->name = name;
 
-       mpic->irqhost = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LINEAR,
+       mpic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
                                       isu_size, &mpic_host_ops,
                                       flags & MPIC_LARGE_VECTORS ? 2048 : 256);
-       if (mpic->irqhost == NULL) {
-               of_node_put(node);
+       if (mpic->irqhost == NULL)
                return NULL;
-       }
 
        mpic->irqhost->host_data = mpic;
        mpic->hc_irq = mpic_irq_chip;
@@ -1143,10 +1192,14 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));
        mpic->num_cpus = ((greg_feature & MPIC_GREG_FEATURE_LAST_CPU_MASK)
                          >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1;
-       if (isu_size == 0)
-               mpic->num_sources =
-                       ((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK)
-                        >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1;
+       if (isu_size == 0) {
+               if (flags & MPIC_BROKEN_FRR_NIRQS)
+                       mpic->num_sources = mpic->irq_count;
+               else
+                       mpic->num_sources =
+                               ((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK)
+                                >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1;
+       }
 
        /* Map the per-CPU registers */
        for (i = 0; i < mpic->num_cpus; i++) {