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