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;
 }
-

Reply via email to