[LWN Logo]

Date:	Tue, 27 Oct 1998 04:17:23 -0500 (EST)
From:	Ion Badulescu <ionut@moisil.cs.columbia.edu>
To:	sparclinux@vger.rutgers.edu
Subject: SMP mode on 4/600 w/ 4 CPU's: success

Hello,

I've finally found the bug which prevented 4-CPU machines from booting
under Linux/SPARC in SMP mode. The patch below fixes it, and does a few
other things:

o makes prom_printf() a macro which calls both the old prom_printf
(renamed as real_prom_printf) and printk. This way messages appear both on
dummycon (for debugging) and in dmesg's output for later study.

o changes a bunch of printk's to prom_printf's -- they are called before
the real console is initialized.

o adds a missing \n to a printk

If you have a 4/600 which had problems booting SMP before, I'd love to
hear if this patch fixes those problems.

A similar patch (for the SMP problem) should be applied to the 2.0 tree.

Thanks,
Ion

-- 
  It is better to keep your mouth shut and be thought a fool,
            than to open it and remove all doubt.
---------------------------
diff -urNX diff_excludes linux/arch/sparc/kernel/devices.c linux-local/arch/sparc/kernel/devices.c
--- linux/arch/sparc/kernel/devices.c	Tue Oct 27 02:22:52 1998
+++ linux-local/arch/sparc/kernel/devices.c	Tue Oct 27 00:07:44 1998
@@ -68,11 +68,11 @@
 			}
 		}
 		if(linux_num_cpus == 0) {
-			printk("No CPU nodes found, cannot continue.\n");
+			prom_printf("No CPU nodes found, cannot continue.\n");
 			/* Probably a sun4e, Sun is trying to trick us ;-) */
 			halt();
 		}
-		printk("Found %d CPU prom device tree node(s).\n", linux_num_cpus);
+		prom_printf("Found %d CPU prom device tree node(s).\n", linux_num_cpus);
 	};
 
 	cpu_probe();
