Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 14 Sep 2021 10:42:35 GMT
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: e4d89a633e3b - main - Add support for gicv2m as a child of gicv3
Message-ID:  <202109141042.18EAgZX9041638@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by andrew:

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

commit e4d89a633e3b31ec1319e3238abceee2048996c4
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2021-09-01 09:41:14 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2021-09-14 07:24:52 +0000

    Add support for gicv2m as a child of gicv3
    
    On some systems, e.g. Parallels set to host a Linux VM under an M1 Mac,
    there is a GICv2m as a child of the GICv3. We previously assumed the
    GICv2m was always a child of a GICv2. Fix this by adding the needed
    support to the GICv3 driver.
    
    PR:             258136
    Reported by:    trasz
    Sponsored by:   The FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D31768
---
 sys/arm64/arm64/gic_v3.c     | 90 ++++++++++++++++++++++++++++++++++++++++----
 sys/arm64/arm64/gic_v3_fdt.c |  2 +-
 2 files changed, 83 insertions(+), 9 deletions(-)

diff --git a/sys/arm64/arm64/gic_v3.c b/sys/arm64/arm64/gic_v3.c
index 3e7cd30140eb..a53d0b272723 100644
--- a/sys/arm64/arm64/gic_v3.c
+++ b/sys/arm64/arm64/gic_v3.c
@@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$");
 
 static bus_get_domain_t gic_v3_get_domain;
 static bus_read_ivar_t gic_v3_read_ivar;
+static bus_write_ivar_t gic_v3_write_ivar;
 
 static pic_disable_intr_t gic_v3_disable_intr;
 static pic_enable_intr_t gic_v3_enable_intr;
@@ -113,6 +114,7 @@ static device_method_t gic_v3_methods[] = {
 	/* Bus interface */
 	DEVMETHOD(bus_get_domain,	gic_v3_get_domain),
 	DEVMETHOD(bus_read_ivar,	gic_v3_read_ivar),
+	DEVMETHOD(bus_write_ivar,	gic_v3_write_ivar),
 
 	/* Interrupt controller interface */
 	DEVMETHOD(pic_disable_intr,	gic_v3_disable_intr),
@@ -242,6 +244,33 @@ gic_r_write_8(device_t dev, bus_size_t offset, uint64_t val)
 	bus_write_8(rdist, offset, val);
 }
 
+static void
+gic_v3_reserve_msi_range(device_t dev, u_int start, u_int count)
+{
+	struct gic_v3_softc *sc;
+	int i;
+
+	sc = device_get_softc(dev);
+
+	KASSERT((start + count) < sc->gic_nirqs,
+	    ("%s: Trying to allocate too many MSI IRQs: %d + %d > %d", __func__,
+	    start, count, sc->gic_nirqs));
+	for (i = 0; i < count; i++) {
+		KASSERT(sc->gic_irqs[start + i].gi_isrc.isrc_handlers == 0,
+		    ("%s: MSI interrupt %d already has a handler", __func__,
+		    count + i));
+		KASSERT(sc->gic_irqs[start + i].gi_pol == INTR_POLARITY_CONFORM,
+		    ("%s: MSI interrupt %d already has a polarity", __func__,
+		    count + i));
+		KASSERT(sc->gic_irqs[start + i].gi_trig == INTR_TRIGGER_CONFORM,
+		    ("%s: MSI interrupt %d already has a trigger", __func__,
+		    count + i));
+		sc->gic_irqs[start + i].gi_pol = INTR_POLARITY_HIGH;
+		sc->gic_irqs[start + i].gi_trig = INTR_TRIGGER_EDGE;
+		sc->gic_irqs[start + i].gi_flags |= GI_FLAG_MSI;
+	}
+}
+
 /*
  * Device interface.
  */
@@ -332,15 +361,10 @@ gic_v3_attach(device_t dev)
 		}
 	}
 
