From: Rusty Russell 1) Check for cpuids >= NR_CPUS in prom_hold_cpus: we previously overflowed arrays when this happened, and checking it here ensures that it doesn't happen elsewhere. Still move processors to secondary_hold (out of OF), but we won't release them. 2) smp_iSeries_message_pass and smp_xics_message_pass don't need to iterate if given a specific CPU: cleanup and fix. 3) kick_cpu variants don't need to check cpu range (caller is screwed anyway if this happened): replaced with BUG_ON for now. 4) smp_openpic_probe and smp_xics_probe can use cpus_weight(): it's faster and simpler. 5) User for_each_cpu/for_each_online_cpu as appropriate. --- arch/ppc64/kernel/prom.c | 14 +++++- arch/ppc64/kernel/smp.c | 107 +++++++++++++++++++++-------------------------- arch/ppc64/kernel/xics.c | 4 - 3 files changed, 62 insertions(+), 63 deletions(-) diff -puN arch/ppc64/kernel/prom.c~ppc64-cpu-spinup-fixes arch/ppc64/kernel/prom.c --- 25/arch/ppc64/kernel/prom.c~ppc64-cpu-spinup-fixes 2004-02-21 20:58:24.000000000 -0800 +++ 25-akpm/arch/ppc64/kernel/prom.c 2004-02-21 20:58:24.000000000 -0800 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -1073,6 +1074,10 @@ prom_hold_cpus(unsigned long mem) if (*acknowledge == cpuid) { prom_print(RELOC("ok\n")); + /* We have to get every CPU out of OF, + * even if we never start it. */ + if (cpuid >= NR_CPUS) + goto next; #ifdef CONFIG_SMP /* Set the number of active processors. */ _systemcfg->processorCount++; @@ -1099,9 +1104,12 @@ prom_hold_cpus(unsigned long mem) cpu_set(cpuid, RELOC(cpu_present_at_boot)); } + next: /* Init paca for secondary threads. They start later. */ for (i=1; i < cpu_threads; i++) { cpuid++; + if (cpuid >= NR_CPUS) + continue; _xPaca[cpuid].xHwProcNum = interrupt_server[i]; prom_print_hex(interrupt_server[i]); prom_print(RELOC(" : preparing thread ... ")); @@ -1146,7 +1154,11 @@ prom_hold_cpus(unsigned long mem) prom_print(RELOC("Processor is not HMT capable\n")); } #endif - + + if (cpuid >= NR_CPUS) + prom_print(RELOC("WARNING: maximum CPUs (" __stringify(NR_CPUS) + ") exceeded: ignoring extras\n")); + #ifdef DEBUG_PROM prom_print(RELOC("prom_hold_cpus: end...\n")); #endif diff -puN arch/ppc64/kernel/smp.c~ppc64-cpu-spinup-fixes arch/ppc64/kernel/smp.c --- 25/arch/ppc64/kernel/smp.c~ppc64-cpu-spinup-fixes 2004-02-21 20:58:24.000000000 -0800 +++ 25-akpm/arch/ppc64/kernel/smp.c 2004-02-21 20:58:24.000000000 -0800 @@ -95,20 +95,25 @@ void iSeries_smp_message_recv( struct pt smp_message_recv( msg, regs ); } -static void smp_iSeries_message_pass(int target, int msg, unsigned long data, int wait) +static inline void smp_iSeries_do_message(int cpu, int msg) +{ + set_bit(msg, &iSeries_smp_message[cpu]); + HvCall_sendIPI(&(paca[cpu])); +} + +static void +smp_iSeries_message_pass(int target, int msg, long data, int wait) { int i; - for (i = 0; i < NR_CPUS; ++i) { - if (!cpu_online(i)) - continue; - - if ((target == MSG_ALL) || - (target == i) || - ((target == MSG_ALL_BUT_SELF) && - (i != smp_processor_id())) ) { - set_bit(msg, &iSeries_smp_message[i]); - HvCall_sendIPI(&(paca[i])); + if (target < NR_CPUS) + smp_iSeries_do_message(target, msg); + else { + for_each_online_cpu(i) { + if (target == MSG_ALL_BUT_SELF + && i == smp_processor_id()) + continue; + smp_iSeries_do_message(i, msg); } } } @@ -151,21 +156,14 @@ static int smp_iSeries_probe(void) static void smp_iSeries_kick_cpu(int nr) { struct ItLpPaca * lpPaca; - /* Verify we have a Paca for processor nr */ - if ( ( nr <= 0 ) || - ( nr >= NR_CPUS ) ) - return; + + BUG_ON(nr < 0 || nr >= NR_CPUS); + /* Verify that our partition has a processor nr */ lpPaca = paca[nr].xLpPacaPtr; - if ( lpPaca->xDynProcStatus >= 2 ) + if (lpPaca->xDynProcStatus >= 2) return; - /* The information for processor bringup must - * be written out to main store before we release - * the processor. - */ - mb(); - /* The processor is currently spinning, waiting * for the xProcStart field to become non-zero * After we set xProcStart, the processor will @@ -219,13 +217,9 @@ void smp_openpic_message_pass(int target static int __init smp_openpic_probe(void) { - int i; - int nr_cpus = 0; + int nr_cpus; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_possible(i)) - nr_cpus++; - } + nr_cpus = cpus_weight(cpu_possible_map); if (nr_cpus > 1) openpic_request_IPIs(); @@ -240,16 +234,7 @@ static void __devinit smp_openpic_setup_ static void smp_pSeries_kick_cpu(int nr) { - /* Verify we have a Paca for processor nr */ - if ( ( nr <= 0 ) || - ( nr >= NR_CPUS ) ) - return; - - /* The information for processor bringup must - * be written out to main store before we release - * the processor. - */ - mb(); + BUG_ON(nr < 0 || nr >= NR_CPUS); /* The processor is currently spinning, waiting * for the xProcStart field to become non-zero @@ -266,8 +251,8 @@ static void __init smp_space_timers(unsi unsigned long offset = tb_ticks_per_jiffy / max_cpus; unsigned long previous_tb = paca[boot_cpuid].next_jiffy_update_tb; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_possible(i) && i != boot_cpuid) { + for_each_cpu(i) { + if (i != boot_cpuid) { paca[i].next_jiffy_update_tb = previous_tb + offset; previous_tb = paca[i].next_jiffy_update_tb; @@ -287,20 +272,25 @@ void vpa_init(int cpu) register_vpa(flags, cpu, __pa((unsigned long)&(paca[cpu].xLpPaca))); } +static inline void smp_xics_do_message(int cpu, int msg) +{ + set_bit(msg, &xics_ipi_message[cpu].value); + mb(); + xics_cause_IPI(cpu); +} + static void smp_xics_message_pass(int target, int msg, unsigned long data, int wait) { - int i; + unsigned int i; - for (i = 0; i < NR_CPUS; ++i) { - if (!cpu_online(i)) - continue; - - if (target == MSG_ALL || target == i - || (target == MSG_ALL_BUT_SELF - && i != smp_processor_id())) { - set_bit(msg, &xics_ipi_message[i].value); - mb(); - xics_cause_IPI(i); + if (target < NR_CPUS) { + smp_xics_do_message(target, msg); + } else { + for_each_online_cpu(i) { + if (target == MSG_ALL_BUT_SELF + && i == smp_processor_id()) + continue; + smp_xics_do_message(i, msg); } } } @@ -309,18 +299,11 @@ extern void xics_request_IPIs(void); static int __init smp_xics_probe(void) { - int i; - int nr_cpus = 0; - - for (i = 0; i < NR_CPUS; i++) { - if (cpu_possible(i)) - nr_cpus++; - } #ifdef CONFIG_SMP xics_request_IPIs(); #endif - return nr_cpus; + return cpus_weight(cpu_possible_map); } static void __devinit smp_xics_setup_cpu(int cpu) @@ -660,6 +643,12 @@ int __devinit __cpu_up(unsigned int cpu) paca[cpu].xCurrent = (u64)p; current_set[cpu] = p->thread_info; + /* The information for processor bringup must + * be written out to main store before we release + * the processor. + */ + mb(); + /* wake up cpus */ smp_ops->kick_cpu(cpu); diff -puN arch/ppc64/kernel/xics.c~ppc64-cpu-spinup-fixes arch/ppc64/kernel/xics.c --- 25/arch/ppc64/kernel/xics.c~ppc64-cpu-spinup-fixes 2004-02-21 20:58:24.000000000 -0800 +++ 25-akpm/arch/ppc64/kernel/xics.c 2004-02-21 20:58:24.000000000 -0800 @@ -475,9 +475,7 @@ nextnode: if (systemcfg->platform == PLATFORM_PSERIES) { #ifdef CONFIG_SMP - for (i = 0; i < NR_CPUS; ++i) { - if (!cpu_possible(i)) - continue; + for_each_cpu(i) { xics_per_cpu[i] = __ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr, (ulong)inodes[get_hard_smp_processor_id(i)].size, _PAGE_NO_CACHE); _