diff -urNX diff_excludes linux/arch/sparc/kernel/idprom.c linux-local/arch/sparc/kernel/idprom.c
--- linux/arch/sparc/kernel/idprom.c	Tue Oct 27 02:22:59 1998
+++ linux-local/arch/sparc/kernel/idprom.c	Mon Oct 26 18:03:14 1998
@@ -54,11 +54,11 @@
 	for (i = 0; i < NUM_SUN_MACHINES; i++) {
 		if(Sun_Machines[i].id_machtype == machtype) {
 			if (machtype != (SM_SUN4M_OBP | 0x00))
-				printk("TYPE: %s\n", Sun_Machines[i].name);
+				prom_printf("TYPE: %s\n", Sun_Machines[i].name);
 			else {
 				prom_getproperty(prom_root_node, "banner-name",
 						 sysname, sizeof(sysname));
-				printk("TYPE: %s\n", sysname);
+				prom_printf("TYPE: %s\n", sysname);
 			}
 			return;
 		}
@@ -99,7 +99,7 @@
 
 	display_system_type(idprom->id_machtype);
 
-	printk("Ethernet address: %x:%x:%x:%x:%x:%x\n",
+	prom_printf("Ethernet address: %x:%x:%x:%x:%x:%x\n",
 		    idprom->id_ethaddr[0], idprom->id_ethaddr[1],
 		    idprom->id_ethaddr[2], idprom->id_ethaddr[3],
 		    idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
diff -urNX diff_excludes linux/arch/sparc/kernel/setup.c linux-local/arch/sparc/kernel/setup.c
--- linux/arch/sparc/kernel/setup.c	Tue Oct 27 02:23:04 1998
+++ linux-local/arch/sparc/kernel/setup.c	Mon Oct 26 16:54:41 1998
@@ -327,39 +327,39 @@
 	sparc_cpu_model=ap1000;
 	strcpy(&cputypval, "ap+");
 #endif
-	printk("ARCH: ");
+	prom_printf("ARCH: ");
 	packed = 0;
 	switch(sparc_cpu_model) {
 	case sun4:
-		printk("SUN4\n");
+		prom_printf("SUN4\n");
 		packed = 0;
 		break;
 	case sun4c:
-		printk("SUN4C\n");
+		prom_printf("SUN4C\n");
 		packed = 0;
 		break;
 	case sun4m:
-		printk("SUN4M\n");
+		prom_printf("SUN4M\n");
 		packed = 1;
 		break;
 	case sun4d:
-		printk("SUN4D\n");
+		prom_printf("SUN4D\n");
 		packed = 1;
 		break;
 	case sun4e:
-		printk("SUN4E\n");
+		prom_printf("SUN4E\n");
 		packed = 0;
 		break;
 	case sun4u:
-		printk("SUN4U\n");
+		prom_printf("SUN4U\n");
 		break;
 	case ap1000:
 		register_console(&prom_console);
-		printk("AP1000\n");
+		prom_printf("AP1000\n");
 		packed = 1;
 		break;
 	default:
-		printk("UNKNOWN!\n");
+		prom_printf("UNKNOWN!\n");
 		break;
 	};
 
diff -urNX diff_excludes linux/arch/sparc/kernel/sun4d_smp.c linux-local/arch/sparc/kernel/sun4d_smp.c
--- linux/arch/sparc/kernel/sun4d_smp.c	Tue Oct 27 02:23:09 1998
+++ linux-local/arch/sparc/kernel/sun4d_smp.c	Tue Oct 27 04:05:28 1998
@@ -166,11 +166,7 @@
 	int cpucount = 0;
 	int i = 0;
 
-	printk("Entering SMP Mode...\n");
-	
-	smp_penguin_ctable.which_io = 0;
-	smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
-	smp_penguin_ctable.reg_size = 0;
+	prom_printf("Entering SMP Mode...\n");
 
 	for (i = 0; i < NR_CPUS; i++)
 		cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data;
@@ -216,11 +212,20 @@
 
 			p->processor = i;
 			current_set[i] = p;
-			
+
 			for (no = 0; no < linux_num_cpus; no++)
 				if (linux_cpus[no].mid == i)
 					break;
-			
+
+			/*
+			 * Initialize the contexts table
+			 * Since the call to prom_startcpu() trashes the structure,
+			 * we need to re-initialize it for each cpu
+			 */
+			smp_penguin_ctable.which_io = 0;
+			smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
+			smp_penguin_ctable.reg_size = 0;
+
 			/* whirrr, whirrr, whirrrrrrrrr... */
 			SMP_PRINTK(("Starting CPU %d at %p task %d node %08x\n", i, entry, cpucount, linux_cpus[no].prom_node));
 			local_flush_cache_all();
@@ -230,10 +235,10 @@
 			SMP_PRINTK(("prom_startcpu returned :)\n"));
 
 			/* wheee... it's going... */
-			for(timeout = 0; timeout < 5000000; timeout++) {
+			for(timeout = 0; timeout < 10000; timeout++) {
 				if(cpu_callin_map[i])
 					break;
-				udelay(100);
+				udelay(200);
 			}
 			
 			if(cpu_callin_map[i]) {
@@ -242,7 +247,7 @@
 				__cpu_logical_map[cpucount] = i;
 			} else {
 				cpucount--;
-				printk("Processor %d is stuck.\n", i);
+				prom_printf("Processor %d is stuck.\n", i);
 			}
 		}
 		if(!(cpu_callin_map[i])) {
@@ -252,7 +257,7 @@
 	}
 	local_flush_cache_all();
 	if(cpucount == 0) {
-		printk("Error: only one Processor found.\n");
+		prom_printf("Error: only one Processor found.\n");
 		cpu_present_map = (1 << hard_smp4d_processor_id());
 	} else {
 		unsigned long bogosum = 0;
@@ -264,10 +269,10 @@
 			}
 		}
 		SMP_PRINTK(("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n", cpucount + 1, (bogosum + 2500)/500000, ((bogosum + 2500)/5000)%100));
-		printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n",
-		       cpucount + 1,
-		       (bogosum + 2500)/500000,
-		       ((bogosum + 2500)/5000)%100);
+		prom_printf("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n",
+			    cpucount + 1,
+			    (bogosum + 2500)/500000,
+			    ((bogosum + 2500)/5000)%100);
 		smp_activated = 1;
 		smp_num_cpus = cpucount + 1;
 	}
diff -urNX diff_excludes linux/arch/sparc/kernel/sun4m_smp.c linux-local/arch/sparc/kernel/sun4m_smp.c
--- linux/arch/sparc/kernel/sun4m_smp.c	Tue Oct 27 02:23:10 1998
+++ linux-local/arch/sparc/kernel/sun4m_smp.c	Tue Oct 27 00:06:00 1998
@@ -135,17 +135,14 @@
 extern unsigned long trapbase_cpu2[];
 extern unsigned long trapbase_cpu3[];
 
