powerpc: Hugetlb pgtable cache access cleanup
[safe/jmp/linux-2.6] / arch / powerpc / sysdev / mpic.c
index 6131fd2..f6299cc 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);
+
+               mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
+       } else {
+               cpumask_t tmp;
 
-       cpus_and(tmp, cpumask, cpu_online_map);
+               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++) {
@@ -1331,6 +1384,9 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
        unsigned long flags;
        u32 reg;
 
+       if (!mpic)
+               return;
+
        spin_lock_irqsave(&mpic_lock, flags);
        if (is_ipi) {
                reg = mpic_ipi_read(src - mpic->ipi_vecs[0]) &
@@ -1346,23 +1402,6 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
        spin_unlock_irqrestore(&mpic_lock, flags);
 }
 
-unsigned int mpic_irq_get_priority(unsigned int irq)
-{
-       unsigned int is_ipi;
-       struct mpic *mpic = mpic_find(irq, &is_ipi);
-       unsigned int src = mpic_irq_to_hw(irq);
-       unsigned long flags;
-       u32 reg;
-
-       spin_lock_irqsave(&mpic_lock, flags);
-       if (is_ipi)
-               reg = mpic_ipi_read(src = mpic->ipi_vecs[0]);
-       else
-               reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
-       spin_unlock_irqrestore(&mpic_lock, flags);
-       return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT;
-}
-
 void mpic_setup_this_cpu(void)
 {
 #ifdef CONFIG_SMP
@@ -1410,11 +1449,6 @@ void mpic_cpu_set_priority(int prio)
        mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), prio);
 }
 
-/*
- * XXX: someone who knows mpic should check this.
- * do we need to eoi the ipi including for kexec cpu here (see xics comments)?
- * or can we reset the mpic in the new kernel?
- */
 void mpic_teardown_this_cpu(int secondary)
 {
        struct mpic *mpic = mpic_primary;
@@ -1434,6 +1468,10 @@ void mpic_teardown_this_cpu(int secondary)
 
        /* Set current processor priority to max */
        mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
+       /* We need to EOI the IPI since not all platforms reset the MPIC
+        * on boot and new interrupts wouldn't get delivered otherwise.
+        */
+       mpic_eoi(mpic);
 
        spin_unlock_irqrestore(&mpic_lock, flags);
 }
@@ -1509,7 +1547,7 @@ void mpic_request_ipis(void)
        static char *ipi_names[] = {
                "IPI0 (call function)",
                "IPI1 (reschedule)",
-               "IPI2 (unused)",
+               "IPI2 (call function single)",
                "IPI3 (debugger break)",
        };
        BUG_ON(mpic == NULL);