Commit 4357f614 authored by Olof Johansson's avatar Olof Johansson Committed by Linus Torvalds

[PATCH] ppc64: Make early processor spinup based on physical ids

This 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: default avatarOlof Johansson <olof@austin.ibm.com>
Signed-off-by: default avatarAnton Blanchard <anton@samba.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent faed452d
...@@ -103,6 +103,7 @@ int main(void) ...@@ -103,6 +103,7 @@ int main(void)
DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi)); DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi));
DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp));
DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca)); DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca));
DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0)); DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1)); DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt)); DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt));
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#define SECONDARY_PROCESSORS #define SECONDARY_PROCESSORS
#include <linux/config.h> #include <linux/config.h>
#include <linux/threads.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/mmu.h> #include <asm/mmu.h>
...@@ -1192,7 +1193,7 @@ unrecov_slb: ...@@ -1192,7 +1193,7 @@ unrecov_slb:
/* /*
* On pSeries, secondary processors spin in the following code. * 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) _GLOBAL(pseries_secondary_smp_init)
mr r24,r3 mr r24,r3
...@@ -1204,13 +1205,27 @@ _GLOBAL(pseries_secondary_smp_init) ...@@ -1204,13 +1205,27 @@ _GLOBAL(pseries_secondary_smp_init)
/* Copy some CPU settings from CPU 0 */ /* Copy some CPU settings from CPU 0 */
bl .__restore_cpu_setup bl .__restore_cpu_setup
/* Set up a paca value for this processor. */ /* Set up a paca value for this processor. Since we have the
LOADADDR(r5, paca) /* Get base vaddr of paca array */ * physical cpu id in r3, we need to search the pacas to find
mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */ * which logical id maps to our physical one.
add r13,r13,r5 /* for this processor. */ */
mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ LOADADDR(r13, paca) /* Get base vaddr of paca array */
1: li r5,0 /* logical cpu id */
HMT_LOW 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 */ lbz r23,PACAPROCSTART(r13) /* Test if this processor should */
/* start. */ /* start. */
sync sync
...@@ -1225,7 +1240,7 @@ _GLOBAL(pseries_secondary_smp_init) ...@@ -1225,7 +1240,7 @@ _GLOBAL(pseries_secondary_smp_init)
bne .__secondary_start bne .__secondary_start
#endif #endif
#endif #endif
b 1b /* Loop until told to go */ b 3b /* Loop until told to go */
#ifdef CONFIG_PPC_ISERIES #ifdef CONFIG_PPC_ISERIES
_STATIC(__start_initialization_iSeries) _STATIC(__start_initialization_iSeries)
/* Clear out the BSS */ /* Clear out the BSS */
...@@ -1921,19 +1936,6 @@ _STATIC(start_here_multiplatform) ...@@ -1921,19 +1936,6 @@ _STATIC(start_here_multiplatform)
bl .__save_cpu_setup bl .__save_cpu_setup
sync 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 /* Setup a valid physical PACA pointer in SPRG3 for early_setup
* note that boot_cpuid can always be 0 nowadays since there is * note that boot_cpuid can always be 0 nowadays since there is
* nowhere it can be initialized differently before we reach this * nowhere it can be initialized differently before we reach this
...@@ -2131,6 +2133,22 @@ _GLOBAL(hmt_start_secondary) ...@@ -2131,6 +2133,22 @@ _GLOBAL(hmt_start_secondary)
blr blr
#endif #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. * We put a few things here that have to be page-aligned.
* This stuff goes at the beginning of the data segment, * This stuff goes at the beginning of the data segment,
......
...@@ -58,6 +58,7 @@ extern unsigned long __toc_start; ...@@ -58,6 +58,7 @@ extern unsigned long __toc_start;
.stab_real = (asrr), /* Real pointer to segment table */ \ .stab_real = (asrr), /* Real pointer to segment table */ \
.stab_addr = (asrv), /* Virt pointer to segment table */ \ .stab_addr = (asrv), /* Virt pointer to segment table */ \
.cpu_start = (start), /* Processor start */ \ .cpu_start = (start), /* Processor start */ \
.hw_cpu_id = 0xffff, \
.lppaca = { \ .lppaca = { \
.xDesc = 0xd397d781, /* "LpPa" */ \ .xDesc = 0xd397d781, /* "LpPa" */ \
.xSize = sizeof(struct ItLpPaca), \ .xSize = sizeof(struct ItLpPaca), \
......
...@@ -853,10 +853,19 @@ static int __init early_init_dt_scan_cpus(unsigned long node, ...@@ -853,10 +853,19 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
} }
} }
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 */ /* 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) { if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) {
u32 *prop = get_flat_dt_prop(node, "reg", NULL); u32 *prop = get_flat_dt_prop(node, "reg", NULL);
paca[0].hw_cpu_id = prop == NULL ? 0 : *prop; set_hard_smp_processor_id(0, prop == NULL ? 0 : *prop);
boot_cpuid_phys = get_hard_smp_processor_id(0);
}
} }
return 0; return 0;
......
...@@ -988,13 +988,13 @@ static void __init prom_hold_cpus(void) ...@@ -988,13 +988,13 @@ static void __init prom_hold_cpus(void)
/* Primary Thread of non-boot cpu */ /* Primary Thread of non-boot cpu */
prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg); prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg);
call_prom("start-cpu", 3, 0, node, call_prom("start-cpu", 3, 0, node,
secondary_hold, cpuid); secondary_hold, reg);
for ( i = 0 ; (i < 100000000) && for ( i = 0 ; (i < 100000000) &&
(*acknowledge == ((unsigned long)-1)); i++ ) (*acknowledge == ((unsigned long)-1)); i++ )
mb(); mb();
if (*acknowledge == cpuid) { if (*acknowledge == reg) {
prom_printf("done\n"); prom_printf("done\n");
/* We have to get every CPU out of OF, /* We have to get every CPU out of OF,
* even if we never start it. */ * even if we never start it. */
......
...@@ -99,6 +99,8 @@ extern void htab_initialize(void); ...@@ -99,6 +99,8 @@ extern void htab_initialize(void);
extern void early_init_devtree(void *flat_dt); extern void early_init_devtree(void *flat_dt);
extern void unflatten_device_tree(void); extern void unflatten_device_tree(void);
extern void smp_release_cpus(void);
unsigned long decr_overclock = 1; unsigned long decr_overclock = 1;
unsigned long decr_overclock_proc0 = 1; unsigned long decr_overclock_proc0 = 1;
unsigned long decr_overclock_set = 0; unsigned long decr_overclock_set = 0;
...@@ -106,6 +108,7 @@ unsigned long decr_overclock_proc0_set = 0; ...@@ -106,6 +108,7 @@ unsigned long decr_overclock_proc0_set = 0;
int have_of = 1; int have_of = 1;
int boot_cpuid = 0; int boot_cpuid = 0;
int boot_cpuid_phys = 0;
dev_t boot_dev; dev_t boot_dev;
/* /*
...@@ -242,6 +245,7 @@ static void __init setup_cpu_maps(void) ...@@ -242,6 +245,7 @@ static void __init setup_cpu_maps(void)
{ {
struct device_node *dn = NULL; struct device_node *dn = NULL;
int cpu = 0; int cpu = 0;
int swap_cpuid = 0;
check_smt_enabled(); check_smt_enabled();
...@@ -266,11 +270,23 @@ static void __init setup_cpu_maps(void) ...@@ -266,11 +270,23 @@ static void __init setup_cpu_maps(void)
cpu_set(cpu, cpu_present_map); cpu_set(cpu, cpu_present_map);
set_hard_smp_processor_id(cpu, intserv[j]); set_hard_smp_processor_id(cpu, intserv[j]);
} }
if (intserv[j] == boot_cpuid_phys)
swap_cpuid = cpu;
cpu_set(cpu, cpu_possible_map); cpu_set(cpu, cpu_possible_map);
cpu++; 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 * On pSeries LPAR, we need to know how many cpus
* could possibly be added to this partition. * could possibly be added to this partition.
...@@ -630,6 +646,11 @@ void __init setup_system(void) ...@@ -630,6 +646,11 @@ void __init setup_system(void)
* iSeries has already initialized the cpu maps at this point. * iSeries has already initialized the cpu maps at this point.
*/ */
setup_cpu_maps(); 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) */ #endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */
printk("Starting Linux PPC64 %s\n", UTS_RELEASE); printk("Starting Linux PPC64 %s\n", UTS_RELEASE);
......
...@@ -56,6 +56,8 @@ struct boot_param_header ...@@ -56,6 +56,8 @@ struct boot_param_header
u32 off_mem_rsvmap; /* offset to memory reserve map */ u32 off_mem_rsvmap; /* offset to memory reserve map */
u32 version; /* format version */ u32 version; /* format version */
u32 last_comp_version; /* last compatible version */ u32 last_comp_version; /* last compatible version */
/* version 2 fields below */
u32 boot_cpuid_phys; /* Which physical CPU id we're booting on */
}; };
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <asm/paca.h> #include <asm/paca.h>
extern int boot_cpuid; extern int boot_cpuid;
extern int boot_cpuid_phys;
extern void cpu_die(void) __attribute__((noreturn)); extern void cpu_die(void) __attribute__((noreturn));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment