From 8e95379f5d8db5b6cb8fe97be8a889303b02cf58 Mon Sep 17 00:00:00 2001
From: Mark Kettenis <kettenis@cvs.openbsd.org>
Date: Sun, 14 Dec 2008 17:10:45 +0000
Subject: Implement a "machine xir" ddb command, making it possible to send an
 External Initiated Reset (XIR) to processors.  A XIR is non-maskable and will
 drop us at the PROM ok prompt.  This makes it possible to diagnose problems
 where a CPU is spinning with interrupts disabled.

For now, this is only supported on machines with bbc(4).
---
 sys/arch/sparc64/dev/bbc.c              | 44 ++++++++++++++++++++++++++++++--
 sys/arch/sparc64/include/db_machdep.h   |  5 +++-
 sys/arch/sparc64/sparc64/db_interface.c | 45 ++++++++++++++++++++++++++++++++-
 3 files changed, 90 insertions(+), 4 deletions(-)

(limited to 'sys')

diff --git a/sys/arch/sparc64/dev/bbc.c b/sys/arch/sparc64/dev/bbc.c
index 353a759ccac..7b51b288335 100644
--- a/sys/arch/sparc64/dev/bbc.c
+++ b/sys/arch/sparc64/dev/bbc.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: bbc.c,v 1.2 2007/08/21 19:01:38 kettenis Exp $	*/
+/*	$OpenBSD: bbc.c,v 1.3 2008/12/14 17:10:44 kettenis Exp $	*/
 
 /*
  * Copyright (c) 2007 Mark Kettenis
@@ -25,19 +25,31 @@
 #include <machine/bus.h>
 #include <machine/autoconf.h>
 
+#ifdef DDB
+#include <machine/db_machdep.h>
+#endif
+
 #include <sparc64/dev/ebusreg.h>
 #include <sparc64/dev/ebusvar.h>
 
+/* Agent ID */
+#define BBC_AID			0x00000
+
 /* Watchdog Action */
 #define BBC_WATCHDOG_ACTION	0x00004
 
 /* Perform system reset when watchdog timer expires. */
 #define	BBC_WATCHDOG_RESET	0x01
 
+/* Soft_XIR_GEN */
+#define BBC_SOFT_XIR_GEN	0x00007
+
 struct bbc_softc {
 	struct device		sc_dv;
 	bus_space_tag_t		sc_iot;
 	bus_space_handle_t	sc_ioh;
+
+	int			sc_aid;
 };
 
 int	bbc_match(struct device *, void *, void *);
@@ -51,6 +63,10 @@ struct cfdriver bbc_cd = {
 	NULL, "bbc", DV_DULL
 };
 
+#ifdef DDB
+void	bbc_xir(void *, int);
+#endif
+
 int
 bbc_match(struct device *parent, void *cf, void *aux)
 {
@@ -88,7 +104,8 @@ bbc_attach(struct device *parent, struct device *self, void *aux)
 		return;
 	}
 
-	printf("\n");
+	sc->sc_aid = bus_space_read_1(sc->sc_iot, sc->sc_ioh, BBC_AID);
+	printf(": AID 0x%02x\n", sc->sc_aid);
 
 	/*
 	 * Make sure we actually reset the system when the watchdog
@@ -96,4 +113,27 @@ bbc_attach(struct device *parent, struct device *self, void *aux)
 	 */
 	bus_space_write_1(sc->sc_iot, sc->sc_ioh,
 	    BBC_WATCHDOG_ACTION, BBC_WATCHDOG_RESET);
+
+#ifdef DDB
+	db_register_xir(bbc_xir, sc);
+#endif
+}
+
+#ifdef DDB
+void
+bbc_xir(void *arg, int cpu)
+{
+	struct bbc_softc *sc = arg;
+
+	/* Redirect a request to reset all processors to Processor 0. */
+	if (cpu == -1)
+		cpu = 0;
+
+	/* Check whether we're handling the requested processor. */
+	if ((cpu & ~0x7) != sc->sc_aid)
+		return;
+
+	bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+	    BBC_SOFT_XIR_GEN, 1 << (cpu & 0x7));
 }
