diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index d071abe78ab1..b5b2b1103de8 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -656,13 +656,38 @@ 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 = get_property(np, "ibm,ppc-interrupt-server#s", &len); + + if (!intserv) + intserv = 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; + int i, j; struct device_node *np; u32 ilen, indx = 0; - const u32 *ireg; + const u32 *ireg, *isize; int found = 0; + u32 hcpuid; ppc64_boot_msg(0x20, "XICS Init"); @@ -683,26 +708,31 @@ void __init xics_init_IRQ(void) xics_init_host(); /* Find the server numbers for the boot cpu. */ - for (np = of_find_node_by_type(NULL, "cpu"); - np; - np = of_find_node_by_type(np, "cpu")) { - ireg = get_property(np, "reg", &ilen); - if (ireg && ireg[0] == get_hard_smp_processor_id(boot_cpuid)) { - ireg = get_property(np, - "ibm,ppc-interrupt-gserver#s", &ilen); - i = ilen / sizeof(int); - if (ireg && i > 0) { - default_server = ireg[0]; - /* take last element */ - default_distrib_server = ireg[i-1]; - } - ireg = get_property(np, + np = cpuid_to_of_node(boot_cpuid); + BUG_ON(!np); + ireg = 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 = get_property(np, "ibm,interrupt-server#-size", NULL); - if (ireg) - interrupt_server_size = *ireg; - break; + if (isize) + interrupt_server_size = *isize; } } +skip_gserver_check: of_node_put(np); if (firmware_has_feature(FW_FEATURE_LPAR))