Module Name: src
Committed By: cliff
Date: Sat Feb 5 06:06:11 UTC 2011
Modified Files:
src/sys/arch/mips/mips [matt-nb5-mips64]: cpu_subr.c
Log Message:
- add ddb related includes
- convert 'cpus_running' et. al. to mips_cpuset_t, and use CPUSET_* macros
- add IPI broadcast, multicast functions
- add IPI halt, pause, resume, functions and related, useful for MP ddb
To generate a diff of this commit:
cvs rdiff -u -r1.1.2.13 -r1.1.2.14 src/sys/arch/mips/mips/cpu_subr.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/mips/mips/cpu_subr.c
diff -u src/sys/arch/mips/mips/cpu_subr.c:1.1.2.13 src/sys/arch/mips/mips/cpu_subr.c:1.1.2.14
--- src/sys/arch/mips/mips/cpu_subr.c:1.1.2.13 Wed Dec 22 05:53:38 2010
+++ src/sys/arch/mips/mips/cpu_subr.c Sat Feb 5 06:06:11 2011
@@ -29,10 +29,11 @@
#include <sys/cdefs.h>
+#include "opt_ddb.h"
#include "opt_multiprocessor.h"
#include "opt_sa.h"
-__KERNEL_RCSID(0, "$NetBSD: cpu_subr.c,v 1.1.2.13 2010/12/22 05:53:38 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu_subr.c,v 1.1.2.14 2011/02/05 06:06:11 cliff Exp $");
#include <sys/param.h>
#include <sys/cpu.h>
@@ -57,6 +58,15 @@
#include <mips/frame.h>
#include <mips/userret.h>
#include <mips/pte.h>
+#include <mips/cpuset.h>
+
+#if defined(DDB) || defined(KGDB)
+#ifdef DDB
+#include <mips/db_machdep.h>
+#include <ddb/db_command.h>
+#include <ddb/db_output.h>
+#endif
+#endif
struct cpu_info cpu_info_store
#ifdef MULTIPROCESSOR
@@ -82,9 +92,15 @@
#ifdef MULTIPROCESSOR
-volatile u_long cpus_running = 1;
-volatile u_long cpus_hatched = 1;
-volatile u_long cpus_paused = 0;
+volatile mips_cpuset_t cpus_running = 1;
+volatile mips_cpuset_t cpus_hatched = 1;
+volatile mips_cpuset_t cpus_paused = 0;
+volatile mips_cpuset_t cpus_resumed = 0;
+volatile mips_cpuset_t cpus_halted = 0;
+
+static int cpu_ipi_wait(volatile mips_cpuset_t *, u_long);
+static void cpu_ipi_error(const char *, mips_cpuset_t, mips_cpuset_t);
+
static struct cpu_info *cpu_info_last = &cpu_info_store;
@@ -602,6 +618,32 @@
}
#ifdef MULTIPROCESSOR
+
+void
+cpu_broadcast_ipi(int tag)
+{
+ (void)cpu_multicast_ipi(
+ CPUSET_EXCEPT(cpus_running, cpu_index(curcpu())), tag);
+}
+
+void
+cpu_multicast_ipi(mips_cpuset_t cpuset, int tag)
+{
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+
+ CPUSET_DEL(cpuset, cpu_index(curcpu()));
+ if (CPUSET_EMPTY(cpuset))
+ return;
+
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ if (CPUSET_HAS(cpuset, cpu_index(ci))) {
+ CPUSET_DEL(cpuset, cpu_index(ci));
+ (void)cpu_send_ipi(ci, tag);
+ }
+ }
+}
+
int
cpu_send_ipi(struct cpu_info *ci, int tag)
{
@@ -609,11 +651,192 @@
return (*mips_locoresw.lsw_send_ipi)(ci, tag);
}
+static void
+cpu_ipi_error(const char *s, mips_cpuset_t succeeded, mips_cpuset_t expected)
+{
+ CPUSET_SUB(expected, succeeded);
+ if (!CPUSET_EMPTY(expected)) {
+ printf("Failed to %s:", s);
+ do {
+ int index = CPUSET_NEXT(expected);
+ CPUSET_DEL(expected, index);
+ printf(" cpu%d", index);
+ } while(!CPUSET_EMPTY(expected));
+ printf("\n");
+ }
+}
+
+static int
+cpu_ipi_wait(volatile mips_cpuset_t *watchset, u_long mask)
+{
+ u_long limit = curcpu()->ci_cpu_freq; /* some finite amount of time */
+
+ while (limit--)
+ if (*watchset == mask)
+ return 0; /* success */
+
+ return 1; /* timed out */
+}
+
+/*
+ * Halt this cpu
+ */
+void
+cpu_halt(void)
+{
+ int index = cpu_index(curcpu());
+
+ printf("cpu%d: shutting down\n", index);
+ CPUSET_ADD(cpus_halted, index);
+ spl0(); /* allow interrupts e.g. further ipi ? */
+ for (;;) ; /* spin */
+
+ /* NOTREACHED */
+}
+
+/*
+ * Halt all running cpus, excluding current cpu.
+ */
+void
+cpu_halt_others(void)
+{
+ mips_cpuset_t cpumask, cpuset;
+
+ CPUSET_ASSIGN(cpuset, cpus_running);
+ CPUSET_DEL(cpuset, cpu_index(curcpu()));
+ CPUSET_ASSIGN(cpumask, cpuset);
+ CPUSET_SUB(cpuset, cpus_halted);
+
+ if (CPUSET_EMPTY(cpuset))
+ return;
+
+ cpu_multicast_ipi(cpuset, IPI_HALT);
+ if (cpu_ipi_wait(&cpus_halted, cpumask))
+ cpu_ipi_error("halt", cpumask, cpus_halted);
+
+ /*
+ * 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 reg *regsp)
+{
+ int s = splhigh();
+ int index = cpu_index(curcpu());
+
+ for (;;) {
+ CPUSET_ADD(cpus_paused, index);
+ do {
+ ;
+ } while(CPUSET_HAS(cpus_paused, index));
+ CPUSET_ADD(cpus_resumed, index);
+
+#if defined(DDB)
+ if (ddb_running_on_this_cpu())
+ cpu_Debugger();
+ if (ddb_running_on_any_cpu())
+ continue;
+#endif
+ break;
+ }
+#if defined(DDB) && defined(MIPS_DDB_WATCH)
+ db_mach_watch_set_all();
+#endif
+
+ splx(s);
+}
+
+/*
+ * Pause all running cpus, excluding current cpu.
+ */
+void
+cpu_pause_others(void)
+{
+ mips_cpuset_t cpuset;
+
+ CPUSET_ASSIGN(cpuset, cpus_running);
+ CPUSET_DEL(cpuset, cpu_index(curcpu()));
+
+ if (CPUSET_EMPTY(cpuset))
+ return;
+
+ cpu_multicast_ipi(cpuset, IPI_SUSPEND);
+ if (cpu_ipi_wait(&cpus_paused, cpuset))
+ cpu_ipi_error("pause", cpus_paused, cpuset);
+}
+
+/*
+ * Resume a single cpu
+ */
+void
+cpu_resume(int index)
+{
+ CPUSET_CLEAR(cpus_resumed);
+ CPUSET_DEL(cpus_paused, index);
+
+ if (cpu_ipi_wait(&cpus_resumed, CPUSET_SINGLE(index)))
+ cpu_ipi_error("resume", cpus_resumed, CPUSET_SINGLE(index));
+}
+
+/*
+ * Resume all paused cpus.
+ */
+void
+cpu_resume_others(void)
+{
+ mips_cpuset_t cpuset;
+
+ CPUSET_CLEAR(cpus_resumed);
+ CPUSET_ASSIGN(cpuset, cpus_paused);
+ CPUSET_CLEAR(cpus_paused);
+
+ /* CPUs awake on cpus_paused clear */
+ if (cpu_ipi_wait(&cpus_resumed, cpuset))
+ cpu_ipi_error("resume", cpus_resumed, cpuset);
+}
+
+int
+cpu_is_paused(int index)
+{
+
+ return CPUSET_HAS(cpus_paused, index);
+}
+
+void
+cpu_debug_dump(void)
+{
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+ char running, hatched, paused, resumed, halted;
+
+ db_printf("CPU STATE CPUINFO CPL INT MTX IPIS\n");
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ hatched = (CPUSET_HAS(cpus_hatched, cpu_index(ci)) ? 'H' : '-');
+ running = (CPUSET_HAS(cpus_running, cpu_index(ci)) ? 'R' : '-');
+ paused = (CPUSET_HAS(cpus_paused, cpu_index(ci)) ? 'P' : '-');
+ resumed = (CPUSET_HAS(cpus_resumed, cpu_index(ci)) ? 'r' : '-');
+ halted = (CPUSET_HAS(cpus_halted, cpu_index(ci)) ? 'h' : '-');
+ db_printf("%3d %c%c%c%c%c %p "
+ "%3d %3d %3d "
+ "0x%02" PRIx64 "/0x%02" PRIx64 "\n",
+ cpu_index(ci),
+ running, hatched, paused, resumed, halted,
+ ci, ci->ci_cpl, ci->ci_idepth, ci->ci_mtx_count,
+ ci->ci_active_ipis, ci->ci_request_ipis);
+ }
+}
+
void
cpu_hatch(struct cpu_info *ci)
{
struct pmap_tlb_info * const ti = ci->ci_tlb_info;
- const u_long cpu_mask = 1L << cpu_index(ci);
/*
* Invalidate all the TLB enties (even wired ones) and then reserve
@@ -648,12 +871,12 @@
/*
* Announce we are hatched
*/
- atomic_or_ulong(&cpus_hatched, cpu_mask);
+ CPUSET_ADD(cpus_hatched, cpu_index(ci));
/*
* Now wait to be set free!
*/
- while ((cpus_running & cpu_mask) == 0) {
+ while (! CPUSET_HAS(cpus_running, cpu_index(ci))) {
/* spin, spin, spin */
}
@@ -683,19 +906,18 @@
for (struct cpu_info *ci = cpu_info_store.ci_next;
ci != NULL;
ci = ci->ci_next) {
- const u_long cpu_mask = 1L << cpu_index(ci);
KASSERT(!CPU_IS_PRIMARY(ci));
KASSERT(ci->ci_data.cpu_idlelwp);
/*
* Skip this CPU if it didn't sucessfully hatch.
*/
- if ((cpus_hatched & cpu_mask) == 0)
+ if (! CPUSET_HAS(cpus_hatched, cpu_index(ci)))
continue;
ci->ci_data.cpu_cc_skew = mips3_cp0_count_read();
atomic_or_ulong(&ci->ci_flags, CPUF_RUNNING);
- atomic_or_ulong(&cpus_running, cpu_mask);
+ CPUSET_ADD(cpus_running, cpu_index(ci));
}
}
#endif /* MULTIPROCESSOR */