Merge master.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6
[pandora-kernel.git] / arch / ppc64 / kernel / xics.c
index eedd1d3..d9dc6f2 100644 (file)
@@ -432,6 +432,7 @@ void xics_cause_IPI(int cpu)
 {
        ops->qirr_info(cpu, IPI_PRIORITY);
 }
+#endif /* CONFIG_SMP */
 
 void xics_setup_cpu(void)
 {
@@ -439,9 +440,17 @@ void xics_setup_cpu(void)
 
        ops->cppr_info(cpu, 0xff);
        iosync();
-}
 
-#endif /* CONFIG_SMP */
+       /*
+        * Put the calling processor into the GIQ.  This is really only
+        * necessary from a secondary thread as the OF start-cpu interface
+        * performs this function for us on primary threads.
+        *
+        * XXX: undo of teardown on kexec needs this too, as may hotplug
+        */
+       rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE,
+               (1UL << interrupt_server_size) - 1 - default_distrib_server, 1);
+}
 
 void xics_init_IRQ(void)
 {
@@ -563,8 +572,7 @@ nextnode:
        for (; i < NR_IRQS; ++i)
                get_irq_desc(i)->handler = &xics_pic;
 
-       ops->cppr_info(boot_cpuid, 0xff);
-       iosync();
+       xics_setup_cpu();
 
        ppc64_boot_msg(0x21, "XICS Done");
 }
@@ -639,6 +647,32 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
        }
 }
 
+void xics_teardown_cpu(int secondary)
+{
+       int cpu = smp_processor_id();
+
+       ops->cppr_info(cpu, 0x00);
+       iosync();
+
+       /*
+        * Some machines need to have at least one cpu in the GIQ,
+        * so leave the master cpu in the group.
+        */
+       if (secondary) {
+               /*
+                * we need to EOI the IPI if we got here from kexec down IPI
+                *
+                * probably need to check all the other interrupts too
+                * should we be flagging idle loop instead?
+                * or creating some task to be scheduled?
+                */
+               ops->xirr_info_set(cpu, XICS_IPI);
+               rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE,
+                       (1UL << interrupt_server_size) - 1 -
+                       default_distrib_server, 0);
+       }
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 
 /* Interrupts are disabled. */