From: Anton Blanchard From: Olof Johansson Below patch changes the early CPU spinup code to be based on physical CPU ID instead of logical. This will make it possible to kexec off of a different cpu than 0, for example after it's been hot-unplugged. The booted cpu will still be mapped as logical cpu 0, since there's various stuff in the early boot that assumes logical boot cpuid is 0. Also, it expands the kexec boot param structure to allow the booted physical cpuid to be passed in. This includes bumping the version number to 2 for backwards compat. Signed-off-by: Olof Johansson Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton --- 25-akpm/arch/ppc64/kernel/asm-offsets.c | 1 25-akpm/arch/ppc64/kernel/head.S | 62 ++++++++++++++++++++------------ 25-akpm/arch/ppc64/kernel/pacaData.c | 1 25-akpm/arch/ppc64/kernel/prom.c | 17 ++++++-- 25-akpm/arch/ppc64/kernel/prom_init.c | 4 +- 25-akpm/arch/ppc64/kernel/setup.c | 21 ++++++++++ 25-akpm/include/asm-ppc64/prom.h | 2 + 25-akpm/include/asm-ppc64/smp.h | 1 8 files changed, 81 insertions(+), 28 deletions(-) diff -puN arch/ppc64/kernel/asm-offsets.c~ppc64-make-early-processor-spinup-based-on-physical-ids arch/ppc64/kernel/asm-offsets.c --- 25/arch/ppc64/kernel/asm-offsets.c~ppc64-make-early-processor-spinup-based-on-physical-ids Fri Nov 19 14:29:40 2004 +++ 25-akpm/arch/ppc64/kernel/asm-offsets.c Fri Nov 19 14:29:40 2004 @@ -103,6 +103,7 @@ int main(void) DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi)); DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca)); + DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0)); DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1)); DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt)); diff -puN arch/ppc64/kernel/head.S~ppc64-make-early-processor-spinup-based-on-physical-ids arch/ppc64/kernel/head.S --- 25/arch/ppc64/kernel/head.S~ppc64-make-early-processor-spinup-based-on-physical-ids Fri Nov 19 14:29:40 2004 +++ 25-akpm/arch/ppc64/kernel/head.S Fri Nov 19 14:29:40 2004 @@ -26,6 +26,7 @@ #define SECONDARY_PROCESSORS #include +#include #include #include #include @@ -1192,7 +1193,7 @@ unrecov_slb: /* * On pSeries, secondary processors spin in the following code. - * At entry, r3 = this processor's number (in Linux terms, not hardware). + * At entry, r3 = this processor's number (physical cpu id) */ _GLOBAL(pseries_secondary_smp_init) mr r24,r3 @@ -1204,13 +1205,27 @@ _GLOBAL(pseries_secondary_smp_init) /* Copy some CPU settings from CPU 0 */ bl .__restore_cpu_setup - /* Set up a paca value for this processor. */ - LOADADDR(r5, paca) /* Get base vaddr of paca array */ - mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */ - add r13,r13,r5 /* for this processor. */ - mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ -1: - HMT_LOW + /* Set up a paca value for this processor. Since we have the + * physical cpu id in r3, we need to search the pacas to find + * which logical id maps to our physical one. + */ + LOADADDR(r13, paca) /* Get base vaddr of paca array */ + li r5,0 /* logical cpu id */ +1: lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */ + cmpw r6,r24 /* Compare to our id */ + beq 2f + addi r13,r13,PACA_SIZE /* Loop to next PACA on miss */ + addi r5,r5,1 + cmpwi r5,NR_CPUS + blt 1b + +99: HMT_LOW /* Couldn't find our CPU id */ + b 99b + +2: mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ + /* From now on, r24 is expected to be logica cpuid */ + mr r24,r5 +3: HMT_LOW lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ /* start. */ sync @@ -1225,7 +1240,7 @@ _GLOBAL(pseries_secondary_smp_init) bne .__secondary_start #endif #endif - b 1b /* Loop until told to go */ + b 3b /* Loop until told to go */ #ifdef CONFIG_PPC_ISERIES _STATIC(__start_initialization_iSeries) /* Clear out the BSS */ @@ -1921,19 +1936,6 @@ _STATIC(start_here_multiplatform) bl .__save_cpu_setup sync -#ifdef CONFIG_SMP - /* All secondary cpus are now spinning on a common - * spinloop, release them all now so they can start - * to spin on their individual paca spinloops. - * For non SMP kernels, the secondary cpus never - * get out of the common spinloop. - */ - li r3,1 - LOADADDR(r5,__secondary_hold_spinloop) - tophys(r4,r5) - std r3,0(r4) -#endif - /* Setup a valid physical PACA pointer in SPRG3 for early_setup * note that boot_cpuid can always be 0 nowadays since there is * nowhere it can be initialized differently before we reach this @@ -2131,6 +2133,22 @@ _GLOBAL(hmt_start_secondary) blr #endif +#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) +_GLOBAL(smp_release_cpus) + /* All secondary cpus are spinning on a common + * spinloop, release them all now so they can start + * to spin on their individual paca spinloops. + * For non SMP kernels, the secondary cpus never + * get out of the common spinloop. + */ + li r3,1 + LOADADDR(r5,__secondary_hold_spinloop) + std r3,0(r5) + sync + blr +#endif /* CONFIG_SMP && !CONFIG_PPC_ISERIES */ + + /* * We put a few things here that have to be page-aligned. * This stuff goes at the beginning of the data segment, diff -puN arch/ppc64/kernel/pacaData.c~ppc64-make-early-processor-spinup-based-on-physical-ids arch/ppc64/kernel/pacaData.c --- 25/arch/ppc64/kernel/pacaData.c~ppc64-make-early-processor-spinup-based-on-physical-ids Fri Nov 19 14:29:40 2004 +++ 25-akpm/arch/ppc64/kernel/pacaData.c Fri Nov 19 14:29:40 2004 @@ -58,6 +58,7 @@ extern unsigned long __toc_start; .stab_real = (asrr), /* Real pointer to segment table */ \ .stab_addr = (asrv), /* Virt pointer to segment table */ \ .cpu_start = (start), /* Processor start */ \ + .hw_cpu_id = 0xffff, \ .lppaca = { \ .xDesc = 0xd397d781, /* "LpPa" */ \ .xSize = sizeof(struct ItLpPaca), \ diff -puN arch/ppc64/kernel/prom.c~ppc64-make-early-processor-spinup-based-on-physical-ids arch/ppc64/kernel/prom.c --- 25/arch/ppc64/kernel/prom.c~ppc64-make-early-processor-spinup-based-on-physical-ids Fri Nov 19 14:29:40 2004 +++ 25-akpm/arch/ppc64/kernel/prom.c Fri Nov 19 14:29:40 2004 @@ -853,10 +853,19 @@ static int __init early_init_dt_scan_cpu } } - /* Check if it's the boot-cpu, set it's hw index in paca now */ - if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) { - u32 *prop = get_flat_dt_prop(node, "reg", NULL); - paca[0].hw_cpu_id = prop == NULL ? 0 : *prop; + if (initial_boot_params && initial_boot_params->version >= 2) { + /* version 2 of the kexec param format adds the phys cpuid + * of booted proc. + */ + boot_cpuid_phys = initial_boot_params->boot_cpuid_phys; + boot_cpuid = 0; + } else { + /* Check if it's the boot-cpu, set it's hw index in paca now */ + if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) { + u32 *prop = get_flat_dt_prop(node, "reg", NULL); + set_hard_smp_processor_id(0, prop == NULL ? 0 : *prop); + boot_cpuid_phys = get_hard_smp_processor_id(0); + } } return 0; diff -puN arch/ppc64/kernel/prom_init.c~ppc64-make-early-processor-spinup-based-on-physical-ids arch/ppc64/kernel/prom_init.c --- 25/arch/ppc64/kernel/prom_init.c~ppc64-make-early-processor-spinup-based-on-physical-ids Fri Nov 19 14:29:40 2004 +++ 25-akpm/arch/ppc64/kernel/prom_init.c Fri Nov 19 14:29:40 2004 @@ -988,13 +988,13 @@ static void __init prom_hold_cpus(void) /* Primary Thread of non-boot cpu */ prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg); call_prom("start-cpu", 3, 0, node, - secondary_hold, cpuid); + secondary_hold, reg); for ( i = 0 ; (i < 100000000) && (*acknowledge == ((unsigned long)-1)); i++ ) mb(); - if (*acknowledge == cpuid) { + if (*acknowledge == reg) { prom_printf("done\n"); /* We have to get every CPU out of OF, * even if we never start it. */ diff -puN arch/ppc64/kernel/setup.c~ppc64-make-early-processor-spinup-based-on-physical-ids arch/ppc64/kernel/setup.c --- 25/arch/ppc64/kernel/setup.c~ppc64-make-early-processor-spinup-based-on-physical-ids Fri Nov 19 14:29:40 2004 +++ 25-akpm/arch/ppc64/kernel/setup.c Fri Nov 19 14:29:40 2004 @@ -99,6 +99,8 @@ extern void htab_initialize(void); extern void early_init_devtree(void *flat_dt); extern void unflatten_device_tree(void); +extern void smp_release_cpus(void); + unsigned long decr_overclock = 1; unsigned long decr_overclock_proc0 = 1; unsigned long decr_overclock_set = 0; @@ -106,6 +108,7 @@ unsigned long decr_overclock_proc0_set = int have_of = 1; int boot_cpuid = 0; +int boot_cpuid_phys = 0; dev_t boot_dev; /* @@ -242,6 +245,7 @@ static void __init setup_cpu_maps(void) { struct device_node *dn = NULL; int cpu = 0; + int swap_cpuid = 0; check_smt_enabled(); @@ -266,11 +270,23 @@ static void __init setup_cpu_maps(void) cpu_set(cpu, cpu_present_map); set_hard_smp_processor_id(cpu, intserv[j]); } + if (intserv[j] == boot_cpuid_phys) + swap_cpuid = cpu; cpu_set(cpu, cpu_possible_map); cpu++; } } + /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that + * boot cpu is logical 0. + */ + if (boot_cpuid_phys != get_hard_smp_processor_id(0)) { + u32 tmp; + tmp = get_hard_smp_processor_id(0); + set_hard_smp_processor_id(0, boot_cpuid_phys); + set_hard_smp_processor_id(swap_cpuid, tmp); + } + /* * On pSeries LPAR, we need to know how many cpus * could possibly be added to this partition. @@ -630,6 +646,11 @@ void __init setup_system(void) * iSeries has already initialized the cpu maps at this point. */ setup_cpu_maps(); + + /* Release secondary cpus out of their spinloops at 0x60 now that + * we can map physical -> logical CPU ids + */ + smp_release_cpus(); #endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */ printk("Starting Linux PPC64 %s\n", UTS_RELEASE); diff -puN include/asm-ppc64/prom.h~ppc64-make-early-processor-spinup-based-on-physical-ids include/asm-ppc64/prom.h --- 25/include/asm-ppc64/prom.h~ppc64-make-early-processor-spinup-based-on-physical-ids Fri Nov 19 14:29:40 2004 +++ 25-akpm/include/asm-ppc64/prom.h Fri Nov 19 14:29:40 2004 @@ -56,6 +56,8 @@ struct boot_param_header u32 off_mem_rsvmap; /* offset to memory reserve map */ u32 version; /* format version */ u32 last_comp_version; /* last compatible version */ + /* version 2 fields below */ + u32 boot_cpuid_phys; /* Which physical CPU id we're booting on */ }; diff -puN include/asm-ppc64/smp.h~ppc64-make-early-processor-spinup-based-on-physical-ids include/asm-ppc64/smp.h --- 25/include/asm-ppc64/smp.h~ppc64-make-early-processor-spinup-based-on-physical-ids Fri Nov 19 14:29:40 2004 +++ 25-akpm/include/asm-ppc64/smp.h Fri Nov 19 14:29:40 2004 @@ -27,6 +27,7 @@ #include extern int boot_cpuid; +extern int boot_cpuid_phys; extern void cpu_die(void) __attribute__((noreturn)); _