]> err.no Git - linux-2.6/blobdiff - arch/powerpc/platforms/pseries/xics.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6] / arch / powerpc / platforms / pseries / xics.c
index 8f8dd9c3ca6b9dc499d7a2983d63770a9709a719..a977f200db895c6bbdfd4f98cc60a69af65912df 100644 (file)
@@ -160,6 +160,46 @@ static inline void lpar_qirr_info(int n_cpu , u8 value)
 
 /* High level handlers and init code */
 
+static void xics_update_irq_servers(void)
+{
+       int i, j;
+       struct device_node *np;
+       u32 ilen;
+       const u32 *ireg, *isize;
+       u32 hcpuid;
+
+       /* Find the server numbers for the boot cpu. */
+       np = of_get_cpu_node(boot_cpuid, NULL);
+       BUG_ON(!np);
+
+       ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
+       if (!ireg) {
+               of_node_put(np);
+               return;
+       }
+
+       i = ilen / sizeof(int);
+       hcpuid = get_hard_smp_processor_id(boot_cpuid);
+
+       /* Global interrupt distribution server is specified in the last
+        * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
+        * entry fom this property for current boot cpu id and use it as
+        * default distribution server
+        */
+       for (j = 0; j < i; j += 2) {
+               if (ireg[j] == hcpuid) {
+                       default_server = hcpuid;
+                       default_distrib_server = ireg[j+1];
+
+                       isize = of_get_property(np,
+                                       "ibm,interrupt-server#-size", NULL);
+                       if (isize)
+                               interrupt_server_size = *isize;
+               }
+       }
+
+       of_node_put(np);
+}
 
 #ifdef CONFIG_SMP
 static int get_irq_server(unsigned int virq, unsigned int strict_check)
@@ -169,6 +209,9 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check)
        cpumask_t cpumask = irq_desc[virq].affinity;
        cpumask_t tmp = CPU_MASK_NONE;
 
+       if (! cpu_isset(default_server, cpu_online_map))
+               xics_update_irq_servers();
+
        if (!distribute_irqs)
                return default_server;
 
@@ -658,39 +701,11 @@ static void __init xics_setup_8259_cascade(void)
        set_irq_chained_handler(cascade, pseries_8259_cascade);
 }
 
-static struct device_node *cpuid_to_of_node(int cpu)
-{
-       struct device_node *np;
-       u32 hcpuid = get_hard_smp_processor_id(cpu);
-
-       for_each_node_by_type(np, "cpu") {
-               int i, len;
-               const u32 *intserv;
-
-               intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
-                                       &len);
-
-               if (!intserv)
-                       intserv = of_get_property(np, "reg", &len);
-
-               i = len / sizeof(u32);
-
-               while (i--)
-                       if (intserv[i] == hcpuid)
-                               return np;
-       }
-
-       return NULL;
-}
-
 void __init xics_init_IRQ(void)
 {
-       int i, j;
        struct device_node *np;
-       u32 ilen, indx = 0;
-       const u32 *ireg, *isize;
+       u32 indx = 0;
        int found = 0;
-       u32 hcpuid;
 
        ppc64_boot_msg(0x20, "XICS Init");
 
@@ -709,34 +724,7 @@ void __init xics_init_IRQ(void)
                return;
 
        xics_init_host();
-
-       /* Find the server numbers for the boot cpu. */
-       np = cpuid_to_of_node(boot_cpuid);
-       BUG_ON(!np);
-       ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
-       if (!ireg)
-               goto skip_gserver_check;
-       i = ilen / sizeof(int);
-       hcpuid = get_hard_smp_processor_id(boot_cpuid);
-
-       /* Global interrupt distribution server is specified in the last
-        * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
-        * entry fom this property for current boot cpu id and use it as
-        * default distribution server
-        */
-       for (j = 0; j < i; j += 2) {
-               if (ireg[j] == hcpuid) {
-                       default_server = hcpuid;
-                       default_distrib_server = ireg[j+1];
-
-                       isize = of_get_property(np,
-                                       "ibm,interrupt-server#-size", NULL);
-                       if (isize)
-                               interrupt_server_size = *isize;
-               }
-       }
-skip_gserver_check:
-       of_node_put(np);
+       xics_update_irq_servers();
 
        if (firmware_has_feature(FW_FEATURE_LPAR))
                ppc_md.get_irq = xics_get_irq_lpar;
@@ -775,11 +763,9 @@ void xics_request_IPIs(void)
 }
 #endif /* CONFIG_SMP */
 
-void xics_teardown_cpu(int secondary)
+void xics_teardown_cpu(void)
 {
        int cpu = smp_processor_id();
-       unsigned int ipi;
-       struct irq_desc *desc;
 
        xics_set_cpu_priority(0);
 
@@ -790,9 +776,17 @@ void xics_teardown_cpu(int secondary)
                lpar_qirr_info(cpu, 0xff);
        else
                direct_qirr_info(cpu, 0xff);
+}
+
+void xics_kexec_teardown_cpu(int secondary)
+{
+       unsigned int ipi;
+       struct irq_desc *desc;
+
+       xics_teardown_cpu();
 
        /*
-        * we need to EOI the IPI if we got here from kexec down IPI
+        * we need to EOI the IPI
         *
         * probably need to check all the other interrupts too
         * should we be flagging idle loop instead?
@@ -880,8 +874,8 @@ void xics_migrate_irqs_away(void)
                       virq, cpu);
 
                /* Reset affinity to all cpus */
+               irq_desc[virq].affinity = CPU_MASK_ALL;
                desc->chip->set_affinity(virq, CPU_MASK_ALL);
-               irq_desc[irq].affinity = CPU_MASK_ALL;
 unlock:
                spin_unlock_irqrestore(&desc->lock, flags);
        }