+
 __initfunc(void smp4m_boot_cpus(void))
 {
 	int cpucount = 0;
 	int i = 0;
 	int first, prev;
 
-	printk("Entering SMP Mode...\n");
-
-	smp_penguin_ctable.which_io = 0;
-	smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
-	smp_penguin_ctable.reg_size = 0;
+	prom_printf("Entering SMP Mode...\n");
 
 	for (i = 0; i < NR_CPUS; i++)
 		cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data;
@@ -189,18 +186,28 @@
 			/* See trampoline.S for details... */
 			entry += ((i-1) * 3);
 
+			/*
+			 * Initialize the contexts table
+			 * Since the call to prom_startcpu() trashes the structure,
+			 * we need to re-initialize it for each cpu
+			 */
+			smp_penguin_ctable.which_io = 0;
+			smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
+			smp_penguin_ctable.reg_size = 0;
+
 			/* whirrr, whirrr, whirrrrrrrrr... */
-			printk("Starting CPU %d at %p\n", i, entry);
+			prom_printf("Starting CPU %d at %p\n", i, entry);
 			mid_xlate[i] = (linux_cpus[i].mid & ~8);
 			local_flush_cache_all();
 			prom_startcpu(linux_cpus[i].prom_node,
 				      &smp_penguin_ctable, 0, (char *)entry);
 
 			/* wheee... it's going... */
-			for(timeout = 0; timeout < 5000000; timeout++) {
+			prom_printf("Waiting for CPU #%d to come online...\n", i);
+			for(timeout = 0; timeout < 10000; timeout++) {
 				if(cpu_callin_map[i])
 					break;
-				udelay(100);
+				udelay(200);
 			}
 			if(cpu_callin_map[i]) {
 				/* Another "Red Snapper". */
@@ -208,7 +215,7 @@
 				__cpu_logical_map[i] = i;
 			} else {
 				cpucount--;
-				printk("Processor %d is stuck.\n", i);
+				prom_printf("Processor %d is stuck.\n", i);
 			}
 		}
 		if(!(cpu_callin_map[i])) {
@@ -218,7 +225,7 @@
 	}
 	local_flush_cache_all();
 	if(cpucount == 0) {
-		printk("Error: only one Processor found.\n");
+		prom_printf("Error: only one Processor found.\n");
 		cpu_present_map = (1 << smp_processor_id());
 	} else {
 		unsigned long bogosum = 0;
@@ -226,7 +233,7 @@
 			if(cpu_present_map & (1 << i))
 				bogosum += cpu_data[i].udelay_val;
 		}
-		printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n",
+		prom_printf("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n",
 		       cpucount + 1,
 		       (bogosum + 2500)/500000,
 		       ((bogosum + 2500)/5000)%100);
diff -urNX diff_excludes linux/arch/sparc/mm/fault.c linux-local/arch/sparc/mm/fault.c
--- linux/arch/sparc/mm/fault.c	Tue Oct 27 02:23:42 1998
+++ linux-local/arch/sparc/mm/fault.c	Mon Oct 26 20:49:09 1998
@@ -140,7 +140,7 @@
 {
 	if((unsigned long) address < PAGE_SIZE) {
 		printk(KERN_ALERT "Unable to handle kernel NULL "
-		       "pointer dereference");
+		       "pointer dereference\n");
 	} else {
 		printk(KERN_ALERT "Unable to handle kernel paging request "
 		       "at virtual address %08lx\n", address);
diff -urNX diff_excludes linux/arch/sparc/prom/init.c linux-local/arch/sparc/prom/init.c
--- linux/arch/sparc/prom/init.c	Tue Oct 27 02:24:00 1998
+++ linux-local/arch/sparc/prom/init.c	Mon Oct 26 18:03:58 1998
@@ -94,8 +94,8 @@
 
 #ifndef CONFIG_SUN4
 	/* SUN4 prints this in sun4_prom_init */
-	printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
-	       romvec->pv_romvers, prom_rev);
+	prom_printf("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
+		    romvec->pv_romvers, prom_rev);
 #endif
 
 	/* Initialization successful. */
diff -urNX diff_excludes linux/arch/sparc/prom/printf.c linux-local/arch/sparc/prom/printf.c
--- linux/arch/sparc/prom/printf.c	Tue Oct 27 02:24:02 1998
+++ linux-local/arch/sparc/prom/printf.c	Tue Oct 27 03:51:53 1998
@@ -17,7 +17,7 @@
 static char ppbuf[1024];
 
 void
-prom_printf(char *fmt, ...)
+real_prom_printf(char *fmt, ...)
 {
 	va_list args;
 	char ch, *bptr;
diff -urNX diff_excludes linux/include/asm-sparc/oplib.h linux-local/include/asm-sparc/oplib.h
--- linux/include/asm-sparc/oplib.h	Tue Oct 27 02:42:38 1998
+++ linux-local/include/asm-sparc/oplib.h	Mon Oct 26 17:37:31 1998
@@ -153,7 +153,12 @@
 extern void prom_putchar(char character);
 
 /* Prom's internal printf routine, don't use in kernel/boot code. */
-void prom_printf(char *fmt, ...);
+#define prom_printf(fmt, args...) \
+do { \
+	real_prom_printf(fmt, ##args); \
+	printk(fmt, ##args); \
+} while (0)
+void real_prom_printf(char *fmt, ...);
 
 /* Query for input device type */
 

-
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of the message to majordomo@vger.rutgers.edu