Module Name: src
Committed By: nonaka
Date: Fri Jan 23 07:27:06 UTC 2015
Modified Files:
src/sys/arch/evbppc/mpc85xx: machdep.c
src/sys/arch/powerpc/booke: booke_machdep.c e500_intr.c
src/sys/arch/powerpc/include: cpu.h db_machdep.h
src/sys/arch/powerpc/include/booke: intr.h
src/sys/arch/powerpc/pic: ipi.c ipivar.h
src/sys/arch/powerpc/powerpc: db_interface.c powerpc_machdep.c
Log Message:
ddb MP support
To generate a diff of this commit:
cvs rdiff -u -r1.39 -r1.40 src/sys/arch/evbppc/mpc85xx/machdep.c
cvs rdiff -u -r1.22 -r1.23 src/sys/arch/powerpc/booke/booke_machdep.c
cvs rdiff -u -r1.30 -r1.31 src/sys/arch/powerpc/booke/e500_intr.c
cvs rdiff -u -r1.100 -r1.101 src/sys/arch/powerpc/include/cpu.h
cvs rdiff -u -r1.24 -r1.25 src/sys/arch/powerpc/include/db_machdep.h
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/powerpc/include/booke/intr.h
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/powerpc/pic/ipi.c
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/powerpc/pic/ipivar.h
cvs rdiff -u -r1.52 -r1.53 src/sys/arch/powerpc/powerpc/db_interface.c
cvs rdiff -u -r1.70 -r1.71 src/sys/arch/powerpc/powerpc/powerpc_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/evbppc/mpc85xx/machdep.c
diff -u src/sys/arch/evbppc/mpc85xx/machdep.c:1.39 src/sys/arch/evbppc/mpc85xx/machdep.c:1.40
--- src/sys/arch/evbppc/mpc85xx/machdep.c:1.39 Tue Jan 6 01:23:24 2015
+++ src/sys/arch/evbppc/mpc85xx/machdep.c Fri Jan 23 07:27:05 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.39 2015/01/06 01:23:24 nonaka Exp $ */
+/* $NetBSD: machdep.c,v 1.40 2015/01/23 07:27:05 nonaka Exp $ */
/*-
* Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -41,6 +41,7 @@ __KERNEL_RCSID(0, "$NetSBD$");
#include "opt_altivec.h"
#include "opt_ddb.h"
#include "opt_mpc85xx.h"
+#include "opt_multiprocessor.h"
#include "opt_pci.h"
#include "gpio.h"
#include "pci.h"
@@ -1054,6 +1055,13 @@ e500_cpu_attach(device_t self, u_int ins
void
e500_ipi_halt(void)
{
+#ifdef MULTIPROCESSOR
+ struct cpuset_info * const csi = &cpuset_info;
+ const cpuid_t index = cpu_index(curcpu());
+
+ printf("cpu%lu: shutting down\n", index);
+ kcpuset_set(csi->cpus_halted, index);
+#endif
register_t msr, hid0;
msr = wrtee(0);
Index: src/sys/arch/powerpc/booke/booke_machdep.c
diff -u src/sys/arch/powerpc/booke/booke_machdep.c:1.22 src/sys/arch/powerpc/booke/booke_machdep.c:1.23
--- src/sys/arch/powerpc/booke/booke_machdep.c:1.22 Fri Jan 23 06:39:41 2015
+++ src/sys/arch/powerpc/booke/booke_machdep.c Fri Jan 23 07:27:05 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: booke_machdep.c,v 1.22 2015/01/23 06:39:41 nonaka Exp $ */
+/* $NetBSD: booke_machdep.c,v 1.23 2015/01/23 07:27:05 nonaka Exp $ */
/*-
* Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -38,7 +38,7 @@
#define _POWERPC_BUS_DMA_PRIVATE
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: booke_machdep.c,v 1.22 2015/01/23 06:39:41 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: booke_machdep.c,v 1.23 2015/01/23 07:27:05 nonaka Exp $");
#include "opt_modular.h"
@@ -230,6 +230,8 @@ booke_cpu_startup(const char *model)
kcpuset_create(&cpuset_info.cpus_paused, true);
kcpuset_create(&cpuset_info.cpus_resumed, true);
kcpuset_create(&cpuset_info.cpus_halted, true);
+
+ kcpuset_set(cpuset_info.cpus_running, cpu_number());
#endif /* MULTIPROCESSOR */
}
Index: src/sys/arch/powerpc/booke/e500_intr.c
diff -u src/sys/arch/powerpc/booke/e500_intr.c:1.30 src/sys/arch/powerpc/booke/e500_intr.c:1.31
--- src/sys/arch/powerpc/booke/e500_intr.c:1.30 Fri Jan 23 06:16:23 2015
+++ src/sys/arch/powerpc/booke/e500_intr.c Fri Jan 23 07:27:05 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: e500_intr.c,v 1.30 2015/01/23 06:16:23 nonaka Exp $ */
+/* $NetBSD: e500_intr.c,v 1.31 2015/01/23 07:27:05 nonaka Exp $ */
/*-
* Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -35,11 +35,13 @@
*/
#include "opt_mpc85xx.h"
+#include "opt_multiprocessor.h"
+#include "opt_ddb.h"
#define __INTR_PRIVATE
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: e500_intr.c,v 1.30 2015/01/23 06:16:23 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: e500_intr.c,v 1.31 2015/01/23 07:27:05 nonaka Exp $");
#include <sys/param.h>
#include <sys/proc.h>
@@ -1268,6 +1270,15 @@ e500_ipi_kpreempt(void)
}
#endif
+static void
+e500_ipi_suspend(void)
+{
+
+#ifdef MULTIPROCESSOR
+ cpu_pause(NULL);
+#endif /* MULTIPROCESSOR */
+}
+
static const ipifunc_t e500_ipifuncs[] = {
[ilog2(IPI_XCALL)] = xc_ipi_handler,
[ilog2(IPI_GENERIC)] = ipi_cpu_handler,
@@ -1276,6 +1287,7 @@ static const ipifunc_t e500_ipifuncs[] =
[ilog2(IPI_KPREEMPT)] = e500_ipi_kpreempt,
#endif
[ilog2(IPI_TLB1SYNC)] = e500_tlb1_sync,
+ [ilog2(IPI_SUSPEND)] = e500_ipi_suspend,
};
static int
Index: src/sys/arch/powerpc/include/cpu.h
diff -u src/sys/arch/powerpc/include/cpu.h:1.100 src/sys/arch/powerpc/include/cpu.h:1.101
--- src/sys/arch/powerpc/include/cpu.h:1.100 Mon Mar 24 19:29:59 2014
+++ src/sys/arch/powerpc/include/cpu.h Fri Jan 23 07:27:05 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.h,v 1.100 2014/03/24 19:29:59 christos Exp $ */
+/* $NetBSD: cpu.h,v 1.101 2015/01/23 07:27:05 nonaka Exp $ */
/*
* Copyright (C) 1999 Wolfgang Solfrank.
@@ -393,6 +393,14 @@ register_t
cpu_hatch(void);
void cpu_spinup_trampoline(void);
void cpu_boot_secondary_processors(void);
+void cpu_halt(void);
+void cpu_halt_others(void);
+void cpu_pause(struct trapframe *);
+void cpu_pause_others(void);
+void cpu_resume(cpuid_t);
+void cpu_resume_others(void);
+int cpu_is_paused(int);
+void cpu_debug_dump(void);
#endif /* MULTIPROCESSOR */
#endif /* !_MODULE */
Index: src/sys/arch/powerpc/include/db_machdep.h
diff -u src/sys/arch/powerpc/include/db_machdep.h:1.24 src/sys/arch/powerpc/include/db_machdep.h:1.25
--- src/sys/arch/powerpc/include/db_machdep.h:1.24 Tue Jun 14 03:28:32 2011
+++ src/sys/arch/powerpc/include/db_machdep.h Fri Jan 23 07:27:05 2015
@@ -1,5 +1,5 @@
/* $OpenBSD: db_machdep.h,v 1.2 1997/03/21 00:48:48 niklas Exp $ */
-/* $NetBSD: db_machdep.h,v 1.24 2011/06/14 03:28:32 matt Exp $ */
+/* $NetBSD: db_machdep.h,v 1.25 2015/01/23 07:27:05 nonaka Exp $ */
/*
* Mach Operating System
@@ -163,6 +163,10 @@ typedef long kgdb_reg_t;
void kdb_kintr(void *);
int kdb_trap(int, void *);
+bool ddb_running_on_this_cpu_p(void);
+bool ddb_running_on_any_cpu_p(void);
+void db_resume_others(void);
+
/*
* We have machine-dependent commands.
*/
Index: src/sys/arch/powerpc/include/booke/intr.h
diff -u src/sys/arch/powerpc/include/booke/intr.h:1.8 src/sys/arch/powerpc/include/booke/intr.h:1.9
--- src/sys/arch/powerpc/include/booke/intr.h:1.8 Mon May 19 22:47:53 2014
+++ src/sys/arch/powerpc/include/booke/intr.h Fri Jan 23 07:27:05 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: intr.h,v 1.8 2014/05/19 22:47:53 rmind Exp $ */
+/* $NetBSD: intr.h,v 1.9 2015/01/23 07:27:05 nonaka Exp $ */
/*-
* Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -74,6 +74,7 @@
#define IPI_KPREEMPT 0x0004
#define IPI_TLB1SYNC 0x0008
#define IPI_GENERIC 0x0010
+#define IPI_SUSPEND 0x0020
#define __HAVE_FAST_SOFTINTS 1
#define SOFTINT_KPREEMPT SOFTINT_COUNT
Index: src/sys/arch/powerpc/pic/ipi.c
diff -u src/sys/arch/powerpc/pic/ipi.c:1.11 src/sys/arch/powerpc/pic/ipi.c:1.12
--- src/sys/arch/powerpc/pic/ipi.c:1.11 Mon May 19 22:47:53 2014
+++ src/sys/arch/powerpc/pic/ipi.c Fri Jan 23 07:27:05 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ipi.c,v 1.11 2014/05/19 22:47:53 rmind Exp $ */
+/* $NetBSD: ipi.c,v 1.12 2015/01/23 07:27:05 nonaka Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -29,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipi.c,v 1.11 2014/05/19 22:47:53 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipi.c,v 1.12 2015/01/23 07:27:05 nonaka Exp $");
#include "opt_multiprocessor.h"
#include "opt_pic.h"
@@ -75,8 +75,13 @@ ipi_intr(void *v)
if (ipi & IPI_GENERIC)
ipi_cpu_handler();
+ if (ipi & IPI_SUSPEND)
+ cpu_pause(NULL);
+
if (ipi & IPI_HALT) {
+ struct cpuset_info * const csi = &cpuset_info;
aprint_normal("halting CPU %d\n", cpu_id);
+ kcpuset_set(csi->cpus_halted, cpu_id);
msr = (mfmsr() & ~PSL_EE) | PSL_POW;
for (;;) {
__asm volatile ("sync; isync");
Index: src/sys/arch/powerpc/pic/ipivar.h
diff -u src/sys/arch/powerpc/pic/ipivar.h:1.7 src/sys/arch/powerpc/pic/ipivar.h:1.8
--- src/sys/arch/powerpc/pic/ipivar.h:1.7 Mon May 19 22:47:53 2014
+++ src/sys/arch/powerpc/pic/ipivar.h Fri Jan 23 07:27:05 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: ipivar.h,v 1.7 2014/05/19 22:47:53 rmind Exp $ */
+/* $NetBSD: ipivar.h,v 1.8 2015/01/23 07:27:05 nonaka Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -29,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipivar.h,v 1.7 2014/05/19 22:47:53 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipivar.h,v 1.8 2015/01/23 07:27:05 nonaka Exp $");
#ifndef _IPI_VAR_H_
#define _IPI_VAR_H_
@@ -55,6 +55,7 @@ struct ipi_ops {
#define IPI_XCALL 0x0002
#define IPI_KPREEMPT 0x0004
#define IPI_GENERIC 0x0008
+#define IPI_SUSPEND 0x0010
/* OpenPIC */
void setup_openpic_ipi(void);
Index: src/sys/arch/powerpc/powerpc/db_interface.c
diff -u src/sys/arch/powerpc/powerpc/db_interface.c:1.52 src/sys/arch/powerpc/powerpc/db_interface.c:1.53
--- src/sys/arch/powerpc/powerpc/db_interface.c:1.52 Thu Jul 4 22:59:58 2013
+++ src/sys/arch/powerpc/powerpc/db_interface.c Fri Jan 23 07:27:05 2015
@@ -1,19 +1,21 @@
-/* $NetBSD: db_interface.c,v 1.52 2013/07/04 22:59:58 joerg Exp $ */
+/* $NetBSD: db_interface.c,v 1.53 2015/01/23 07:27:05 nonaka Exp $ */
/* $OpenBSD: db_interface.c,v 1.2 1996/12/28 06:21:50 rahnds Exp $ */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.52 2013/07/04 22:59:58 joerg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.53 2015/01/23 07:27:05 nonaka Exp $");
#define USERACC
#include "opt_ddb.h"
#include "opt_kgdb.h"
+#include "opt_multiprocessor.h"
#include "opt_ppcarch.h"
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/cpu.h>
+#include <sys/atomic.h>
#include <dev/cons.h>
@@ -48,6 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: db_interface
#include <ddb/db_access.h>
#include <ddb/db_lex.h>
#include <ddb/db_output.h>
+#include <ddb/db_run.h> /* for db_continue_cmd() proto */
#include <ddb/ddbvar.h>
#endif
@@ -58,6 +61,9 @@ __KERNEL_RCSID(0, "$NetBSD: db_interface
#include <dev/ofw/openfirm.h>
+#define NOCPU ~0
+volatile u_int ddb_cpu = NOCPU;
+
int db_active = 0;
db_regs_t ddb_regs;
@@ -89,6 +95,10 @@ static void db_ppcbooke_tf(db_expr_t, bo
static void db_ppcbooke_dumptlb(db_expr_t, bool, db_expr_t, const char *);
#endif
+#ifdef MULTIPROCESSOR
+static void db_mach_cpu(db_expr_t, bool, db_expr_t, const char *);
+#endif /* MULTIPROCESSOR */
+
#ifdef DDB
const struct db_command db_machine_command_table[] = {
#if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
@@ -138,6 +148,12 @@ const struct db_command db_machine_comma
"Display instruction translation storage buffer information.",
NULL,NULL) },
#endif /* PPC_BOOKE */
+
+#ifdef MULTIPROCESSOR
+ { DDB_ADD_CMD("cpu", db_mach_cpu, 0,
+ "switch to another cpu", "cpu-no", NULL) },
+#endif /* MULTIPROCESSOR */
+
{ DDB_ADD_CMD(NULL, NULL, 0,
NULL,NULL,NULL) }
};
@@ -183,6 +199,8 @@ int
kdb_trap(int type, void *v)
{
struct trapframe *tf = v;
+ int rv = 1;
+ int s;
#ifdef DDB
if (db_recover != 0 && (type != -1 && type != T_BREAKPOINT)) {
@@ -193,6 +211,24 @@ kdb_trap(int type, void *v)
/* XXX Should switch to kdb's own stack here. */
+#ifdef MULTIPROCESSOR
+ bool first_in_ddb = false;
+ const u_int cpu_me = cpu_number();
+ const u_int old_ddb_cpu = atomic_cas_uint(&ddb_cpu, NOCPU, cpu_me);
+ if (old_ddb_cpu == NOCPU) {
+ first_in_ddb = true;
+ cpu_pause_others();
+ } else {
+ if (old_ddb_cpu != cpu_me) {
+ KASSERT(cpu_is_paused(cpu_me));
+ cpu_pause(tf);
+ return 1;
+ }
+ }
+ KASSERT(!cpu_is_paused(cpu_me));
+#endif /* MULTIPROCESSOR */
+
+ s = splhigh();
memcpy(DDB_REGS->r, tf->tf_fixreg, 32 * sizeof(u_int32_t));
DDB_REGS->iar = tf->tf_srr0;
DDB_REGS->msr = tf->tf_srr1;
@@ -215,8 +251,10 @@ kdb_trap(int type, void *v)
cnpollc(0);
db_active--;
#elif defined(KGDB)
- if (!kgdb_trap(type, DDB_REGS))
- return 0;
+ if (!kgdb_trap(type, DDB_REGS)) {
+ rv = 0;
+ goto out;
+ }
#endif
/* KGDB isn't smart about advancing PC if we
@@ -246,8 +284,22 @@ kdb_trap(int type, void *v)
tf->tf_esr = DDB_REGS->esr;
tf->tf_pid = DDB_REGS->pid;
#endif
+#ifdef KGDB
+ out:
+#endif /* KGDB */
+ splx(s);
+
+#ifdef MULTIPROCESSOR
+ if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me) {
+ cpu_resume_others();
+ } else {
+ cpu_resume(ddb_cpu);
+ if (first_in_ddb)
+ cpu_pause(tf);
+ }
+#endif /* MULTIPROCESSOR */
- return 1;
+ return rv;
}
#if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
@@ -789,3 +841,64 @@ db_ppcbooke_dumptlb(db_expr_t addr, bool
tlb_dump(db_printf);
}
#endif /* PPC_BOOKE */
+
+#ifdef MULTIPROCESSOR
+bool
+ddb_running_on_this_cpu_p(void)
+{
+
+ return ddb_cpu == cpu_number();
+}
+
+bool
+ddb_running_on_any_cpu_p(void)
+{
+
+ return ddb_cpu != NOCPU;
+}
+
+void
+db_resume_others(void)
+{
+ u_int cpu_me = cpu_number();
+
+ if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me)
+ cpu_resume_others();
+}
+
+static void
+db_mach_cpu(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
+{
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+ bool found = false;
+
+ if (!have_addr) {
+ cpu_debug_dump();
+ return;
+ }
+
+ if (addr < 0) {
+ db_printf("%ld: CPU out of range\n", addr);
+ return;
+ }
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ if (cpu_index(ci) == addr) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ db_printf("CPU %ld not configured\n", addr);
+ return;
+ }
+ if (ci != curcpu()) {
+ if (!cpu_is_paused(cpu_index(ci))) {
+ db_printf("CPU %ld not paused\n", (long)addr);
+ return;
+ }
+ (void)atomic_cas_uint(&ddb_cpu, cpu_number(), cpu_index(ci));
+ db_continue_cmd(0, false, 0, "");
+ }
+}
+#endif /* MULTIPROCESSOR */
Index: src/sys/arch/powerpc/powerpc/powerpc_machdep.c
diff -u src/sys/arch/powerpc/powerpc/powerpc_machdep.c:1.70 src/sys/arch/powerpc/powerpc/powerpc_machdep.c:1.71
--- src/sys/arch/powerpc/powerpc/powerpc_machdep.c:1.70 Mon May 19 22:47:53 2014
+++ src/sys/arch/powerpc/powerpc/powerpc_machdep.c Fri Jan 23 07:27:05 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: powerpc_machdep.c,v 1.70 2014/05/19 22:47:53 rmind Exp $ */
+/* $NetBSD: powerpc_machdep.c,v 1.71 2015/01/23 07:27:05 nonaka Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,9 +32,10 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: powerpc_machdep.c,v 1.70 2014/05/19 22:47:53 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: powerpc_machdep.c,v 1.71 2015/01/23 07:27:05 nonaka Exp $");
#include "opt_altivec.h"
+#include "opt_ddb.h"
#include "opt_modular.h"
#include "opt_multiprocessor.h"
#include "opt_ppcarch.h"
@@ -70,6 +71,12 @@ __KERNEL_RCSID(0, "$NetBSD: powerpc_mach
#ifdef MULTIPROCESSOR
#include <powerpc/pic/ipivar.h>
+#include <machine/cpu_counter.h>
+#endif
+
+#ifdef DDB
+#include <machine/db_machdep.h>
+#include <ddb/db_output.h>
#endif
int cpu_timebase;
@@ -503,6 +510,254 @@ cpu_ipi(struct cpu_info *ci)
cpu_send_ipi(target, IPI_GENERIC);
}
+/* XXX kcpuset_create(9), kcpuset_clone(9) couldn't use interrupt context */
+typedef uint32_t __cpuset_t;
+CTASSERT(MAXCPUS <= 32);
+
+#define CPUSET_SINGLE(cpu) ((__cpuset_t)1 << (cpu))
+
+#define CPUSET_ADD(set, cpu) atomic_or_32(&(set), CPUSET_SINGLE(cpu))
+#define CPUSET_DEL(set, cpu) atomic_and_32(&(set), ~CPUSET_SINGLE(cpu))
+#define CPUSET_SUB(set1, set2) atomic_and_32(&(set1), ~(set2))
+
+#define CPUSET_EXCEPT(set, cpu) ((set) & ~CPUSET_SINGLE(cpu))
+
+#define CPUSET_HAS_P(set, cpu) ((set) & CPUSET_SINGLE(cpu))
+#define CPUSET_NEXT(set) (ffs(set) - 1)
+
+#define CPUSET_EMPTY_P(set) ((set) == (__cpuset_t)0)
+#define CPUSET_EQUAL_P(set1, set2) ((set1) == (set2))
+#define CPUSET_CLEAR(set) ((set) = (__cpuset_t)0)
+#define CPUSET_ASSIGN(set1, set2) ((set1) = (set2))
+
+#define CPUSET_EXPORT(kset, set) kcpuset_export_u32((kset), &(set), sizeof(set))
+
+/*
+ * Send an inter-processor interupt to CPUs in cpuset (excludes curcpu())
+ */
+static void
+cpu_multicast_ipi(__cpuset_t cpuset, uint32_t msg)
+{
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+
+ CPUSET_DEL(cpuset, cpu_index(curcpu()));
+ if (CPUSET_EMPTY_P(cpuset))
+ return;
+
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ const int index = cpu_index(ci);
+ if (CPUSET_HAS_P(cpuset, index)) {
+ CPUSET_DEL(cpuset, index);
+ cpu_send_ipi(index, msg);
+ }
+ }
+}
+
+static void
+cpu_ipi_error(const char *s, kcpuset_t *succeeded, __cpuset_t expected)
+{
+ __cpuset_t cpuset;
+
+ CPUSET_EXPORT(succeeded, cpuset);
+ CPUSET_SUB(expected, cpuset);
+ if (!CPUSET_EMPTY_P(expected)) {
+ printf("Failed to %s:", s);
+ do {
+ const int index = CPUSET_NEXT(expected);
+ CPUSET_DEL(expected, index);
+ printf(" cpu%d", index);
+ } while (!CPUSET_EMPTY_P(expected));
+ printf("\n");
+ }
+}
+
+static int
+cpu_ipi_wait(kcpuset_t *watchset, __cpuset_t mask)
+{
+ uint64_t tmout = curcpu()->ci_data.cpu_cc_freq; /* some finite amount of time */
+ __cpuset_t cpuset;
+
+ while (tmout--) {
+ CPUSET_EXPORT(watchset, cpuset);
+ if (cpuset == mask)
+ return 0; /* success */
+ }
+ return 1; /* timed out */
+}
+
+/*
+ * Halt this cpu.
+ */
+void
+cpu_halt(void)
+{
+ struct cpuset_info * const csi = &cpuset_info;
+ const cpuid_t index = cpu_index(curcpu());
+
+ printf("cpu%ld: shutting down\n", index);
+ kcpuset_set(csi->cpus_halted, index);
+ spl0(); /* allow interrupts e.g. further ipi ? */
+
+ /* spin */
+ for (;;)
+ continue;
+ /*NOTREACHED*/
+}
+
+/*
+ * Halt all running cpus, excluding current cpu.
+ */
+void
+cpu_halt_others(void)
+{
+ struct cpuset_info * const csi = &cpuset_info;
+ const cpuid_t index = cpu_index(curcpu());
+ __cpuset_t cpumask, cpuset, halted;
+
+ KASSERT(kpreempt_disabled());
+
+ CPUSET_EXPORT(csi->cpus_running, cpuset);
+ CPUSET_DEL(cpuset, index);
+ CPUSET_ASSIGN(cpumask, cpuset);
+ CPUSET_EXPORT(csi->cpus_halted, halted);
+ CPUSET_SUB(cpuset, halted);
+
+ if (CPUSET_EMPTY_P(cpuset))
+ return;
+
+ cpu_multicast_ipi(cpuset, IPI_HALT);
+ if (cpu_ipi_wait(csi->cpus_halted, cpumask))
+ cpu_ipi_error("halt", csi->cpus_halted, cpumask);
+
+ /*
+ * TBD
+ * Depending on available firmware methods, other cpus will
+ * either shut down themselfs, or spin and wait for us to
+ * stop them.
+ */
+}
+
+/*
+ * Pause this cpu.
+ */
+void
+cpu_pause(struct trapframe *tf)
+{
+ volatile struct cpuset_info * const csi = &cpuset_info;
+ int s = splhigh();
+ const cpuid_t index = cpu_index(curcpu());
+
+ for (;;) {
+ kcpuset_set(csi->cpus_paused, index);
+ while (kcpuset_isset(csi->cpus_paused, index))
+ docritpollhooks();
+ kcpuset_set(csi->cpus_resumed, index);
+#ifdef DDB
+ if (ddb_running_on_this_cpu_p())
+ cpu_Debugger();
+ if (ddb_running_on_any_cpu_p())
+ continue;
+#endif /* DDB */
+ break;
+ }
+
+ splx(s);
+}
+
+/*
+ * Pause all running cpus, excluding current cpu.
+ */
+void
+cpu_pause_others(void)
+{
+ struct cpuset_info * const csi = &cpuset_info;
+ const cpuid_t index = cpu_index(curcpu());
+ __cpuset_t cpuset;
+
+ KASSERT(kpreempt_disabled());
+
+ CPUSET_EXPORT(csi->cpus_running, cpuset);
+ CPUSET_DEL(cpuset, index);
+
+ if (CPUSET_EMPTY_P(cpuset))
+ return;
+
+ cpu_multicast_ipi(cpuset, IPI_SUSPEND);
+ if (cpu_ipi_wait(csi->cpus_paused, cpuset))
+ cpu_ipi_error("pause", csi->cpus_paused, cpuset);
+}
+
+/*
+ * Resume a single cpu.
+ */
+void
+cpu_resume(cpuid_t index)
+{
+ struct cpuset_info * const csi = &cpuset_info;
+ __cpuset_t cpuset = CPUSET_SINGLE(index);
+
+ kcpuset_zero(csi->cpus_resumed);
+ kcpuset_clear(csi->cpus_paused, index);
+
+ if (cpu_ipi_wait(csi->cpus_paused, cpuset))
+ cpu_ipi_error("resume", csi->cpus_resumed, cpuset);
+}
+
+/*
+ * Resume all paused cpus.
+ */
+void
+cpu_resume_others(void)
+{
+ struct cpuset_info * const csi = &cpuset_info;
+ __cpuset_t cpuset;
+
+ kcpuset_zero(csi->cpus_resumed);
+ CPUSET_EXPORT(csi->cpus_paused, cpuset);
+ kcpuset_zero(csi->cpus_paused);
+
+ if (cpu_ipi_wait(csi->cpus_resumed, cpuset))
+ cpu_ipi_error("resume", csi->cpus_resumed, cpuset);
+}
+
+int
+cpu_is_paused(int index)
+{
+ struct cpuset_info * const csi = &cpuset_info;
+
+ return kcpuset_isset(csi->cpus_paused, index);
+}
+
+#ifdef DDB
+void
+cpu_debug_dump(void)
+{
+ struct cpuset_info * const csi = &cpuset_info;
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+ char running, hatched, paused, resumed, halted;
+
+#ifdef _LP64
+ db_printf("CPU CPUID STATE CPUINFO CPL INT MTX IPIS\n");
+#else
+ db_printf("CPU CPUID STATE CPUINFO CPL INT MTX IPIS\n");
+#endif
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ const cpuid_t index = cpu_index(ci);
+ hatched = (kcpuset_isset(csi->cpus_hatched, index) ? 'H' : '-');
+ running = (kcpuset_isset(csi->cpus_running, index) ? 'R' : '-');
+ paused = (kcpuset_isset(csi->cpus_paused, index) ? 'P' : '-');
+ resumed = (kcpuset_isset(csi->cpus_resumed, index) ? 'r' : '-');
+ halted = (kcpuset_isset(csi->cpus_halted, index) ? 'h' : '-');
+ db_printf("%3ld 0x%03x %c%c%c%c%c %p %3d %3d %3d 0x%08x\n",
+ index, ci->ci_cpuid,
+ running, hatched, paused, resumed, halted,
+ ci, ci->ci_cpl, ci->ci_idepth, ci->ci_mtx_count,
+ ci->ci_pending_ipis);
+ }
+}
+#endif /* DDB */
#endif /* MULTIPROCESSOR */
#ifdef MODULAR
@@ -548,4 +803,3 @@ mm_md_kernacc(void *va, vm_prot_t prot,
*handled = false;
return 0;
}
-