diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/xics.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/xics.c | 73 |
1 files changed, 51 insertions, 22 deletions
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index d071abe78ab1..81d172d65038 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -224,7 +224,6 @@ static void xics_unmask_irq(unsigned int virq) | |||
224 | static void xics_mask_real_irq(unsigned int irq) | 224 | static void xics_mask_real_irq(unsigned int irq) |
225 | { | 225 | { |
226 | int call_status; | 226 | int call_status; |
227 | unsigned int server; | ||
228 | 227 | ||
229 | if (irq == XICS_IPI) | 228 | if (irq == XICS_IPI) |
230 | return; | 229 | return; |
@@ -236,9 +235,9 @@ static void xics_mask_real_irq(unsigned int irq) | |||
236 | return; | 235 | return; |
237 | } | 236 | } |
238 | 237 | ||
239 | server = get_irq_server(irq); | ||
240 | /* Have to set XIVE to 0xff to be able to remove a slot */ | 238 | /* Have to set XIVE to 0xff to be able to remove a slot */ |
241 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, 0xff); | 239 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, |
240 | default_server, 0xff); | ||
242 | if (call_status != 0) { | 241 | if (call_status != 0) { |
243 | printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)" | 242 | printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)" |
244 | " returned %d\n", irq, call_status); | 243 | " returned %d\n", irq, call_status); |
@@ -656,13 +655,38 @@ static void __init xics_setup_8259_cascade(void) | |||
656 | set_irq_chained_handler(cascade, pseries_8259_cascade); | 655 | set_irq_chained_handler(cascade, pseries_8259_cascade); |
657 | } | 656 | } |
658 | 657 | ||
658 | static struct device_node *cpuid_to_of_node(int cpu) | ||
659 | { | ||
660 | struct device_node *np; | ||
661 | u32 hcpuid = get_hard_smp_processor_id(cpu); | ||
662 | |||
663 | for_each_node_by_type(np, "cpu") { | ||
664 | int i, len; | ||
665 | const u32 *intserv; | ||
666 | |||
667 | intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len); | ||
668 | |||
669 | if (!intserv) | ||
670 | intserv = get_property(np, "reg", &len); | ||
671 | |||
672 | i = len / sizeof(u32); | ||
673 | |||
674 | while (i--) | ||
675 | if (intserv[i] == hcpuid) | ||
676 | return np; | ||
677 | } | ||
678 | |||
679 | return NULL; | ||
680 | } | ||
681 | |||
659 | void __init xics_init_IRQ(void) | 682 | void __init xics_init_IRQ(void) |
660 | { | 683 | { |
661 | int i; | 684 | int i, j; |
662 | struct device_node *np; | 685 | struct device_node *np; |
663 | u32 ilen, indx = 0; | 686 | u32 ilen, indx = 0; |
664 | const u32 *ireg; | 687 | const u32 *ireg, *isize; |
665 | int found = 0; | 688 | int found = 0; |
689 | u32 hcpuid; | ||
666 | 690 | ||
667 | ppc64_boot_msg(0x20, "XICS Init"); | 691 | ppc64_boot_msg(0x20, "XICS Init"); |
668 | 692 | ||
@@ -683,26 +707,31 @@ void __init xics_init_IRQ(void) | |||
683 | xics_init_host(); | 707 | xics_init_host(); |
684 | 708 | ||
685 | /* Find the server numbers for the boot cpu. */ | 709 | /* Find the server numbers for the boot cpu. */ |
686 | for (np = of_find_node_by_type(NULL, "cpu"); | 710 | np = cpuid_to_of_node(boot_cpuid); |
687 | np; | 711 | BUG_ON(!np); |
688 | np = of_find_node_by_type(np, "cpu")) { | 712 | ireg = get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); |
689 | ireg = get_property(np, "reg", &ilen); | 713 | if (!ireg) |
690 | if (ireg && ireg[0] == get_hard_smp_processor_id(boot_cpuid)) { | 714 | goto skip_gserver_check; |
691 | ireg = get_property(np, | 715 | i = ilen / sizeof(int); |
692 | "ibm,ppc-interrupt-gserver#s", &ilen); | 716 | hcpuid = get_hard_smp_processor_id(boot_cpuid); |
693 | i = ilen / sizeof(int); | 717 | |
694 | if (ireg && i > 0) { | 718 | /* Global interrupt distribution server is specified in the last |
695 | default_server = ireg[0]; | 719 | * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last |
696 | /* take last element */ | 720 | * entry fom this property for current boot cpu id and use it as |
697 | default_distrib_server = ireg[i-1]; | 721 | * default distribution server |
698 | } | 722 | */ |
699 | ireg = get_property(np, | 723 | for (j = 0; j < i; j += 2) { |
724 | if (ireg[j] == hcpuid) { | ||
725 | default_server = hcpuid; | ||
726 | default_distrib_server = ireg[j+1]; | ||
727 | |||
728 | isize = get_property(np, | ||
700 | "ibm,interrupt-server#-size", NULL); | 729 | "ibm,interrupt-server#-size", NULL); |
701 | if (ireg) | 730 | if (isize) |
702 | interrupt_server_size = *ireg; | 731 | interrupt_server_size = *isize; |
703 | break; | ||
704 | } | 732 | } |
705 | } | 733 | } |
734 | skip_gserver_check: | ||
706 | of_node_put(np); | 735 | of_node_put(np); |
707 | 736 | ||
708 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 737 | if (firmware_has_feature(FW_FEATURE_LPAR)) |