summaryrefslogtreecommitdiffstats
path: root/sys/sparc64
diff options
context:
space:
mode:
authorjake <jake@FreeBSD.org>2002-03-13 04:59:01 +0000
committerjake <jake@FreeBSD.org>2002-03-13 04:59:01 +0000
commit97430a03ac6d96f08ba946c67589e361d670addb (patch)
tree68e6712418e38dab294e56d6aea9d572d6b03950 /sys/sparc64
parent89751e20c27db82879f0a6f9c83a527d641a6494 (diff)
downloadFreeBSD-src-97430a03ac6d96f08ba946c67589e361d670addb.zip
FreeBSD-src-97430a03ac6d96f08ba946c67589e361d670addb.tar.gz
Add support for starting and stopping cpus with ipis.
Stop the other cpus when shutting down or entering the debugger. Submitted by: tmm
Diffstat (limited to 'sys/sparc64')
-rw-r--r--sys/sparc64/include/ofw_machdep.h2
-rw-r--r--sys/sparc64/sparc64/db_interface.c11
-rw-r--r--sys/sparc64/sparc64/machdep.c19
-rw-r--r--sys/sparc64/sparc64/mp_machdep.c69
4 files changed, 93 insertions, 8 deletions
diff --git a/sys/sparc64/include/ofw_machdep.h b/sys/sparc64/include/ofw_machdep.h
index bd4c651..64c7d56 100644
--- a/sys/sparc64/include/ofw_machdep.h
+++ b/sys/sparc64/include/ofw_machdep.h
@@ -31,7 +31,7 @@
#include <sys/bus.h>
void OF_getetheraddr(device_t dev, u_char *addr);
-
+void cpu_shutdown(void *);
void openfirmware_exit(void *);
#endif /* _MACHINE_OFW_MACHDEP_H_ */
diff --git a/sys/sparc64/sparc64/db_interface.c b/sys/sparc64/sparc64/db_interface.c
index 4322acf..b6a1e20 100644
--- a/sys/sparc64/sparc64/db_interface.c
+++ b/sys/sparc64/sparc64/db_interface.c
@@ -48,6 +48,7 @@
#include <ddb/db_sym.h>
#include <ddb/db_variables.h>
+#include <machine/atomic.h>
#include <machine/setjmp.h>
static jmp_buf *db_nofault = 0;
@@ -67,14 +68,22 @@ kdb_trap(struct trapframe *tf)
longjmp(db_global_jmpbuf, 1);
flushw();
ddb_regs = *tf;
+ critical_enter();
setjmp(db_global_jmpbuf);
db_global_jmpbuf_valid = TRUE;
- db_active++;
+ atomic_add_acq_int(&db_active, 1);
+#ifdef SMP
+ stop_cpus(PCPU_GET(other_cpus));
+#endif
cndbctl(TRUE);
db_trap(tf->tf_type, 0);
cndbctl(FALSE);
db_active--;
+#ifdef SMP
+ restart_cpus(stopped_cpus);
+#endif
db_global_jmpbuf_valid = FALSE;
+ critical_exit();
*tf = ddb_regs;
TF_DONE(tf);
return (1);
diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c
index 8ac7528..5e96a40 100644
--- a/sys/sparc64/sparc64/machdep.c
+++ b/sys/sparc64/sparc64/machdep.c
@@ -526,6 +526,20 @@ sigreturn(struct thread *td, struct sigreturn_args *uap)
}
/*
+ * Exit the kernel and execute a firmware call that will not return, as
+ * specified by the arguments.
+ */
+void
+cpu_shutdown(void *args)
+{
+
+#ifdef SMP
+ cpu_mp_shutdown();
+#endif
+ openfirmware_exit(args);
+}
+
+/*
* Duplicate OF_exit() with a different firmware call function that restores
* the trap table, otherwise a RED state exception is triggered in at least
* some firmware versions.
@@ -543,7 +557,7 @@ cpu_halt(void)
0
};
- openfirmware_exit(&args);
+ cpu_shutdown(&args);
}
void
@@ -561,11 +575,10 @@ sparc64_shutdown_final(void *dummy, int howto)
/* Turn the power off? */
if ((howto & RB_POWEROFF) != 0)
- openfirmware_exit(&args);
+ cpu_shutdown(&args);
/* In case of halt, return to the firmware */
if ((howto & RB_HALT) != 0)
cpu_halt();
-
}
int
diff --git a/sys/sparc64/sparc64/mp_machdep.c b/sys/sparc64/sparc64/mp_machdep.c
index 03f5390..1176c37 100644
--- a/sys/sparc64/sparc64/mp_machdep.c
+++ b/sys/sparc64/sparc64/mp_machdep.c
@@ -74,8 +74,12 @@
#include <dev/ofw/openfirm.h>
+#include <ddb/ddb.h>
+
#include <machine/asi.h>
+#include <machine/atomic.h>
#include <machine/md_var.h>
+#include <machine/ofw_machdep.h>
#include <machine/smp.h>
#include <machine/tlb.h>
#include <machine/tte.h>
@@ -91,7 +95,6 @@ static ih_func_t cpu_ipi_stop;
*/
struct cpu_start_args cpu_start_args = { 0, -1, -1, 0, 0 };
struct ipi_tlb_args ipi_tlb_args;
-struct ipi_level_args ipi_level_args;
vm_offset_t mp_tramp;
@@ -99,6 +102,8 @@ static struct mtx ap_boot_mtx;
u_int mp_boot_mid;
+static volatile u_int shutdown_cpus;
+
void cpu_mp_unleash(void *);
SYSINIT(cpu_mp_unleash, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL);
@@ -174,6 +179,26 @@ sun4u_startcpu(phandle_t cpu, void *func, u_long arg)
}
/*
+ * Stop the calling CPU.
+ */
+static void
+sun4u_stopself(void)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ } args = {
+ (cell_t)"SUNW,stop-self",
+ 0,
+ 0,
+ };
+
+ openfirmware_exit(&args);
+ panic("sun4u_stopself: failed.");
+}
+
+/*
* Fire up any non-boot processors.
*/
void
@@ -235,6 +260,7 @@ cpu_mp_start(void)
all_cpus |= 1 << cpuid;
}
PCPU_SET(other_cpus, all_cpus & ~(1 << PCPU_GET(cpuid)));
+ smp_active = 1;
}
void
@@ -294,6 +320,7 @@ cpu_mp_unleash(void *v)
membar(StoreLoad);
csa->csa_count = 0;
+ smp_started = 1;
}
void
@@ -304,6 +331,7 @@ cpu_mp_bootstrap(struct pcpu *pc)
csa = &cpu_start_args;
pmap_map_tsb();
cpu_setregs(pc);
+ tick_start_ap();
smp_cpus++;
PCPU_SET(other_cpus, all_cpus & ~(1 << PCPU_GET(cpuid)));
@@ -323,6 +351,27 @@ cpu_mp_bootstrap(struct pcpu *pc)
cpu_throw(); /* doesn't return */
}
+void
+cpu_mp_shutdown(void)
+{
+ int i;
+
+ critical_enter();
+ shutdown_cpus = PCPU_GET(other_cpus);
+ if (stopped_cpus != PCPU_GET(other_cpus)) /* XXX */
+ stop_cpus(stopped_cpus ^ PCPU_GET(other_cpus));
+ i = 0;
+ while (shutdown_cpus != 0) {
+ if (i++ > 100000) {
+ printf("timeout shutting down CPUs.\n");
+ break;
+ }
+ }
+ /* XXX: delay a bit to allow the CPUs to actually enter the PROM. */
+ DELAY(100000);
+ critical_exit();
+}
+
static void
cpu_ipi_ast(struct trapframe *tf)
{
@@ -331,7 +380,18 @@ cpu_ipi_ast(struct trapframe *tf)
static void
cpu_ipi_stop(struct trapframe *tf)
{
- TODO;
+
+ CTR1(KTR_SMP, "cpu_ipi_stop: stopped %d", PCPU_GET(cpuid));
+ atomic_set_acq_int(&stopped_cpus, PCPU_GET(cpumask));
+ while ((started_cpus & PCPU_GET(cpumask)) == 0) {
+ if ((shutdown_cpus & PCPU_GET(cpumask)) != 0) {
+ atomic_clear_int(&shutdown_cpus, PCPU_GET(cpumask));
+ sun4u_stopself();
+ }
+ }
+ atomic_clear_rel_int(&started_cpus, PCPU_GET(cpumask));
+ atomic_clear_rel_int(&stopped_cpus, PCPU_GET(cpumask));
+ CTR1(KTR_SMP, "cpu_ipi_stop: restarted %d", PCPU_GET(cpuid));
}
void
@@ -369,7 +429,10 @@ cpu_ipi_send(u_int mid, u_long d0, u_long d1, u_long d2)
if ((ldxa(0, ASI_INTR_DISPATCH_STATUS) & IDR_NACK) == 0)
return;
}
- panic("ipi_send: couldn't send ipi");
+ if (db_active || panicstr != NULL)
+ printf("ipi_send: couldn't send ipi to module %u\n", mid);
+ else
+ panic("ipi_send: couldn't send ipi");
}
void
OpenPOWER on IntegriCloud