git: 904a13759cf6 - main - ddb: Add 'show gic <name>' and 'show all gics' commands.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Thu, 10 Mar 2022 23:41:32 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=904a13759cf68fc2eb60bcdd2fecc1e9c3546c5c

commit 904a13759cf68fc2eb60bcdd2fecc1e9c3546c5c
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2022-03-10 23:39:37 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2022-03-10 23:39:37 +0000

    ddb: Add 'show gic <name>' and 'show all gics' commands.
    
    To handle the different register layouts for different versions, add a
    GIC_DB_SHOW() method.  Currently this hook is only implemented for
    versions 1 and 2.
    
    Sponsored by:   University of Cambridge, Google, Inc.
    Differential Revision:  https://reviews.freebsd.org/D34415
---
 sys/arm/arm/gic.c    | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++
 sys/arm/arm/gic_if.m |   4 ++
 2 files changed, 113 insertions(+)

diff --git a/sys/arm/arm/gic.c b/sys/arm/arm/gic.c
index e285747678de..434c491b4d56 100644
--- a/sys/arm/arm/gic.c
+++ b/sys/arm/arm/gic.c
@@ -37,6 +37,7 @@
 __FBSDID("$FreeBSD$");
 
 #include "opt_acpi.h"
+#include "opt_ddb.h"
 #include "opt_platform.h"
 
 #include <sys/param.h>
@@ -72,6 +73,11 @@ __FBSDID("$FreeBSD$");
 #include <dev/acpica/acpivar.h>
 #endif
 
+#ifdef DDB
+#include <ddb/ddb.h>
+#include <ddb/db_lex.h>
+#endif
+
 #include <arm/arm/gic.h>
 #include <arm/arm/gic_common.h>
 
@@ -1147,6 +1153,58 @@ arm_gic_release_msix(device_t dev, struct intr_irqsrc *isrc)
 	return (0);
 }
 
+#ifdef DDB
+static void
+arm_gic_db_show(device_t dev)
+{
+	struct arm_gic_softc *sc = device_get_softc(dev);
+	uint32_t val;
+	u_int i;
+
+	db_printf("%s CPU registers:\n", device_get_nameunit(dev));
+	db_printf(" CTLR: %08x   PMR: %08x   BPR: %08x   RPR: %08x\n",
+	    gic_c_read_4(sc, GICC_CTLR), gic_c_read_4(sc, GICC_PMR),
+	    gic_c_read_4(sc, GICC_BPR), gic_c_read_4(sc, GICC_RPR));
+	db_printf("HPPIR: %08x  IIDR: %08x\n", gic_c_read_4(sc, GICC_HPPIR),
+	    gic_c_read_4(sc, GICC_IIDR));
+
+	db_printf("%s Distributor registers:\n", device_get_nameunit(dev));
+	db_printf(" CTLR: %08x TYPER: %08x  IIDR: %08x\n",
+	    gic_d_read_4(sc, GICD_CTLR), gic_d_read_4(sc, GICD_TYPER),
+	    gic_d_read_4(sc, GICD_IIDR));
+	for (i = 0; i < sc->nirqs; i++) {
+		if (i <= GIC_LAST_SGI)
+			db_printf("SGI %2u ", i);
+		else if (i <= GIC_LAST_PPI)
+			db_printf("PPI %2u ", i - GIC_FIRST_PPI);
+		else
+			db_printf("SPI %2u ", i - GIC_FIRST_SPI);
+		db_printf(" grp:%u",
+		    !!(gic_d_read_4(sc, GICD_IGROUPR(i)) & GICD_I_MASK(i)));
+		db_printf(" enable:%u pend:%u active:%u",
+		    !!(gic_d_read_4(sc, GICD_ISENABLER(i)) & GICD_I_MASK(i)),
+		    !!(gic_d_read_4(sc, GICD_ISPENDR(i)) & GICD_I_MASK(i)),
+		    !!(gic_d_read_4(sc, GICD_ISACTIVER(i)) & GICD_I_MASK(i)));
+		db_printf(" pri:%u",
+		    (gic_d_read_4(sc, GICD_IPRIORITYR(i)) >> 8 * (i & 0x3)) &
+		    0xff);
+		db_printf(" trg:%u",
+		    (gic_d_read_4(sc, GICD_ITARGETSR(i)) >> 8 * (i & 0x3)) &
+		    0xff);
+		val = gic_d_read_4(sc, GICD_ICFGR(i)) >> 2 * (i & 0xf);
+		if ((val & GICD_ICFGR_POL_MASK) == GICD_ICFGR_POL_LOW)
+			db_printf(" LO");
+		else
+			db_printf(" HI");
+		if ((val & GICD_ICFGR_TRIG_MASK) == GICD_ICFGR_TRIG_LVL)
+			db_printf(" LV");
+		else
+			db_printf(" ED");
+		db_printf("\n");
+	}
+}
+#endif
+
 static device_method_t arm_gic_methods[] = {
 	/* Bus interface */
 	DEVMETHOD(bus_print_child,	arm_gic_print_child),
@@ -1179,6 +1237,9 @@ static device_method_t arm_gic_methods[] = {
 	DEVMETHOD(gic_release_msi,	arm_gic_release_msi),
 	DEVMETHOD(gic_alloc_msix,	arm_gic_alloc_msix),
 	DEVMETHOD(gic_release_msix,	arm_gic_release_msix),
+#ifdef DDB
+	DEVMETHOD(gic_db_show,		arm_gic_db_show),
+#endif
 
 	{ 0, 0 }
 };
@@ -1186,6 +1247,54 @@ static device_method_t arm_gic_methods[] = {
 DEFINE_CLASS_0(gic, arm_gic_driver, arm_gic_methods,
     sizeof(struct arm_gic_softc));
 
+#ifdef DDB
+DB_FUNC(gic, db_show_gic, db_show_table, CS_OWN, NULL)
+{
+	device_t dev;
+	int t;
+	bool valid;
+
+	valid = false;
+	t = db_read_token();
+	if (t == tIDENT) {
+		dev = device_lookup_by_name(db_tok_string);
+		valid = true;
+	}
+	db_skip_to_eol();
+	if (!valid) {
+		db_printf("usage: show gic <name>\n");
+		return;
+	}
+
+	if (dev == NULL) {
+		db_printf("device not found\n");
+		return;
+	}
+
+	GIC_DB_SHOW(dev);
+}
+
+DB_SHOW_ALL_COMMAND(gics, db_show_all_gics)
+{
+	devclass_t dc;
+	device_t dev;
+	int i;
+
+	dc = devclass_find("gic");
+	if (dc == NULL)
+		return;
+
+	for (i = 0; i < devclass_get_maxunit(dc); i++) {
+		dev = devclass_get_device(dc, i);
+		if (dev != NULL)
+			GIC_DB_SHOW(dev);
+		if (db_pager_quit)
+			break;
+	}
+}
+
+#endif
+
 /*
  * GICv2m support -- the GICv2 MSI/MSI-X controller.
  */
diff --git a/sys/arm/arm/gic_if.m b/sys/arm/arm/gic_if.m
index ba722c3b1250..d6458cf177c4 100644
--- a/sys/arm/arm/gic_if.m
+++ b/sys/arm/arm/gic_if.m
@@ -67,3 +67,7 @@ METHOD int release_msix {
 	device_t	dev;
 	struct intr_irqsrc *isrc;
 };
+
+METHOD void db_show {
+	device_t	dev;
+};