Module Name:    src
Committed By:   martin
Date:           Sat Feb 20 16:46:38 UTC 2010

Modified Files:
        src/sys/arch/sparc64/include: sparc64.h
        src/sys/arch/sparc64/sparc64: ipifuncs.c ofw_machdep.c

Log Message:
Select the shutdown method for secondary CPUs by available firmware
methods, not properties of the CPU.
Inspired by OpenSolaris, pointed out by eeh.


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/sys/arch/sparc64/include/sparc64.h
cvs rdiff -u -r1.30 -r1.31 src/sys/arch/sparc64/sparc64/ipifuncs.c
cvs rdiff -u -r1.36 -r1.37 src/sys/arch/sparc64/sparc64/ofw_machdep.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/sparc64/include/sparc64.h
diff -u src/sys/arch/sparc64/include/sparc64.h:1.10 src/sys/arch/sparc64/include/sparc64.h:1.11
--- src/sys/arch/sparc64/include/sparc64.h:1.10	Mon May 18 12:15:26 2009
+++ src/sys/arch/sparc64/include/sparc64.h	Sat Feb 20 16:46:38 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: sparc64.h,v 1.10 2009/05/18 12:15:26 nakayama Exp $	*/
+/*	$NetBSD: sparc64.h,v 1.11 2010/02/20 16:46:38 martin Exp $	*/
 
 /*
  * Copyright (C) 1996 Wolfgang Solfrank.
@@ -51,6 +51,9 @@
 paddr_t prom_get_msgbuf(int, int);
 
 void prom_stopself(void);
+bool prom_has_stopself(void);
+int  prom_stop_other(u_int);
+bool prom_has_stop_other(void);
 void prom_startcpu(u_int, void *, u_long);
 
 #endif	/* _MACHINE_SPARC64_H_ */

Index: src/sys/arch/sparc64/sparc64/ipifuncs.c
diff -u src/sys/arch/sparc64/sparc64/ipifuncs.c:1.30 src/sys/arch/sparc64/sparc64/ipifuncs.c:1.31
--- src/sys/arch/sparc64/sparc64/ipifuncs.c:1.30	Tue Feb  2 04:28:56 2010
+++ src/sys/arch/sparc64/sparc64/ipifuncs.c	Sat Feb 20 16:46:38 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipifuncs.c,v 1.30 2010/02/02 04:28:56 mrg Exp $ */
+/*	$NetBSD: ipifuncs.c,v 1.31 2010/02/20 16:46:38 martin Exp $ */
 
 /*-
  * Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.30 2010/02/02 04:28:56 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.31 2010/02/20 16:46:38 martin Exp $");
 
 #include "opt_ddb.h"
 
@@ -53,6 +53,7 @@
 
 /* CPU sets containing halted, paused and resumed cpus */
 static volatile sparc64_cpuset_t cpus_halted;
+static volatile sparc64_cpuset_t cpus_spinning;
 static volatile sparc64_cpuset_t cpus_paused;
 static volatile sparc64_cpuset_t cpus_resumed;
 
@@ -78,16 +79,19 @@
 	extern void prom_printf(const char *fmt, ...);
 
 	printf("cpu%d: shutting down\n", cpu_number());
-	CPUSET_ADD(cpus_halted, cpu_number());
-	if (CPU_IS_USIII_UP()) {
+	if (prom_has_stop_other() || !prom_has_stopself()) {
 		/*
-		 * prom_selfstop() doesn't seem to work on newer machines.
+		 * just loop here, the final cpu will stop us later
 		 */
+		CPUSET_ADD(cpus_spinning, cpu_number());
+		CPUSET_ADD(cpus_halted, cpu_number());
 		spl0();
 		while (1)
 			/* nothing */;
-	} else
+	} else {
+		CPUSET_ADD(cpus_halted, cpu_number());
 		prom_stopself();
+	}
 }
 
 void
@@ -151,6 +155,7 @@
 
 	/* Clear all cpu sets. */
 	CPUSET_CLEAR(cpus_halted);
+	CPUSET_CLEAR(cpus_spinning);
 	CPUSET_CLEAR(cpus_paused);
 	CPUSET_CLEAR(cpus_resumed);
 }
@@ -272,6 +277,7 @@
 mp_halt_cpus(void)
 {
 	sparc64_cpuset_t cpumask, cpuset;
+	struct cpu_info *ci;
 
 	CPUSET_ASSIGN(cpuset, cpus_active);
 	CPUSET_DEL(cpuset, cpu_number());
@@ -281,9 +287,28 @@
 	if (CPUSET_EMPTY(cpuset))
 		return;
 
+	CPUSET_CLEAR(cpus_spinning);
 	sparc64_multicast_ipi(cpuset, sparc64_ipi_halt, 0, 0);
 	if (sparc64_ipi_wait(&cpus_halted, cpumask))
 		sparc64_ipi_error("halt", cpumask, cpus_halted);
+
+	/*
+	 * Depending on available firmware methods, other cpus will
+	 * either shut down themselfs, or spin and wait for us to
+	 * stop them.
+	 */
+	if (CPUSET_EMPTY(cpus_spinning)) {
+		/* give other cpus a few cycles to actually power down */
+		delay(10000);
+		return;
+	}
+	/* there are cpus spinning - shut them down if we can */
+	if (prom_has_stop_other()) {
+		for (ci = cpus; ci != NULL; ci = ci->ci_next) {
+			if (!CPUSET_HAS(cpus_spinning, ci->ci_index)) continue;
+			prom_stop_other(ci->ci_cpuid);
+		}
+	}
 }
 
 /*

Index: src/sys/arch/sparc64/sparc64/ofw_machdep.c
diff -u src/sys/arch/sparc64/sparc64/ofw_machdep.c:1.36 src/sys/arch/sparc64/sparc64/ofw_machdep.c:1.37
--- src/sys/arch/sparc64/sparc64/ofw_machdep.c:1.36	Thu Nov 26 20:15:20 2009
+++ src/sys/arch/sparc64/sparc64/ofw_machdep.c	Sat Feb 20 16:46:38 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: ofw_machdep.c,v 1.36 2009/11/26 20:15:20 mrg Exp $	*/
+/*	$NetBSD: ofw_machdep.c,v 1.37 2010/02/20 16:46:38 martin Exp $	*/
 
 /*
  * Copyright (C) 1996 Wolfgang Solfrank.
@@ -34,7 +34,7 @@
 #include "opt_multiprocessor.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ofw_machdep.c,v 1.36 2009/11/26 20:15:20 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ofw_machdep.c,v 1.37 2010/02/20 16:46:38 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/buf.h>
@@ -575,7 +575,41 @@
 	args.nreturns = 0;
 
 	openfirmware_exit(&args);
-	panic("sun4u_stopself: failed.");
+	panic("prom_stopself: failed.");
+}
+
+bool
+prom_has_stopself(void)
+{
+	return OF_test("SUNW,stop-self") == 0;
+}
+
+int
+prom_stop_other(u_int id)
+{
+	static struct {
+		cell_t  name;
+		cell_t  nargs;
+		cell_t  nreturns;
+		cell_t	cpuid;
+		cell_t	result;
+	} args;
+
+	args.name = ADR2CELL(&"SUNW,stop-cpu-by-cpuid");
+	args.nargs = 1;
+	args.nreturns = 1;
+	args.cpuid = id;
+	args.result = 0;
+
+	if (openfirmware(&args) == -1)
+		return -1;
+	return args.result;
+}
+
+bool
+prom_has_stop_other(void)
+{
+	return OF_test("SUNW,stop-cpu-by-cpuid") == 0;
 }
 #endif
 

Reply via email to