aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMohan Kumar M <mohan@in.ibm.com>2006-11-17 07:12:24 -0500
committerPaul Mackerras <paulus@samba.org>2006-12-04 04:41:22 -0500
commita5715d6dfc85e002bfad68bb2858cf5a248e2060 (patch)
treeb3976f51fa51de75a44022b31e17ac98e051f99d /arch
parent11faa658c668030759d4aea6a273b7ac9a0b4746 (diff)
[POWERPC] pSeries/kexec: Fix for interrupt distribution
This allows any secondary CPU thread also to become boot cpu for POWER5. The patch is required to solve kdump boot issue when the kdump kernel is booted with parameter "maxcpus=1". XICS init code tries to match the current boot cpu id with "reg" property in each CPU node in the device tree. But CPU node is created only for primary thread CPU ids and "reg" property only reflects primary CPU ids. So when a kernel is booted on a secondary cpu thread above condition will never meet and the default distribution server is left as zero. This leads to route the interrupts to CPU 0, but which is not online at this time. We use ibm,ppc-interrupt-server#s to check for both primary and secondary CPU ids. Accordingly default distribution server value is initialized from "ibm,ppc-interrupt-gserver#s" property. We loop through ibm,ppc-interrupt-gserver#s property to find the global distribution server from the last entry that matches with boot cpuid. Signed-off-by: Mohan Kumar M <mohan@in.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/pseries/xics.c68
1 files changed, 49 insertions, 19 deletions
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)
656 set_irq_chained_handler(cascade, pseries_8259_cascade); 656 set_irq_chained_handler(cascade, pseries_8259_cascade);
657} 657}
658 658
659static struct device_node *cpuid_to_of_node(int cpu)
660{
661 struct device_node *np;
662 u32 hcpuid = get_hard_smp_processor_id(cpu);
663
664 for_each_node_by_type(np, "cpu") {
665 int i, len;
666 const u32 *intserv;
667
668 intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
669
670 if (!intserv)
671 intserv = get_property(np, "reg", &len);
672
673 i = len / sizeof(u32);
674
675 while (i--)
676 if (intserv[i] == hcpuid)
677 return np;
678 }
679
680 return NULL;
681}
682
659void __init xics_init_IRQ(void) 683void __init xics_init_IRQ(void)
660{ 684{
661 int i; 685 int i, j;
662 struct device_node *np; 686 struct device_node *np;
663 u32 ilen, indx = 0; 687 u32 ilen, indx = 0;
664 const u32 *ireg; 688 const u32 *ireg, *isize;
665 int found = 0; 689 int found = 0;
690 u32 hcpuid;
666 691
667 ppc64_boot_msg(0x20, "XICS Init"); 692 ppc64_boot_msg(0x20, "XICS Init");
668 693
@@ -683,26 +708,31 @@ void __init xics_init_IRQ(void)
683 xics_init_host(); 708 xics_init_host();
684 709
685 /* Find the server numbers for the boot cpu. */ 710 /* Find the server numbers for the boot cpu. */
686 for (np = of_find_node_by_type(NULL, "cpu"); 711 np = cpuid_to_of_node(boot_cpuid);
687 np; 712 BUG_ON(!np);
688 np = of_find_node_by_type(np, "cpu")) { 713 ireg = get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
689 ireg = get_property(np, "reg", &ilen); 714 if (!ireg)
690 if (ireg && ireg[0] == get_hard_smp_processor_id(boot_cpuid)) { 715 goto skip_gserver_check;
691 ireg = get_property(np, 716 i = ilen / sizeof(int);
692 "ibm,ppc-interrupt-gserver#s", &ilen); 717 hcpuid = get_hard_smp_processor_id(boot_cpuid);
693 i = ilen / sizeof(int); 718
694 if (ireg && i > 0) { 719 /* Global interrupt distribution server is specified in the last
695 default_server = ireg[0]; 720 * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
696 /* take last element */ 721 * entry fom this property for current boot cpu id and use it as
697 default_distrib_server = ireg[i-1]; 722 * default distribution server
698 } 723 */
699 ireg = get_property(np, 724 for (j = 0; j < i; j += 2) {
725 if (ireg[j] == hcpuid) {
726 default_server = hcpuid;
727 default_distrib_server = ireg[j+1];
728
729 isize = get_property(np,
700 "ibm,interrupt-server#-size", NULL); 730 "ibm,interrupt-server#-size", NULL);
701 if (ireg) 731 if (isize)
702 interrupt_server_size = *ireg; 732 interrupt_server_size = *isize;
703 break;
704 } 733 }
705 } 734 }
735skip_gserver_check:
706 of_node_put(np); 736 of_node_put(np);
707 737
708 if (firmware_has_feature(FW_FEATURE_LPAR)) 738 if (firmware_has_feature(FW_FEATURE_LPAR))