+	mtx_init(&sc->gic_mbi_mtx, "GICv3 mbi lock", NULL, MTX_DEF);
 	if (sc->gic_mbi_start > 0) {
-		/* Reserve these interrupts for MSI/MSI-X use */
-		for (irq = sc->gic_mbi_start; irq <= sc->gic_mbi_end; irq++) {
-			sc->gic_irqs[irq].gi_pol = INTR_POLARITY_HIGH;
-			sc->gic_irqs[irq].gi_trig = INTR_TRIGGER_EDGE;
-			sc->gic_irqs[irq].gi_flags |= GI_FLAG_MSI;
-		}
-
-		mtx_init(&sc->gic_mbi_mtx, "GICv3 mbi lock", NULL, MTX_DEF);
+		gic_v3_reserve_msi_range(dev, sc->gic_mbi_start,
+		    sc->gic_mbi_end - sc->gic_mbi_start);
 
 		if (bootverbose) {
 			device_printf(dev, "using spi %u to %u\n", sc->gic_mbi_start,
@@ -442,6 +466,56 @@ gic_v3_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
 		KASSERT(sc->gic_bus <= GIC_BUS_MAX,
 		    ("gic_v3_read_ivar: Invalid bus type %u", sc->gic_bus));
 		*result = sc->gic_bus;
+		return (0);
+	case GIC_IVAR_MBI_START:
+		*result = sc->gic_mbi_start;
+		return (0);
+	case GIC_IVAR_MBI_COUNT:
+		*result = sc->gic_mbi_end - sc->gic_mbi_start;
+		return (0);
+	}
+
+	return (ENOENT);
+}
+
+static int
+gic_v3_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+	struct gic_v3_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	switch(which) {
+	case GICV3_IVAR_NIRQS:
+	case GICV3_IVAR_REDIST:
+	case GIC_IVAR_HW_REV:
+	case GIC_IVAR_BUS:
+		return (EINVAL);
+	case GIC_IVAR_MBI_START:
+		/*
+		 * GIC_IVAR_MBI_START must be set once and first. This allows
+		 * us to reserve the registers when GIC_IVAR_MBI_COUNT is set.
+		 */
+		MPASS(sc->gic_mbi_start == 0);
+		MPASS(sc->gic_mbi_end == 0);
+		MPASS(value >= GIC_FIRST_SPI);
+		MPASS(value < sc->gic_nirqs);
+
+		sc->gic_mbi_start = value;
+		return (0);
+	case GIC_IVAR_MBI_COUNT:
+		MPASS(sc->gic_mbi_start != 0);
+		MPASS(sc->gic_mbi_end == 0);
+		MPASS(value >= sc->gic_mbi_start);
+		MPASS(value >= GIC_FIRST_SPI);
+
+		sc->gic_mbi_end = value - sc->gic_mbi_start;
+
+		MPASS(sc->gic_mbi_end <= sc->gic_nirqs);
+
+		/* Reserve these interrupts for MSI/MSI-X use */
+		gic_v3_reserve_msi_range(dev, sc->gic_mbi_start, value);
+
 		return (0);
 	}
 
diff --git a/sys/arm64/arm64/gic_v3_fdt.c b/sys/arm64/arm64/gic_v3_fdt.c
index d2c0611c9167..65d7ca7e374d 100644
--- a/sys/arm64/arm64/gic_v3_fdt.c
+++ b/sys/arm64/arm64/gic_v3_fdt.c
@@ -143,7 +143,7 @@ gic_v3_fdt_attach(device_t dev)
 		if (ret % 2 == 0) {
 			/* Limit to a single range for now. */
 			sc->gic_mbi_start = mbi_ranges[0];
-			sc->gic_mbi_end = mbi_ranges[0] + mbi_ranges[1] - 1;
+			sc->gic_mbi_end = mbi_ranges[0] + mbi_ranges[1];
 		} else {
 			if (bootverbose)
 				device_printf(dev, "Malformed mbi-ranges property\n");



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202109141042.18EAgZX9041638>