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