+#endif
diff --git a/sys/arch/sparc64/include/db_machdep.h b/sys/arch/sparc64/include/db_machdep.h
index 9bc6d9c21bf..8691ce60e81 100644
--- a/sys/arch/sparc64/include/db_machdep.h
+++ b/sys/arch/sparc64/include/db_machdep.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: db_machdep.h,v 1.10 2008/03/17 23:10:21 kettenis Exp $	*/
+/*	$OpenBSD: db_machdep.h,v 1.11 2008/12/14 17:10:44 kettenis Exp $	*/
 /*	$NetBSD: db_machdep.h,v 1.12 2001/07/07 15:16:13 eeh Exp $ */
 
 /*
@@ -144,4 +144,7 @@ int kdb_trap(int, struct trapframe64 *);
 #define	DB_ELF_SYMBOLS
 #define DB_ELFSIZE	64
 
+/* Register device-specific method for triggering XIRs. */
+void db_register_xir(void (*)(void *, int), void *);
+
 #endif	/* _SPARC_DB_MACHDEP_H_ */
diff --git a/sys/arch/sparc64/sparc64/db_interface.c b/sys/arch/sparc64/sparc64/db_interface.c
index 97cb75aeaf7..a5f3d190a79 100644
--- a/sys/arch/sparc64/sparc64/db_interface.c
+++ b/sys/arch/sparc64/sparc64/db_interface.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: db_interface.c,v 1.26 2008/03/13 23:29:46 kettenis Exp $	*/
+/*	$OpenBSD: db_interface.c,v 1.27 2008/12/14 17:10:44 kettenis Exp $	*/
 /*	$NetBSD: db_interface.c,v 1.61 2001/07/31 06:55:47 eeh Exp $ */
 
 /*
@@ -34,6 +34,7 @@
 #include <sys/user.h>
 #include <sys/reboot.h>
 #include <sys/systm.h>
+#include <sys/malloc.h>
 
 #include <uvm/uvm_extern.h>
 
@@ -227,6 +228,7 @@ void db_traptrace(db_expr_t, int, db_expr_t, char *);
 void db_dump_buf(db_expr_t, int, db_expr_t, char *);
 void db_dump_espcmd(db_expr_t, int, db_expr_t, char *);
 void db_watch(db_expr_t, int, db_expr_t, char *);
+void db_xir(db_expr_t, int, db_expr_t, char *);
 
 static void db_dump_pmap(struct pmap*);
 static void db_print_trace_entry(struct traptrace *, int);
@@ -1028,6 +1030,46 @@ db_watch(addr, have_addr, count, modif)
 	}
 }
 
+/*
+ * Provide a way to trigger an External Initiated Reset (XIR).  Some
+ * systems can target individual processors, others can only target
+ * all processors at once.
+ */
+
+struct xirhand {
+	void (*xh_fun)(void *, int);
+	void *xh_arg;
+	SIMPLEQ_ENTRY(xirhand) xh_list;
+};
+
+SIMPLEQ_HEAD(, xirhand) db_xh = SIMPLEQ_HEAD_INITIALIZER(db_xh);
+
+void
+db_xir(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
+{
+	struct xirhand *xh;
+
+	if (!have_addr)
+		addr = -1;
+
+	SIMPLEQ_FOREACH(xh, &db_xh, xh_list) {
+		xh->xh_fun(xh->xh_arg, addr);
+	}
+}
+
+void
+db_register_xir(void (*fun)(void *, int), void *arg)
+{
+	struct xirhand *xh;
+
+	xh = malloc(sizeof(*xh), M_DEVBUF, M_NOWAIT);
+	if (xh == NULL)
+		panic("db_register_xir");
+	xh->xh_fun = fun;
+	xh->xh_arg = arg;
+	SIMPLEQ_INSERT_TAIL(&db_xh, xh, xh_list);
+}
+
 
 #include <uvm/uvm.h>
 
@@ -1080,6 +1122,7 @@ struct db_command db_machine_command_table[] = {
 #endif
 	{ "watch",	db_watch,	0,	0 },
 	{ "window",	db_dump_window,	0,	0 },
+	{ "xir",	db_xir,		0,	0 },
 	{ (char *)0, }
 };
 
-- 
cgit v1.2.3