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

Anton Blanchard anton at samba.org
Fri Nov 19 18:39:47 EST 2004


From: Olof Johansson <olof at austin.ibm.com>

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 <olof at austin.ibm.com>
Signed-off-by: Anton Blanchard <anton at samba.org>

diff -puN arch/ppc64/kernel/asm-offsets.c~boot-cpuid arch/ppc64/kernel/asm-offsets.c
--- linux-2.5/arch/ppc64/kernel/asm-offsets.c~boot-cpuid	2004-11-16 12:41:26.546908234 -0600
+++ linux-2.5-olof/arch/ppc64/kernel/asm-offsets.c	2004-11-16 13:24:49.372405523 -0600
@@ -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~boot-cpuid arch/ppc64/kernel/head.S
--- linux-2.5/arch/ppc64/kernel/head.S~boot-cpuid	2004-11-16 12:41:26.548908679 -0600
+++ linux-2.5-olof/arch/ppc64/kernel/head.S	2004-11-16 13:20:02.404741718 -0600
@@ -26,6 +26,7 @@
 #define SECONDARY_PROCESSORS
 
 #include <linux/config.h>
+#include <linux/threads.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
@@ -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~boot-cpuid arch/ppc64/kernel/pacaData.c
--- linux-2.5/arch/ppc64/kernel/pacaData.c~boot-cpuid	2004-11-16 12:41:26.551909346 -0600
+++ linux-2.5-olof/arch/ppc64/kernel/pacaData.c	2004-11-16 12:41:26.572914016 -0600
@@ -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~boot-cpuid arch/ppc64/kernel/prom.c
--- linux-2.5/arch/ppc64/kernel/prom.c~boot-cpuid	2004-11-16 12:41:26.554910013 -0600
+++ linux-2.5-olof/arch/ppc64/kernel/prom.c	2004-11-16 12:41:26.573914239 -0600
@@ -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~boot-cpuid arch/ppc64/kernel/prom_init.c
--- linux-2.5/arch/ppc64/kernel/prom_init.c~boot-cpuid	2004-11-16 12:41:26.556910458 -0600
+++ linux-2.5-olof/arch/ppc64/kernel/prom_init.c	2004-11-16 12:41:26.575914683 -0600
@@ -992,13 +992,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~boot-cpuid arch/ppc64/kernel/setup.c
--- linux-2.5/arch/ppc64/kernel/setup.c~boot-cpuid	2004-11-16 12:41:26.559911125 -0600
+++ linux-2.5-olof/arch/ppc64/kernel/setup.c	2004-11-16 13:22:53.060669846 -0600
@@ -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~boot-cpuid include/asm-ppc64/prom.h
--- linux-2.5/include/asm-ppc64/prom.h~boot-cpuid	2004-11-16 12:41:26.561911570 -0600
+++ linux-2.5-olof/include/asm-ppc64/prom.h	2004-11-16 12:41:26.577915128 -0600
@@ -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~boot-cpuid include/asm-ppc64/smp.h
--- linux-2.5/include/asm-ppc64/smp.h~boot-cpuid	2004-11-16 12:41:26.564912237 -0600
+++ linux-2.5-olof/include/asm-ppc64/smp.h	2004-11-16 12:41:26.577915128 -0600
@@ -27,6 +27,7 @@
 #include <asm/paca.h>
 
 extern int boot_cpuid;
+extern int boot_cpuid_phys;
 
 extern void cpu_die(void) __attribute__((noreturn));
 

_




More information about the Linuxppc64-dev mailing list